Skip to contentSkip to conversation

AHCI PCI MSI support, update 1

PATCH In review Jeff Garzik 2 participants 4 messages May 31, 2005 – Jun 1, 2005

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 AHCI PCI MSI support, update 1

I just updated the AHCI PCI MSI support patch to support the latest ->host_stop() semantics changes that just made it into upstream.

This patch, until its merged, may always be found in the 'ahci-msi' branch of rsync://rsync.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev.git

drivers/scsi/ahci.c +64 -11
@@ -39,7 +39,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME	"ahci"
-#define DRV_VERSION	"1.00"
+#define DRV_VERSION	"1.01"
 
 
 enum {
@@ -153,6 +153,7 @@ struct ahci_sg {
 
 struct ahci_host_priv {
 	unsigned long		flags;
+	unsigned int		have_msi; /* is PCI MSI enabled? */
 	u32			cap;	/* cache of HOST_CAP register */
 	u32			port_map; /* cache of HOST_PORTS_IMPL reg */
 };
@@ -183,6 +184,7 @@ static void ahci_qc_prep(struct ata_queu
 static u8 ahci_check_status(struct ata_port *ap);
 static u8 ahci_check_err(struct ata_port *ap);
 static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
+static void ahci_remove_one (struct pci_dev *pdev);
 
 static Scsi_Host_Template ahci_sht = {
 	.module			= THIS_MODULE,
@@ -272,7 +274,7 @@ static struct pci_driver ahci_pci_driver
 	.name			= DRV_NAME,
 	.id_table		= ahci_pci_tbl,
 	.probe			= ahci_init_one,
-	.remove			= ata_pci_remove_one,
+	.remove			= ahci_remove_one,
 };
 
 
@@ -879,15 +881,19 @@ static int ahci_host_init(struct ata_pro
 }
 
 /* move to PCI layer, integrate w/ MSI stuff */
-static void pci_enable_intx(struct pci_dev *pdev)
+static void pci_intx(struct pci_dev *pdev, int enable)
 {
-	u16 pci_command;
+	u16 pci_command, new;
 
 	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-	if (pci_command & PCI_COMMAND_INTX_DISABLE) {
-		pci_command &= ~PCI_COMMAND_INTX_DISABLE;
+
+	if (enable)
+		new = pci_command & ~PCI_COMMAND_INTX_DISABLE;
+	else
+		new = pci_command | PCI_COMMAND_INTX_DISABLE;
+
+	if (new != pci_command)
 		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-	}
 }
 
 static void ahci_print_info(struct ata_probe_ent *probe_ent)
@@ -969,7 +975,7 @@ static int ahci_init_one (struct pci_dev
 	unsigned long base;
 	void *mmio_base;
 	unsigned int board_idx = (unsigned int) ent->driver_data;
-	int pci_dev_busy = 0;
+	int have_msi, pci_dev_busy = 0;
 	int rc;
 
 	VPRINTK("ENTER\n");
@@ -987,12 +993,17 @@ static int ahci_init_one (struct pci_dev
 		goto err_out;
 	}
 
-	pci_enable_intx(pdev);
+	if (pci_enable_msi(pdev) == 0)
+		have_msi = 1;
+	else {
+		pci_intx(pdev, 1);
+		have_msi = 0;
+	}
 
 	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
 	if (probe_ent == NULL) {
 		rc = -ENOMEM;
-		goto err_out_regions;
+		goto err_out_msi;
 	}
 
 	memset(probe_ent, 0, sizeof(*probe_ent));
@@ -1025,6 +1036,8 @@ static int ahci_init_one (struct pci_dev
 	probe_ent->mmio_base = mmio_base;
 	probe_ent->private_data = hpriv;
 
+	hpriv->have_msi = have_msi;
+
 	/* initialize adapter */
 	rc = ahci_host_init(probe_ent);
 	if (rc)
@@ -1044,7 +1057,11 @@ err_out_iounmap:
 	iounmap(mmio_base);
 err_out_free_ent:
 	kfree(probe_ent);
-err_out_regions:
+err_out_msi:
+	if (have_msi)
+		pci_disable_msi(pdev);
+	else
+		pci_intx(pdev, 0);
 	pci_release_regions(pdev);
 err_out:
 	if (!pci_dev_busy)
@@ -1052,6 +1069,42 @@ err_out:
 	return rc;
 }
 
+static void ahci_remove_one (struct pci_dev *pdev)
+{
+	struct device *dev = pci_dev_to_dev(pdev);
+	struct ata_host_set *host_set = dev_get_drvdata(dev);
+	struct ahci_host_priv *hpriv = host_set->private_data;
+	struct ata_port *ap;
+	unsigned int i;
+	int have_msi;
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		ap = host_set->ports[i];
+
+		scsi_remove_host(ap->host);
+	}
+
+	have_msi = hpriv->have_msi;
+	free_irq(host_set->irq, host_set);
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		ap = host_set->ports[i];
+
+		ata_scsi_release(ap->host);
+		scsi_host_put(ap->host);
+	}
+
+	host_set->ops->host_stop(host_set);
+	kfree(host_set);
+
+	if (have_msi)
+		pci_disable_msi(pdev);
+	else
+		pci_intx(pdev, 0);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	dev_set_drvdata(dev, NULL);
+}
 
 static int __init ahci_init(void)
 {
#1 lore raw
Quoted 7 lines · Jeff Garzik

I just updated the AHCI PCI MSI support patch to support the latest ->host_stop() semantics changes that just made it into upstream.

This patch, until its merged, may always be found in the 'ahci-msi' branch of rsync://rsync.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev.git

Tested on an ich6 based system, with this ahci controller:

centera:~ # lspci -s 0000:00:1f.2 -v
0000:00:1f.2 IDE interface: Intel Corp. I/O Controller Hub SATA cc=raid (rev 03) (prog-if 8f [Master SecP SecO PriP PriO])

        Subsystem: Tyan Computer: Unknown device 5150
        Flags: bus master, 66Mhz, medium devsel, latency 0, IRQ 169
        I/O ports at e900
        I/O ports at ea00 [size=4]
        I/O ports at eb00 [size=8]
        I/O ports at ec00 [size=4]
        I/O ports at ed00 [size=16]
        Memory at d03c3000 (32-bit, non-prefetchable) [size=1K]
        Capabilities: [70] Power Management version 2

And system boots and works fine, MSI isn't enabled of course.

Also tested on an ich7 based system (945G express chipset), with this ahci controller:

nelson:~ # lspci -s 0000:00:1f.2 -v
0000:00:1f.2 Class 0106: Intel Corporation I/O Controller Hub SATA cc=AHCI (rev 01) (prog-if 01)

        Subsystem: Intel Corporation: Unknown device e302
        Flags: bus master, 66Mhz, medium devsel, latency 0, IRQ 201
        I/O ports at 40d8 [size=8]
        I/O ports at 40f4 [size=4]
        I/O ports at 40d0 [size=8]
        I/O ports at 40f0 [size=4]
        I/O ports at 4020 [size=32]
        Memory at 48304000 (32-bit, non-prefetchable) [size=1K]
        Capabilities: [80] Message Signalled Interrupts: 64bit- Queue=0/0 Enable+
        Capabilities: [70] Power Management version 2
        Capabilities: [a8] #12 [0010]

System boots and works fine (typing this message here), MSI is enabled. I double checked with an added printk :-)

So that's at least one ACK for you. Now running NCQ and MSI enabled ahci, I'm not sure SATA gets any better!

Signature · 1 line
Jens Axboe
#2 lore raw
Quoted 2 lines · Jens Axboe

System boots and works fine (typing this message here), MSI is enabled. I double checked with an added printk :-)

Any chance you could post a full /proc/interrupts output for this box?

Quoted 2 lines

So that's at least one ACK for you. Now running NCQ and MSI enabled ahci, I'm not sure SATA gets any better!

<grin>

Thanks,

Jeff

#3 lore raw
Quoted 5 lines · Jeff Garzik
Quoted 2 lines · Jens Axboe

System boots and works fine (typing this message here), MSI is enabled. I double checked with an added printk :-)

Any chance you could post a full /proc/interrupts output for this box?

Sure:

CPU0 CPU1

  0:     349415     330112    IO-APIC-edge  timer
  4:         10          0    IO-APIC-edge  serial
  8:          0          0    IO-APIC-edge  rtc
  9:          0          0   IO-APIC-level  acpi
 14:          2          0    IO-APIC-edge  ide0
169:          0          0   IO-APIC-level  uhci_hcd:usb4
177:       2565          0   IO-APIC-level  eth0
185:       6932       7195   IO-APIC-level  uhci_hcd:usb3
201:       8991       5154         PCI-MSI  libata
209:          3          0   IO-APIC-level  ehci_hcd:usb1, uhci_hcd:usb2
217:          0          0   IO-APIC-level  uhci_hcd:usb5
225:        345         51   IO-APIC-level  HDA Intel
NMI:        150         83
LOC:     671016     671636
ERR:          1
MIS:          0
Signature · 1 line
Jens Axboe