Commit 6636487e8dc49a1c43fed336bdc4a2f3d7ce6881

Authored by Bartlomiej Zolnierkiewicz
1 parent f9e3326dce

amd74xx: workaround unreliable AltStatus register for nVidia controllers

It seems that on some nVidia controllers using AltStatus register
can be unreliable so default to Status register if the PCI device
is in Compatibility Mode.  In order to achieve this:

* Add ide_pci_is_in_compatibility_mode() inline helper to <linux/ide.h>.

* Add IDE_HFLAG_BROKEN_ALTSTATUS host flag and set it in amd74xx host
  driver for nVidia controllers in Compatibility Mode.

* Teach actual_try_to_identify() and drive_is_ready() about the new flag.

This fixes the regression caused by removal of CONFIG_IDEPCI_SHARE_IRQ
config option in 2.6.25 and using AltStatus register unconditionally when
available (kernel.org bugs #11659 and #10216).

[ Moreover for CONFIG_IDEPCI_SHARE_IRQ=y (which is what most people
  and distributions use) it never worked correctly. ]

Thanks to Remy LABENE and Lars Winterfeld for help with debugging the problem.

More info at:
http://bugzilla.kernel.org/show_bug.cgi?id=11659
http://bugzilla.kernel.org/show_bug.cgi?id=10216

Reported-by: Remy LABENE <remy.labene@free.fr>
Tested-by: Remy LABENE <remy.labene@free.fr>
Tested-by: Lars Winterfeld <lars.winterfeld@tu-ilmenau.de>
Acked-by: Borislav Petkov <petkovbb@gmail.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

Showing 4 changed files with 22 additions and 3 deletions Side-by-side Diff

drivers/ide/amd74xx.c
... ... @@ -3,7 +3,7 @@
3 3 * IDE driver for Linux.
4 4 *
5 5 * Copyright (c) 2000-2002 Vojtech Pavlik
6   - * Copyright (c) 2007 Bartlomiej Zolnierkiewicz
  6 + * Copyright (c) 2007-2008 Bartlomiej Zolnierkiewicz
7 7 *
8 8 * Based on the work of:
9 9 * Andre Hedrick
... ... @@ -262,6 +262,15 @@
262 262 dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
263 263 d.udma_mask = ATA_UDMA5;
264 264 }
  265 +
  266 + /*
  267 + * It seems that on some nVidia controllers using AltStatus
  268 + * register can be unreliable so default to Status register
  269 + * if the device is in Compatibility Mode.
  270 + */
  271 + if (dev->vendor == PCI_VENDOR_ID_NVIDIA &&
  272 + ide_pci_is_in_compatibility_mode(dev))
  273 + d.host_flags |= IDE_HFLAG_BROKEN_ALTSTATUS;
265 274  
266 275 printk(KERN_INFO "%s %s: UDMA%s controller\n",
267 276 d.name, pci_name(dev), amd_dma[fls(d.udma_mask) - 1]);
drivers/ide/ide-iops.c
... ... @@ -468,7 +468,8 @@
468 468 * an interrupt with another pci card/device. We make no assumptions
469 469 * about possible isa-pnp and pci-pnp issues yet.
470 470 */
471   - if (hwif->io_ports.ctl_addr)
  471 + if (hwif->io_ports.ctl_addr &&
  472 + (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0)
472 473 stat = hwif->tp_ops->read_altstatus(hwif);
473 474 else
474 475 /* Note: this may clear a pending IRQ!! */
drivers/ide/ide-probe.c
... ... @@ -266,7 +266,8 @@
266 266 /* take a deep breath */
267 267 msleep(50);
268 268  
269   - if (io_ports->ctl_addr) {
  269 + if (io_ports->ctl_addr &&
  270 + (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) {
270 271 a = tp_ops->read_altstatus(hwif);
271 272 s = tp_ops->read_status(hwif);
272 273 if ((a ^ s) & ~ATA_IDX)
... ... @@ -1296,6 +1296,13 @@
1296 1296 #define ide_pci_register_driver(d) pci_register_driver(d)
1297 1297 #endif
1298 1298  
  1299 +static inline int ide_pci_is_in_compatibility_mode(struct pci_dev *dev)
  1300 +{
  1301 + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 5) != 5)
  1302 + return 1;
  1303 + return 0;
  1304 +}
  1305 +
1299 1306 void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *, int,
1300 1307 hw_regs_t *, hw_regs_t **);
1301 1308 void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *);
... ... @@ -1375,6 +1382,7 @@
1375 1382 IDE_HFLAG_IO_32BIT = (1 << 24),
1376 1383 /* unmask IRQs */
1377 1384 IDE_HFLAG_UNMASK_IRQS = (1 << 25),
  1385 + IDE_HFLAG_BROKEN_ALTSTATUS = (1 << 26),
1378 1386 /* serialize ports if DMA is possible (for sl82c105) */
1379 1387 IDE_HFLAG_SERIALIZE_DMA = (1 << 27),
1380 1388 /* force host out of "simplex" mode */