forked from Minki/linux
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>
This commit is contained in:
parent
f9e3326dce
commit
6636487e8d
@ -3,7 +3,7 @@
|
|||||||
* IDE driver for Linux.
|
* IDE driver for Linux.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2002 Vojtech Pavlik
|
* Copyright (c) 2000-2002 Vojtech Pavlik
|
||||||
* Copyright (c) 2007 Bartlomiej Zolnierkiewicz
|
* Copyright (c) 2007-2008 Bartlomiej Zolnierkiewicz
|
||||||
*
|
*
|
||||||
* Based on the work of:
|
* Based on the work of:
|
||||||
* Andre Hedrick
|
* Andre Hedrick
|
||||||
@ -263,6 +263,15 @@ static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_
|
|||||||
d.udma_mask = ATA_UDMA5;
|
d.udma_mask = ATA_UDMA5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It seems that on some nVidia controllers using AltStatus
|
||||||
|
* register can be unreliable so default to Status register
|
||||||
|
* if the device is in Compatibility Mode.
|
||||||
|
*/
|
||||||
|
if (dev->vendor == PCI_VENDOR_ID_NVIDIA &&
|
||||||
|
ide_pci_is_in_compatibility_mode(dev))
|
||||||
|
d.host_flags |= IDE_HFLAG_BROKEN_ALTSTATUS;
|
||||||
|
|
||||||
printk(KERN_INFO "%s %s: UDMA%s controller\n",
|
printk(KERN_INFO "%s %s: UDMA%s controller\n",
|
||||||
d.name, pci_name(dev), amd_dma[fls(d.udma_mask) - 1]);
|
d.name, pci_name(dev), amd_dma[fls(d.udma_mask) - 1]);
|
||||||
|
|
||||||
|
@ -468,7 +468,8 @@ int drive_is_ready (ide_drive_t *drive)
|
|||||||
* an interrupt with another pci card/device. We make no assumptions
|
* an interrupt with another pci card/device. We make no assumptions
|
||||||
* about possible isa-pnp and pci-pnp issues yet.
|
* about possible isa-pnp and pci-pnp issues yet.
|
||||||
*/
|
*/
|
||||||
if (hwif->io_ports.ctl_addr)
|
if (hwif->io_ports.ctl_addr &&
|
||||||
|
(hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0)
|
||||||
stat = hwif->tp_ops->read_altstatus(hwif);
|
stat = hwif->tp_ops->read_altstatus(hwif);
|
||||||
else
|
else
|
||||||
/* Note: this may clear a pending IRQ!! */
|
/* Note: this may clear a pending IRQ!! */
|
||||||
|
@ -266,7 +266,8 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
|
|||||||
/* take a deep breath */
|
/* take a deep breath */
|
||||||
msleep(50);
|
msleep(50);
|
||||||
|
|
||||||
if (io_ports->ctl_addr) {
|
if (io_ports->ctl_addr &&
|
||||||
|
(hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) {
|
||||||
a = tp_ops->read_altstatus(hwif);
|
a = tp_ops->read_altstatus(hwif);
|
||||||
s = tp_ops->read_status(hwif);
|
s = tp_ops->read_status(hwif);
|
||||||
if ((a ^ s) & ~ATA_IDX)
|
if ((a ^ s) & ~ATA_IDX)
|
||||||
|
@ -1296,6 +1296,13 @@ extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *o
|
|||||||
#define ide_pci_register_driver(d) pci_register_driver(d)
|
#define ide_pci_register_driver(d) pci_register_driver(d)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline int ide_pci_is_in_compatibility_mode(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 5) != 5)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *, int,
|
void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *, int,
|
||||||
hw_regs_t *, hw_regs_t **);
|
hw_regs_t *, hw_regs_t **);
|
||||||
void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *);
|
void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *);
|
||||||
@ -1375,6 +1382,7 @@ enum {
|
|||||||
IDE_HFLAG_IO_32BIT = (1 << 24),
|
IDE_HFLAG_IO_32BIT = (1 << 24),
|
||||||
/* unmask IRQs */
|
/* unmask IRQs */
|
||||||
IDE_HFLAG_UNMASK_IRQS = (1 << 25),
|
IDE_HFLAG_UNMASK_IRQS = (1 << 25),
|
||||||
|
IDE_HFLAG_BROKEN_ALTSTATUS = (1 << 26),
|
||||||
/* serialize ports if DMA is possible (for sl82c105) */
|
/* serialize ports if DMA is possible (for sl82c105) */
|
||||||
IDE_HFLAG_SERIALIZE_DMA = (1 << 27),
|
IDE_HFLAG_SERIALIZE_DMA = (1 << 27),
|
||||||
/* force host out of "simplex" mode */
|
/* force host out of "simplex" mode */
|
||||||
|
Loading…
Reference in New Issue
Block a user