aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2009-01-01 22:04:48 -0500
committerJeff Garzik <jgarzik@redhat.com>2009-01-08 16:09:43 -0500
commit2852bcf7c12d3027c5d10f4f5ca5fada24ce8088 (patch)
tree82a36950e8b3926573d95b23b344e19149915502 /drivers/ata
parentfc80902fdf4219a81eccca4a06259c4b56812ba5 (diff)
ata_piix: save, use saved and restore IOCFG
Certain ACPI implementations mess up IOCFG on _STM making libata detect cable type incorrectly after a suspend/resume cycle. This patch makes ata_piix save IOCFG on attach, use the saved value for things which aren't dynamic and restore it on detach so that the next driver also gets the BIOS initialized value. This patch contains the following changes. * makes ich_pata_cable_detect() use saved_iocfg. * make piix_iocfg_bit18_quirk() take @host and use saved_iocfg. * hpriv allocation moved upwards to save iocfg before doing anything else. This fixes bz#11879. Andreas Mohr reported and diagnosed the problem. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Andreas Mohr <andi@lisas.de> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/ata_piix.c49
1 files changed, 34 insertions, 15 deletions
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 5fdf1678d0cc..78659546130c 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -154,11 +154,13 @@ struct piix_map_db {
154 154
155struct piix_host_priv { 155struct piix_host_priv {
156 const int *map; 156 const int *map;
157 u32 saved_iocfg;
157 void __iomem *sidpr; 158 void __iomem *sidpr;
158}; 159};
159 160
160static int piix_init_one(struct pci_dev *pdev, 161static int piix_init_one(struct pci_dev *pdev,
161 const struct pci_device_id *ent); 162 const struct pci_device_id *ent);
163static void piix_remove_one(struct pci_dev *pdev);
162static int piix_pata_prereset(struct ata_link *link, unsigned long deadline); 164static int piix_pata_prereset(struct ata_link *link, unsigned long deadline);
163static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev); 165static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev);
164static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev); 166static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev);
@@ -296,7 +298,7 @@ static struct pci_driver piix_pci_driver = {
296 .name = DRV_NAME, 298 .name = DRV_NAME,
297 .id_table = piix_pci_tbl, 299 .id_table = piix_pci_tbl,
298 .probe = piix_init_one, 300 .probe = piix_init_one,
299 .remove = ata_pci_remove_one, 301 .remove = piix_remove_one,
300#ifdef CONFIG_PM 302#ifdef CONFIG_PM
301 .suspend = piix_pci_device_suspend, 303 .suspend = piix_pci_device_suspend,
302 .resume = piix_pci_device_resume, 304 .resume = piix_pci_device_resume,
@@ -610,8 +612,9 @@ static const struct ich_laptop ich_laptop[] = {
610static int ich_pata_cable_detect(struct ata_port *ap) 612static int ich_pata_cable_detect(struct ata_port *ap)
611{ 613{
612 struct pci_dev *pdev = to_pci_dev(ap->host->dev); 614 struct pci_dev *pdev = to_pci_dev(ap->host->dev);
615 struct piix_host_priv *hpriv = ap->host->private_data;
613 const struct ich_laptop *lap = &ich_laptop[0]; 616 const struct ich_laptop *lap = &ich_laptop[0];
614 u8 tmp, mask; 617 u8 mask;
615 618
616 /* Check for specials - Acer Aspire 5602WLMi */ 619 /* Check for specials - Acer Aspire 5602WLMi */
617 while (lap->device) { 620 while (lap->device) {
@@ -625,8 +628,7 @@ static int ich_pata_cable_detect(struct ata_port *ap)
625 628
626 /* check BIOS cable detect results */ 629 /* check BIOS cable detect results */
627 mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; 630 mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
628 pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); 631 if ((hpriv->saved_iocfg & mask) == 0)
629 if ((tmp & mask) == 0)
630 return ATA_CBL_PATA40; 632 return ATA_CBL_PATA40;
631 return ATA_CBL_PATA80; 633 return ATA_CBL_PATA80;
632} 634}
@@ -1350,7 +1352,7 @@ static int __devinit piix_init_sidpr(struct ata_host *host)
1350 return 0; 1352 return 0;
1351} 1353}
1352 1354
1353static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) 1355static void piix_iocfg_bit18_quirk(struct ata_host *host)
1354{ 1356{
1355 static const struct dmi_system_id sysids[] = { 1357 static const struct dmi_system_id sysids[] = {
1356 { 1358 {
@@ -1367,7 +1369,8 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
1367 1369
1368 { } /* terminate list */ 1370 { } /* terminate list */
1369 }; 1371 };
1370 u32 iocfg; 1372 struct pci_dev *pdev = to_pci_dev(host->dev);
1373 struct piix_host_priv *hpriv = host->private_data;
1371 1374
1372 if (!dmi_check_system(sysids)) 1375 if (!dmi_check_system(sysids))
1373 return; 1376 return;
@@ -1376,12 +1379,11 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
1376 * seem to use it to disable a channel. Clear the bit on the 1379 * seem to use it to disable a channel. Clear the bit on the
1377 * affected systems. 1380 * affected systems.
1378 */ 1381 */
1379 pci_read_config_dword(pdev, PIIX_IOCFG, &iocfg); 1382 if (hpriv->saved_iocfg & (1 << 18)) {
1380 if (iocfg & (1 << 18)) {
1381 dev_printk(KERN_INFO, &pdev->dev, 1383 dev_printk(KERN_INFO, &pdev->dev,
1382 "applying IOCFG bit18 quirk\n"); 1384 "applying IOCFG bit18 quirk\n");
1383 iocfg &= ~(1 << 18); 1385 pci_write_config_dword(pdev, PIIX_IOCFG,
1384 pci_write_config_dword(pdev, PIIX_IOCFG, iocfg); 1386 hpriv->saved_iocfg & ~(1 << 18));
1385 } 1387 }
1386} 1388}
1387 1389
@@ -1430,6 +1432,17 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
1430 if (rc) 1432 if (rc)
1431 return rc; 1433 return rc;
1432 1434
1435 hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
1436 if (!hpriv)
1437 return -ENOMEM;
1438
1439 /* Save IOCFG, this will be used for cable detection, quirk
1440 * detection and restoration on detach. This is necessary
1441 * because some ACPI implementations mess up cable related
1442 * bits on _STM. Reported on kernel bz#11879.
1443 */
1444 pci_read_config_dword(pdev, PIIX_IOCFG, &hpriv->saved_iocfg);
1445
1433 /* ICH6R may be driven by either ata_piix or ahci driver 1446 /* ICH6R may be driven by either ata_piix or ahci driver
1434 * regardless of BIOS configuration. Make sure AHCI mode is 1447 * regardless of BIOS configuration. Make sure AHCI mode is
1435 * off. 1448 * off.
@@ -1441,10 +1454,6 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
1441 } 1454 }
1442 1455
1443 /* SATA map init can change port_info, do it before prepping host */ 1456 /* SATA map init can change port_info, do it before prepping host */
1444 hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
1445 if (!hpriv)
1446 return -ENOMEM;
1447
1448 if (port_flags & ATA_FLAG_SATA) 1457 if (port_flags & ATA_FLAG_SATA)
1449 hpriv->map = piix_init_sata_map(pdev, port_info, 1458 hpriv->map = piix_init_sata_map(pdev, port_info,
1450 piix_map_db_table[ent->driver_data]); 1459 piix_map_db_table[ent->driver_data]);
@@ -1463,7 +1472,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
1463 } 1472 }
1464 1473
1465 /* apply IOCFG bit18 quirk */ 1474 /* apply IOCFG bit18 quirk */
1466 piix_iocfg_bit18_quirk(pdev); 1475 piix_iocfg_bit18_quirk(host);
1467 1476
1468 /* On ICH5, some BIOSen disable the interrupt using the 1477 /* On ICH5, some BIOSen disable the interrupt using the
1469 * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3. 1478 * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
@@ -1488,6 +1497,16 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
1488 return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht); 1497 return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht);
1489} 1498}
1490 1499
1500static void piix_remove_one(struct pci_dev *pdev)
1501{
1502 struct ata_host *host = dev_get_drvdata(&pdev->dev);
1503 struct piix_host_priv *hpriv = host->private_data;
1504
1505 pci_write_config_dword(pdev, PIIX_IOCFG, hpriv->saved_iocfg);
1506
1507 ata_pci_remove_one(pdev);
1508}
1509
1491static int __init piix_init(void) 1510static int __init piix_init(void)
1492{ 1511{
1493 int rc; 1512 int rc;