[PATCH] AHCI PCI MSI support, update 1

From: Jeff Garzik (jgarzik_at_pobox.com)
Date: 05/31/05

  • Next message: Alexey Dobriyan: "Re: potential-null-pointer-dereference-in-amiga-serial-driver.patch added to -mm tree"
    Date:	Tue, 31 May 2005 11:57:44 -0400
    To: "linux-ide@vger.kernel.org" <linux-ide@vger.kernel.org>
    
    
    

    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

    
    

    diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
    --- a/drivers/scsi/ahci.c
    +++ b/drivers/scsi/ahci.c
    @@ -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)
     {

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/


  • Next message: Alexey Dobriyan: "Re: potential-null-pointer-dereference-in-amiga-serial-driver.patch added to -mm tree"

    Relevant Pages

    • Re: [PATCH] SATA NCQ #3
      ... I still haven't gotten any acks back from anybody yet, and PCI MSI ... +static void pci_intx(struct pci_dev *pdev, ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)
    • [PATCH][RFT] AHCI message signalled interrupt (MSI) support
      ... +static void pci_intx(struct pci_dev *pdev, ... +static void ahci_remove_one (struct pci_dev *pdev) ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)
    • Re: [PATCH] PCI fixes for 2.6.0-test2
      ... static void aty128_remove(struct pci_dev *pdev); ... /* List of boards that we are trying to support */ ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)
    • [RFT PATCH] PCI MSI support for AHCI SATA driver
      ... +static void pci_intx(struct pci_dev *pdev, ... +static void ahci_remove_one (struct pci_dev *pdev) ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)