diff options
Diffstat (limited to 'drivers/pci/quirks.c')
-rw-r--r-- | drivers/pci/quirks.c | 136 |
1 files changed, 94 insertions, 42 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 0a953d43b9a..afd914ebe21 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -867,13 +867,13 @@ static void quirk_disable_pxb(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb); - -static void __devinit quirk_sb600_sata(struct pci_dev *pdev) +static void __devinit quirk_amd_ide_mode(struct pci_dev *pdev) { - /* set sb600 sata to ahci mode */ - if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - u8 tmp; + /* set sb600/sb700/sb800 sata to ahci mode */ + u8 tmp; + pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &tmp); + if (tmp == 0x01) { pci_read_config_byte(pdev, 0x40, &tmp); pci_write_config_byte(pdev, 0x40, tmp|1); pci_write_config_byte(pdev, 0x9, 1); @@ -881,10 +881,13 @@ static void __devinit quirk_sb600_sata(struct pci_dev *pdev) pci_write_config_byte(pdev, 0x40, tmp); pdev->class = PCI_CLASS_STORAGE_SATA_AHCI; + dev_info(&pdev->dev, "set SATA to AHCI mode\n"); } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_sb600_sata); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_sb600_sata); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode); /* * Serverworks CSB5 IDE does not fully support native mode @@ -948,6 +951,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_e * accesses to the SMBus registers, with potentially bad effects. Thus you * should be very careful when adding new entries: if SMM is accessing the * Intel SMBus, this is a very good reason to leave it hidden. + * + * Likewise, many recent laptops use ACPI for thermal management. If the + * ACPI DSDT code accesses the SMBus, then Linux should not access it + * natively, and keeping the SMBus hidden is the right thing to do. If you + * are about to add an entry in the table below, please first disassemble + * the DSDT and double-check that there is no code accessing the SMBus. */ static int asus_hides_smbus; @@ -1025,11 +1034,6 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x12bf: /* HP xw4100 */ asus_hides_smbus = 1; } - else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) - switch (dev->subsystem_device) { - case 0x099c: /* HP Compaq nx6110 */ - asus_hides_smbus = 1; - } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG)) { if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) switch(dev->subsystem_device) { @@ -1498,8 +1502,8 @@ static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_f if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { #ifdef DEBUG - dev_dbg(&dev->dev, "calling quirk 0x%p", f->hook); - print_fn_descriptor_symbol(": %s()\n", + dev_dbg(&dev->dev, "calling "); + print_fn_descriptor_symbol("%s()\n", (unsigned long) f->hook); #endif f->hook(dev); @@ -1644,14 +1648,24 @@ static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) /* Turn off PCI Bus Parking */ pci_write_config_byte(dev, 0x76, b ^ 0x40); + dev_info(&dev->dev, + "Disabling VIA CX700 PCI parking\n"); + } + } + + if (pci_read_config_byte(dev, 0x72, &b) == 0) { + if (b != 0) { /* Turn off PCI Master read caching */ pci_write_config_byte(dev, 0x72, 0x0); + + /* Set PCI Master Bus time-out to "1x16 PCLK" */ pci_write_config_byte(dev, 0x75, 0x1); + + /* Disable "Read FIFO Timer" */ pci_write_config_byte(dev, 0x77, 0x0); - printk(KERN_INFO - "PCI: VIA CX700 PCI parking/caching fixup on %s\n", - pci_name(dev)); + dev_info(&dev->dev, + "Disabling VIA CX700 PCI caching\n"); } } } @@ -1723,10 +1737,34 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2 quirk_msi_ht_cap); -/* - * Force enable MSI mapping capability on HT bridges +/* The nVidia CK804 chipset may have 2 HT MSI mappings. + * MSI are supported if the MSI capability set in any of these mappings. */ -static void __devinit quirk_msi_ht_cap_enable(struct pci_dev *dev) +static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) +{ + struct pci_dev *pdev; + + if (!dev->subordinate) + return; + + /* check HT MSI cap on this chipset and the root one. + * a single one having MSI is enough to be sure that MSI are supported. + */ + pdev = pci_get_slot(dev->bus, 0); + if (!pdev) + return; + if (!msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) { + dev_warn(&dev->dev, "MSI quirk detected; " + "subordinate MSI disabled\n"); + dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; + } + pci_dev_put(pdev); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, + quirk_nvidia_ck804_msi_ht_cap); + +/* Force enable MSI mapping capability on HT bridges */ +static void __devinit ht_enable_msi_mapping(struct pci_dev *dev) { int pos, ttl = 48; @@ -1734,9 +1772,9 @@ static void __devinit quirk_msi_ht_cap_enable(struct pci_dev *dev) while (pos && ttl--) { u8 flags; - if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, &flags) == 0) { - printk(KERN_INFO "PCI: Enabling HT MSI Mapping on %s\n", - pci_name(dev)); + if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, + &flags) == 0) { + dev_info(&dev->dev, "Enabling HT MSI Mapping\n"); pci_write_config_byte(dev, pos + HT_MSI_FLAGS, flags | HT_MSI_FLAGS_ENABLE); @@ -1747,33 +1785,47 @@ static void __devinit quirk_msi_ht_cap_enable(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB, - quirk_msi_ht_cap_enable); + ht_enable_msi_mapping); -/* The nVidia CK804 chipset may have 2 HT MSI mappings. - * MSI are supported if the MSI capability set in any of these mappings. - */ -static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) +static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) { - struct pci_dev *pdev; + struct pci_dev *host_bridge; + int pos, ttl = 48; - if (!dev->subordinate) + /* + * HT MSI mapping should be disabled on devices that are below + * a non-Hypertransport host bridge. Locate the host bridge... + */ + host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)); + if (host_bridge == NULL) { + dev_warn(&dev->dev, + "nv_msi_ht_cap_quirk didn't locate host bridge\n"); return; + } - /* check HT MSI cap on this chipset and the root one. - * a single one having MSI is enough to be sure that MSI are supported. - */ - pdev = pci_get_slot(dev->bus, 0); - if (!pdev) + pos = pci_find_ht_capability(host_bridge, HT_CAPTYPE_SLAVE); + if (pos != 0) { + /* Host bridge is to HT */ + ht_enable_msi_mapping(dev); return; - if (!msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) { - dev_warn(&dev->dev, "MSI quirk detected; " - "subordinate MSI disabled\n"); - dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; } - pci_dev_put(pdev); + + /* Host bridge is not to HT, disable HT MSI mapping on this device */ + pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); + while (pos && ttl--) { + u8 flags; + + if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, + &flags) == 0) { + dev_info(&dev->dev, "Disabling HT MSI mapping"); + pci_write_config_byte(dev, pos + HT_MSI_FLAGS, + flags & ~HT_MSI_FLAGS_ENABLE); + } + pos = pci_find_next_ht_capability(dev, pos, + HT_CAPTYPE_MSI_MAPPING); + } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, - quirk_nvidia_ck804_msi_ht_cap); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk); static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev) { |