libata: PCI device should be powered up before being accessed
authorTejun Heo <htejun@gmail.com>
Tue, 25 Mar 2008 03:22:47 +0000 (12:22 +0900)
committerJeff Garzik <jgarzik@redhat.com>
Thu, 17 Apr 2008 19:44:16 +0000 (15:44 -0400)
PCI device should be powered up or powered up before its PCI regsiters
are accessed.  Although PCI configuration register access is allowed
in D3hot, PCI device is free to reset its status when transiting from
D3hot to D0 causing configuration data to change.

Many libata SFF drivers which use ata_pci_init_one() read and update
configuration registers before calling ata_pci_init_one() which
enables the PCI device.  Also, in resume paths, some drivers access
registers without resuming the PCI device.

This patch adds a call to pcim_enable_device() in init path if
register is accessed before calling ata_pci_init_one() and make resume
paths first resume PCI devices, access PCI configuration regiters then
resume ATA host.

While at it...

* cmd640 was strange in that it set ->resume even when CONFIG_PM is
  not.  This is by-product of minimal build fix.  Updated.

* In cs5530, Don't BUG() on reinit failure.  Just whine and fail
  resume.

Signed-off-by: Tejun Heo <htejun@gmail.com>
19 files changed:
drivers/ata/pata_ali.c
drivers/ata/pata_amd.c
drivers/ata/pata_artop.c
drivers/ata/pata_cmd640.c
drivers/ata/pata_cmd64x.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_cs5530.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_hpt3x2n.c
drivers/ata/pata_it821x.c
drivers/ata/pata_netcell.c
drivers/ata/pata_ns87415.c
drivers/ata/pata_optidma.c
drivers/ata/pata_serverworks.c
drivers/ata/pata_sil680.c
drivers/ata/pata_sis.c
drivers/ata/pata_sl82c105.c
drivers/ata/pata_via.c

index 511a830b6256f03b00d708f08dcaf8fd24e8084f..3814aebefb2dd78cb2a37c820c3db30db90d400f 100644 (file)
@@ -637,6 +637,11 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        const struct ata_port_info *ppi[] = { NULL, NULL };
        u8 tmp;
        struct pci_dev *isa_bridge;
+       int rc;
+
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
 
        /*
         * The chipset revision selects the driver operations and
@@ -672,8 +677,15 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int ali_reinit_one(struct pci_dev *pdev)
 {
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
        ali_init_chipset(pdev);
-       return ata_pci_device_resume(pdev);
+       ata_host_resume(host);
+       return 0;
 }
 #endif
 
index 4b8d9b592ca4358359f95e5a9daef29b77aca346..5e1bc13a756bb4afb09544aa52f595b811f400b2 100644 (file)
@@ -659,10 +659,15 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        static int printed_version;
        int type = id->driver_data;
        u8 fifo;
+       int rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
+
        pci_read_config_byte(pdev, 0x41, &fifo);
 
        /* Check for AMD7409 without swdma errata and if found adjust type */
@@ -706,6 +711,13 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int amd_reinit_one(struct pci_dev *pdev)
 {
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
+
        if (pdev->vendor == PCI_VENDOR_ID_AMD) {
                u8 fifo;
                pci_read_config_byte(pdev, 0x41, &fifo);
@@ -718,7 +730,9 @@ static int amd_reinit_one(struct pci_dev *pdev)
                    pdev->device == PCI_DEVICE_ID_AMD_COBRA_7401)
                        ata_pci_clear_simplex(pdev);
        }
-       return ata_pci_device_resume(pdev);
+
+       ata_host_resume(host);
+       return 0;
 }
 #endif
 
index d4218310327b2795c1b1337eb9383ae9e5866b55..2f8148016971faafa3227929eaf7c91560606028 100644 (file)
@@ -446,11 +446,16 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
                .port_ops       = &artop6260_ops,
        };
        const struct ata_port_info *ppi[] = { NULL, NULL };
+       int rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
+
        if (id->driver_data == 0) {     /* 6210 variant */
                ppi[0] = &info_6210;
                ppi[1] = &ata_dummy_port_info;
index 43d198f909680f926464e1583e650166c193b435..0ef1d1ded1f83bf3961de2e5ec261a7aa8117d50 100644 (file)
@@ -254,20 +254,31 @@ static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                .port_ops = &cmd640_port_ops
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
+       int rc;
+
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
 
        cmd640_hardware_init(pdev);
+
        return ata_pci_init_one(pdev, ppi);
 }
 
+#ifdef CONFIG_PM
 static int cmd640_reinit_one(struct pci_dev *pdev)
 {
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
        cmd640_hardware_init(pdev);
-#ifdef CONFIG_PM
-       return ata_pci_device_resume(pdev);
-#else
+       ata_host_resume(host);
        return 0;
-#endif
 }
+#endif
 
 static const struct pci_device_id cmd640[] = {
        { PCI_VDEVICE(CMD, 0x640), 0 },
@@ -281,8 +292,8 @@ static struct pci_driver cmd640_pci_driver = {
        .remove         = ata_pci_remove_one,
 #ifdef CONFIG_PM
        .suspend        = ata_pci_device_suspend,
-#endif
        .resume         = cmd640_reinit_one,
+#endif
 };
 
 static int __init cmd640_init(void)
index 7acbbd9ee4691d81ab576659e16feeb400457fa1..1c9a8d97f874c0e2454f116984efc0ef787467f1 100644 (file)
@@ -435,6 +435,11 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        };
        const struct ata_port_info *ppi[] = { &cmd_info[id->driver_data], NULL };
        u8 mrdmode;
+       int rc;
+
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
 
        pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
        class_rev &= 0xFF;
@@ -470,7 +475,14 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int cmd64x_reinit_one(struct pci_dev *pdev)
 {
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
        u8 mrdmode;
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
+
        pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
        pci_read_config_byte(pdev, MRDMODE, &mrdmode);
        mrdmode &= ~ 0x30;      /* IRQ set up */
@@ -479,7 +491,8 @@ static int cmd64x_reinit_one(struct pci_dev *pdev)
 #ifdef CONFIG_PPC
        pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
 #endif
-       return ata_pci_device_resume(pdev);
+       ata_host_resume(host);
+       return 0;
 }
 #endif
 
index 7ed279b0a12edb90af54c013261cfadf88a8d5c1..dd6b2355fcdc8a13e52b2f43b853caaddc134c21 100644 (file)
@@ -203,6 +203,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
        struct ata_ioports *ioaddr;
        int i, rc;
 
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
+
        /* IDE port enable bits */
        pci_read_config_byte(pdev, 0x60, &pcicfg);
 
@@ -310,11 +314,20 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
 
 static int cs5520_reinit_one(struct pci_dev *pdev)
 {
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
        u8 pcicfg;
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
+
        pci_read_config_byte(pdev, 0x60, &pcicfg);
        if ((pcicfg & 0x40) == 0)
                pci_write_config_byte(pdev, 0x60, pcicfg | 0x40);
-       return ata_pci_device_resume(pdev);
+
+       ata_host_resume(host);
+       return 0;
 }
 
 /**
index e1818fdd9159eaa4a87fc5326ce660c3531d3fcb..f876aeddf1a1bcc9489d597156c4ee4bb0568d6a 100644 (file)
@@ -349,6 +349,11 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                .port_ops = &cs5530_port_ops
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
+       int rc;
+
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
 
        /* Chip initialisation */
        if (cs5530_init_chip())
@@ -364,10 +369,19 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int cs5530_reinit_one(struct pci_dev *pdev)
 {
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
+
        /* If we fail on resume we are doomed */
        if (cs5530_init_chip())
-               BUG();
-       return ata_pci_device_resume(pdev);
+               return -EIO;
+
+       ata_host_resume(host);
+       return 0;
 }
 #endif /* CONFIG_PM */
 
index a742efa0da2b53cbde8409e87a6a57c01b503c76..a82089048f580f15d7bd134455d8454552e433e4 100644 (file)
@@ -402,6 +402,11 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
        u32 class_rev;
        u32 reg1;
+       int rc;
+
+       rc = pcim_enable_device(dev);
+       if (rc)
+               return rc;
 
        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
        class_rev &= 0xFF;
@@ -435,8 +440,15 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int hpt36x_reinit_one(struct pci_dev *dev)
 {
+       struct ata_host *host = dev_get_drvdata(&dev->dev);
+       int rc;
+
+       rc = ata_pci_device_do_resume(dev);
+       if (rc)
+               return rc;
        hpt36x_init_chipset(dev);
-       return ata_pci_device_resume(dev);
+       ata_host_resume(host);
+       return 0;
 }
 #endif
 
index 9a10878b2ad870049cbd0341dee7b30adacbf44c..2ddcd07a75182cc9cae43e247c4cd02c364c2573 100644 (file)
@@ -966,6 +966,11 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
        const struct hpt_chip *chip_table;
        int clock_slot;
+       int rc;
+
+       rc = pcim_enable_device(dev);
+       if (rc)
+               return rc;
 
        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
        class_rev &= 0xFF;
index 9f1c084f846f4d3fbbe75d7013cc3065685b3a31..3a517cb9bd3ee9ccc8c99c88d53153791397c875 100644 (file)
@@ -505,6 +505,11 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        unsigned int f_low, f_high;
        int adjust;
        unsigned long iobase = pci_resource_start(dev, 4);
+       int rc;
+
+       rc = pcim_enable_device(dev);
+       if (rc)
+               return rc;
 
        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
        class_rev &= 0xFF;
index 257951d03dbbffbb90520e66c96421dd2f15b148..6bdbb7140dfa522daf5b7bcccb1d0b290e7c79d1 100644 (file)
@@ -759,6 +759,11 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        const struct ata_port_info *ppi[] = { NULL, NULL };
        static char *mode[2] = { "pass through", "smart" };
+       int rc;
+
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
 
        /* Force the card into bypass mode if so requested */
        if (it8212_noraid) {
@@ -780,10 +785,17 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int it821x_reinit_one(struct pci_dev *pdev)
 {
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
        /* Resume - turn raid back off if need be */
        if (it8212_noraid)
                it821x_disable_raid(pdev);
-       return ata_pci_device_resume(pdev);
+       ata_host_resume(host);
+       return rc;
 }
 #endif
 
index 25c922abd5540e820ab5a6f879ea982306767c01..0e4a08e15209e1b72eaa510dcf882709923d08fa 100644 (file)
@@ -100,11 +100,16 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e
                .port_ops       = &netcell_ops,
        };
        const struct ata_port_info *port_info[] = { &info, NULL };
+       int rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
+
        /* Any chip specific setup/optimisation/messages here */
        ata_pci_clear_simplex(pdev);
 
index d0e2e50823b1144ed1735ae8524b7dbb3536c186..93eb958cb0c94689713292e0db064ff27fe80097 100644 (file)
@@ -410,6 +410,7 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e
                .port_ops       = &ns87415_pata_ops,
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
+       int rc;
 #if defined(CONFIG_SUPERIO)
        static const struct ata_port_info info87560 = {
                .sht            = &ns87415_sht,
@@ -425,6 +426,11 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
+
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
+
        /* Select 512 byte sectors */
        pci_write_config_byte(pdev, 0x55, 0xEE);
        /* Select PIO0 8bit clocking */
index f9b485a487ae75c7da9ed0097e241a898154df81..be8c421dc2aa6245dd915fa9e92a99e8e13894a7 100644 (file)
@@ -497,10 +497,15 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        };
        const struct ata_port_info *ppi[] = { &info_82c700, NULL };
        static int printed_version;
+       int rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
 
+       rc = pcim_enable_device(dev);
+       if (rc)
+               return rc;
+
        /* Fixed location chipset magic */
        inw(0x1F1);
        inw(0x1F1);
index a589c0fa0dbb699d3e1108f59b577cc645f4bfad..6702df37cfed00e8514009b6f1cbcce947d13139 100644 (file)
@@ -498,6 +498,11 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
                }
        };
        const struct ata_port_info *ppi[] = { &info[id->driver_data], NULL };
+       int rc;
+
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
 
        /* Force master latency timer to 64 PCI clocks */
        pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
@@ -535,11 +540,17 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
 #ifdef CONFIG_PM
 static int serverworks_reinit_one(struct pci_dev *pdev)
 {
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
+
        /* Force master latency timer to 64 PCI clocks */
        pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
 
-       switch (pdev->device)
-       {
+       switch (pdev->device) {
                case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
                        serverworks_fixup_osb4(pdev);
                        break;
@@ -554,7 +565,9 @@ static int serverworks_reinit_one(struct pci_dev *pdev)
                        serverworks_fixup_ht1000(pdev);
                        break;
        }
-       return ata_pci_device_resume(pdev);
+
+       ata_host_resume(host);
+       return 0;
 }
 #endif
 
index 7c5b2dd9a1a1fdd851775cb462414f1dd8bc7457..f4dc09718cab5f48d415b88db7a5dbf4d28b0bde 100644 (file)
@@ -346,6 +346,10 @@ static int __devinit sil680_init_one(struct pci_dev *pdev,
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
+
        switch (sil680_init_chip(pdev, &try_mmio)) {
                case 0:
                        ppi[0] = &info_slow;
@@ -406,10 +410,15 @@ use_ioports:
 #ifdef CONFIG_PM
 static int sil680_reinit_one(struct pci_dev *pdev)
 {
-       int try_mmio;
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       int try_mmio, rc;
 
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
        sil680_init_chip(pdev, &try_mmio);
-       return ata_pci_device_resume(pdev);
+       ata_host_resume(host);
+       return 0;
 }
 #endif
 
index dc7e91562e436fafadab3d2796e328ac4cf5b351..abda90f5124753f880d339e6fb35c7d1b2a0d978 100644 (file)
@@ -862,6 +862,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        struct pci_dev *host = NULL;
        struct sis_chipset *chipset = NULL;
        struct sis_chipset *sets;
+       int rc;
 
        static struct sis_chipset sis_chipsets[] = {
 
@@ -914,8 +915,11 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       /* We have to find the bridge first */
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
 
+       /* We have to find the bridge first */
        for (sets = &sis_chipsets[0]; sets->device; sets++) {
                host = pci_get_device(PCI_VENDOR_ID_SI, sets->device, NULL);
                if (host != NULL) {
index 81ef207f82652ad7b3002ac77b10d42daf2473cf..6c37181341ea91a215fb00648c9d0020fbc4328a 100644 (file)
@@ -344,6 +344,11 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
                                               NULL };
        u32 val;
        int rev;
+       int rc;
+
+       rc = pcim_enable_device(dev);
+       if (rc)
+               return rc;
 
        rev = sl82c105_bridge_revision(dev);
 
index d119a68c388fef2cdf87bbf8c024b9d3c1887f49..24430f70f00e3032f8d47d9c49aa5142e4668157 100644 (file)
@@ -524,10 +524,15 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        static int printed_version;
        u8 enable;
        u32 timing;
+       int rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
+
        /* To find out how the IDE will behave and what features we
           actually have to look at the bridge not the IDE controller */
        for (config = via_isa_bridges; config->id; config++)
@@ -615,6 +620,11 @@ static int via_reinit_one(struct pci_dev *pdev)
        u32 timing;
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
        const struct via_isa_bridge *config = host->private_data;
+       int rc;
+
+       rc = ata_pci_device_do_resume(pdev);
+       if (rc)
+               return rc;
 
        via_config_fifo(pdev, config->flags);
 
@@ -630,7 +640,9 @@ static int via_reinit_one(struct pci_dev *pdev)
                timing &= ~0x80008;
                pci_write_config_dword(pdev, 0x50, timing);
        }
-       return ata_pci_device_resume(pdev);
+
+       ata_host_resume(host);
+       return 0;
 }
 #endif