From aff6136974e4ac43574973a5b4de15d97506b16a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 26 May 2010 12:21:10 +0200 Subject: PCI quirk: AMD 780: work around wrong vendor ID on APC bridge In all AMD 780 family northbridges, the vendor ID of the internal graphics PCI/PCI bridge reads not as AMD but as that of the mainboard vendor, because the hardware actually returns the value of the subsystem vendor ID (erratum 18). We currently have additional quirk entries for Asus and Acer, but it is likely that we will encounter more systems with other vendor IDs. Since we do not know in advance all possible vendor IDs, a better way to find the device is to declare the quirk on the host bridge, whose ID is always correct, and use that device as a stepping stone to find the PCI/ PCI bridge, if present. Reviewed-by: Matthew Wilcox Signed-off-by: Clemens Ladisch Signed-off-by: Jesse Barnes --- drivers/pci/quirks.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers/pci/quirks.c') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 477345d41641..4334d15a8141 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2126,12 +2126,29 @@ static void __devinit quirk_disable_msi(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x9602, quirk_disable_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ASUSTEK, 0x9602, quirk_disable_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AI, 0x9602, quirk_disable_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0xa238, quirk_disable_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x5a3f, quirk_disable_msi); +/* + * The APC bridge device in AMD 780 family northbridges has some random + * OEM subsystem ID in its vendor ID register (erratum 18), so instead + * we use the possible vendor/device IDs of the host bridge for the + * declared quirk, and search for the APC bridge by slot number. + */ +static void __devinit quirk_amd_780_apc_msi(struct pci_dev *host_bridge) +{ + struct pci_dev *apc_bridge; + + apc_bridge = pci_get_slot(host_bridge->bus, PCI_DEVFN(1, 0)); + if (apc_bridge) { + if (apc_bridge->device == 0x9602) + quirk_disable_msi(apc_bridge); + pci_dev_put(apc_bridge); + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x9600, quirk_amd_780_apc_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x9601, quirk_amd_780_apc_msi); + /* Go through the list of Hypertransport capabilities and * return 1 if a HT MSI capability is found and enabled */ static int __devinit msi_ht_cap_enabled(struct pci_dev *dev) -- cgit v1.2.3 From 549e15611b4ac1de51ef0e0a79c2704f50a638a2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 May 2010 10:22:55 +0200 Subject: PCI: disable MSI on VIA K8M800 MSI delivery from on-board ahci controller doesn't work on K8M800. At this point, it's unclear whether the culprit is with the ahci controller or the host bridge. Given the track record and considering the rather minimal impact of MSI, disabling it seems reasonable. Signed-off-by: Tejun Heo Reported-by: Rainer Hurtado Navarro Cc: stable@kernel.org Signed-off-by: Jesse Barnes --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/quirks.c') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 4334d15a8141..3a81d9d44019 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2115,6 +2115,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disabl DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3336, quirk_disable_all_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disable_all_msi); /* Disable MSI on chipsets that are known to not support it */ static void __devinit quirk_disable_msi(struct pci_dev *dev) -- cgit v1.2.3 From 253d2e549818f5a4a52e2db0aba3dacee21e5b38 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Fri, 16 Jul 2010 10:19:22 -0700 Subject: PCI: disable mmio during bar sizing It is a known issue that mmio decoding shall be disabled while doing PCI bar sizing. Host bridge and other devices (PCI PIC) shall be excluded for certain platforms. This patch mainly comes from Mathew Willcox's patch in http://kerneltrap.org/mailarchive/linux-kernel/2007/9/13/258969. A new flag bit "mmio_alway_on" is added to pci_dev with the intention that devices with their mmio decoding cannot be disabled during BAR sizing shall have this bit set, preferrablly in their quirks. Without this patch, Intel Moorestown platform graphics unit will be corrupted during bar sizing activities. Signed-off-by: Jacob Pan Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 10 ++++++++++ drivers/pci/quirks.c | 13 +++++++++++++ include/linux/pci.h | 2 ++ 3 files changed, 25 insertions(+) (limited to 'drivers/pci/quirks.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f4adba2d1dd3..12625d90f8b5 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -163,9 +163,16 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, struct resource *res, unsigned int pos) { u32 l, sz, mask; + u16 orig_cmd; mask = type ? PCI_ROM_ADDRESS_MASK : ~0; + if (!dev->mmio_always_on) { + pci_read_config_word(dev, PCI_COMMAND, &orig_cmd); + pci_write_config_word(dev, PCI_COMMAND, + orig_cmd & ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO)); + } + res->name = pci_name(dev); pci_read_config_dword(dev, pos, &l); @@ -173,6 +180,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, pci_read_config_dword(dev, pos, &sz); pci_write_config_dword(dev, pos, l); + if (!dev->mmio_always_on) + pci_write_config_word(dev, PCI_COMMAND, orig_cmd); + /* * All bits set in sz means the device isn't working properly. * If the BAR isn't implemented, all bits must be 0. If it's a diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 3a81d9d44019..202efa6f57c4 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -91,6 +91,19 @@ static void __devinit quirk_resource_alignment(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment); +/* + * Decoding should be disabled for a PCI device during BAR sizing to avoid + * conflict. But doing so may cause problems on host bridge and perhaps other + * key system devices. For devices that need to have mmio decoding always-on, + * we need to set the dev->mmio_always_on bit. + */ +static void __devinit quirk_mmio_always_on(struct pci_dev *dev) +{ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) + dev->mmio_always_on = 1; +} +DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, quirk_mmio_always_on); + /* The Mellanox Tavor device gives false positive parity errors * Mark this device with a broken_parity_status, to allow * PCI scanning code to "skip" this now blacklisted device. diff --git a/include/linux/pci.h b/include/linux/pci.h index f26fda76b87f..b1d17956a153 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -270,6 +270,8 @@ struct pci_dev { unsigned int d1_support:1; /* Low power state D1 is supported */ unsigned int d2_support:1; /* Low power state D2 is supported */ unsigned int no_d1d2:1; /* Only allow D0 and D3 */ + unsigned int mmio_always_on:1; /* disallow turning off io/mem + decoding during bar sizing */ unsigned int wakeup_prepared:1; unsigned int d3_delay; /* D3->D0 transition time in ms */ -- cgit v1.2.3 From 4e344b1cc53989e8ecc1140e9346f657d7c8aa9e Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Sat, 3 Jul 2010 20:04:39 +0400 Subject: PCI: use for_each_pci_dev() Use for_each_pci_dev() to simplify the code. Signed-off-by: Kulikov Vasiliy Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/fakephp.c | 2 +- drivers/pci/proc.c | 4 ++-- drivers/pci/quirks.c | 2 +- drivers/pci/search.c | 2 +- drivers/pci/setup-irq.c | 3 +-- 5 files changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/pci/quirks.c') diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index 5317e4d7d96e..17d10e2e8fb6 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -135,7 +135,7 @@ static int __init init_legacy(void) struct pci_dev *pdev = NULL; /* Add existing devices */ - while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) + for_each_pci_dev(pdev) legacy_add_slot(pdev); /* Be alerted of any new ones */ diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 68316b59d7d3..01f0306525a5 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -483,9 +483,9 @@ static int __init pci_proc_init(void) proc_create("devices", 0, proc_bus_pci_dir, &proc_bus_pci_dev_operations); proc_initialized = 1; - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + for_each_pci_dev(dev) pci_proc_attach_device(dev); - } + return 0; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 202efa6f57c4..8141f442e3df 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2773,7 +2773,7 @@ static int __init pci_apply_final_quirks(void) printk(KERN_DEBUG "PCI: CLS %u bytes\n", pci_cache_line_size << 2); - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + for_each_pci_dev(dev) { pci_fixup_device(pci_fixup_final, dev); /* * If arch hasn't set it explicitly yet, use the CLS diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 20d03f772289..9d75dc8ca602 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -169,7 +169,7 @@ struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus, { struct pci_dev *dev = NULL; - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + for_each_pci_dev(dev) { if (pci_domain_nr(dev->bus) == domain && (dev->bus->number == bus && dev->devfn == devfn)) return dev; diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index aa795fd428de..eec9738f3492 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -59,7 +59,6 @@ pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *), int (*map_irq)(struct pci_dev *, u8, u8)) { struct pci_dev *dev = NULL; - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + for_each_pci_dev(dev) pdev_fixup_irq(dev, swizzle, map_irq); - } } -- cgit v1.2.3 From 3d2a531804d16cd8df6dbbb0429c6f143e756049 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 23 Jul 2010 22:19:55 +0200 Subject: PCI: Do not run NVidia quirks related to MSI with MSI disabled There is no reason to run NVidia-specific quirks related to HT MSI mappings with MSI disabled via pci=nomsi, so make __nv_msi_ht_cap_quirk() return immediately in that case. This allows at least one machine to boot 100% of the time with pci=nomsi (it still doesn't boot reliably without that). Addresses https://bugzilla.kernel.org/show_bug.cgi?id=16443 . Cc: stable@kernel.org Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/quirks.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/pci/quirks.c') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 8141f442e3df..a1682f19bcb0 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2421,6 +2421,9 @@ static void __devinit __nv_msi_ht_cap_quirk(struct pci_dev *dev, int all) int pos; int found; + if (!pci_msi_enabled()) + return; + /* check if there is HT MSI cap or enabled on this device */ found = ht_check_msi_mapping(dev); -- cgit v1.2.3