Improve MSI detection v5
Subsystems (3)
cover Improve MSI detection v5
Here's another set of patches to cleanup MSI detection to replace the patchset that is currently in Greg's tree.
After -mm5 breakage due to some root chipsets not having a subordinate bus, we now use the dev->no_msi flag to disable MSI on a chipset instead of the subordinate bus flag (see #3).
Other changes include a TTL in the pci_find_next_capability() loop to find MSI HT cap (see #5), and changing the ipath driver to use the common PCI_CAP_ID_HT (see #4).
#1 - Merge existing MSI disabling quirks
#2 - Factorize common MSI detection code from pci_enable_msi() and msix() #3 - Check root chipset no_msi flag instead of all parent busses flags #4 - Rename PCI_CAP_ID_HT_IRQCONF into PCI_CAP_ID_HT
#5 - Blacklist PCI-E chipsets depending on Hypertransport MSI capability #6 - Drop pci_msi_quirk
#7 - Drop pci bus_flags
These patches are against 2.6.17-git20.
Brice Goglin
PATCH 1/7 Merge existing MSI disabling quirks
Merge existing MSI disabling quirks into a generic one that we will use to blacklist all MSI-broken chipsets.
By the way, print the bus id of the device.
--- drivers/pci/quirks.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-)
drivers/pci/quirks.c +16 -13
@@ -585,12 +585,6 @@ {unsigned char revid, tmp; -if (dev->subordinate) { -printk (KERN_WARNING "PCI: MSI quirk detected. " -"PCI_BUS_FLAGS_NO_MSI set for subordinate bus.\n" ); - dev->subordinate->bus_flags |=PCI_BUS_FLAGS_NO_MSI ; - } -if (nr_ioapics ==0 )return ;
@@ -603,13 +597,6 @@ } }DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_AMD ,PCI_DEVICE_ID_AMD_8131_BRIDGE , quirk_amd_8131_ioapic); - -static void __init quirk_svw_msi (struct pci_dev *dev) -{ - pci_msi_quirk =1 ; -printk (KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n" ); -} -DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_SERVERWORKS ,PCI_DEVICE_ID_SERVERWORKS_GCNB_LE , quirk_svw_msi );#endif /* CONFIG_X86_IO_APIC */
@@ -1517,6 +1504,22 @@DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_NVIDIA ,PCI_DEVICE_ID_NVIDIA_CK804_PCIE , quirk_nvidia_ck804_pcie_aer_ext_cap); +#ifdef CONFIG_PCI_MSI +/* Disable MSI on chipsets that are known to not support it */ +static void __devinit quirk_disable_msi (struct pci_dev *dev) +{ +if (dev->subordinate) { +printk (KERN_WARNING "PCI: MSI quirk detected. " +"PCI_BUS_FLAGS_NO_MSI set for %s subordinate bus.\n" , +pci_name (dev)); + dev->subordinate->bus_flags |=PCI_BUS_FLAGS_NO_MSI ; + } +} +DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_AMD ,PCI_DEVICE_ID_AMD_8131_BRIDGE , quirk_disable_msi); +DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_SERVERWORKS ,PCI_DEVICE_ID_SERVERWORKS_GCNB_LE , + quirk_disable_msi); +#endif /* CONFIG_PCI_MSI */ +EXPORT_SYMBOL (pcie_mch_quirk);#ifdef CONFIG_HOTPLUG EXPORT_SYMBOL (pci_fixup_device);
PATCH 2/7 Factorize common MSI detection code from pci_enable_msi() and msix()
In reply to Brice Goglinpci_enable_msi() and pci_enable_msix() have to check same things before enabling MSI. Factorize this code in pci_msi_supported().
--- drivers/pci/msi.c | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-)
drivers/pci/msi.c +26 -20
@@ -901,6 +901,28 @@ }/** +* pci_msi_supported - check whether MSI may be enabled on device +* @dev: pointer to the pci_dev data structure of MSI device function +* +* MSI must be globally enabled and supported by the device and +* its parent busses. +**/ +static +int pci_msi_supported (struct pci_dev * dev) +{ +struct pci_bus *bus; + +if (!pci_msi_enable || !dev || dev->no_msi) +return -1 ; + +for (bus = dev->bus; bus; bus = bus->parent) +if (bus->bus_flags &PCI_BUS_FLAGS_NO_MSI ) +return -1 ; + +return 0 ; +} + +/** * pci_enable_msi - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function *
@@ -912,19 +934,11 @@**/ int pci_enable_msi (struct pci_dev * dev) { -struct pci_bus *bus; -int pos, temp, status = -EINVAL ; +int pos, temp, status;u16 control; -if (!pci_msi_enable || !dev) -return status; - -if (dev->no_msi) -return status; - -for (bus = dev->bus; bus; bus = bus->parent) -if (bus->bus_flags &PCI_BUS_FLAGS_NO_MSI ) -return -EINVAL ; +if (pci_msi_supported (dev) <0 ) +return -EINVAL ; temp = dev->irq;
@@ -1134,22 +1148,14 @@**/ int pci_enable_msix (struct pci_dev * dev,struct msix_entry *entries,int nvec) { -struct pci_bus *bus;int status, pos, nr_entries, free_vectors;int i, j, temp;u16 control;unsigned long flags; -if (!pci_msi_enable || !dev || !entries) +if (!entries ||pci_msi_supported (dev) <0 )return -EINVAL ; -if (dev->no_msi) -return -EINVAL ; - -for (bus = dev->bus; bus; bus = bus->parent) -if (bus->bus_flags &PCI_BUS_FLAGS_NO_MSI ) -return -EINVAL ; - status =msi_init ();if (status <0 )return status;
PATCH 3/7 Check root chipset no_msi flag instead of all parent busses flags
In reply to Brice GoglinMSI only requires support in the root chipset, which may not even have a subordinate bus.pci_msi_supported() now checks the no_msi flag in the root_chipset pci_dev struct instead of the PCI_BUS_FLAGS_NO_MSI flag of all its parent busses. The MSI quirk now sets the no_msi flag accordingly.
--- drivers/pci/msi.c | 15 ++++++++++----- drivers/pci/quirks.c | 10 ++++------ 2 files changed, 14 insertions(+), 11 deletions(-)
drivers/pci/msi.c +10 -5
@@ -905,19 +905,24 @@* @dev: pointer to the pci_dev data structure of MSI device function * * MSI must be globally enabled and supported by the device and -* its parent busses. +* its root chipset. **/ static int pci_msi_supported (struct pci_dev * dev) { -struct pci_bus *bus; +struct pci_dev *pdev;if (!pci_msi_enable || !dev || dev->no_msi)return -1 ; -for (bus = dev->bus; bus; bus = bus->parent) -if (bus->bus_flags &PCI_BUS_FLAGS_NO_MSI ) -return -1 ; +/* find root complex for our device */ + pdev = dev; +while (pdev->bus && pdev->bus->self) + pdev = pdev->bus->self; + +/* check whether it supports MSI */ +if (pdev->no_msi) +return -1 ;return 0 ; }
drivers/pci/quirks.c +4 -6
@@ -1508,12 +1508,10 @@/* Disable MSI on chipsets that are known to not support it */ static void __devinit quirk_disable_msi (struct pci_dev *dev) { -if (dev->subordinate) { -printk (KERN_WARNING "PCI: MSI quirk detected. " -"PCI_BUS_FLAGS_NO_MSI set for %s subordinate bus.\n" , -pci_name (dev)); - dev->subordinate->bus_flags |=PCI_BUS_FLAGS_NO_MSI ; - } +printk (KERN_WARNING "PCI: MSI quirk detected. " +"MSI disabled on chipset %s.\n" , +pci_name (dev)); + dev->no_msi =1 ; }DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_AMD ,PCI_DEVICE_ID_AMD_8131_BRIDGE , quirk_disable_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE,
Re: [patch 3/7] Check root chipset no_msi flag instead of all parent busses flags
Quoted 2 lines · Brice Goglin
MSI only requires support in the root chipset, which may not even have a subordinate bus.
Brice,
The above comment and the main part of this patch don't look right to me. Maybe it's the glass of wine I had two hours ago and it's around midnight now...
If the "root chipset" is not a PCI device and the architecture doesn't fake it, the root chipset (aka "PCI Host bus controller") is not visible to PCI subsystem. Some of the arch code (e.g. drivers/parisc/dino.c) uses "bus->self == NULL" to differentiate between PCI-PCI secondary busses and PCI bus below a "root chipset". ISTR alpha and sparc doing the same.
Can you confirm I'm remembering/understanding this bit correctly?
Quoted 3 lines
pci_msi_supported()now checks theno_msiflag in theroot_chipsetpci_devstruct instead of thePCI_BUS_FLAGS_NO_MSIflag of all its parent busses. The MSI quirk now sets theno_msiflag accordingly.
I don't see how this could work for alpha/parisc/sparc (IIRC) or any other architecture that doesn't create "fake" PCI Root busses.
I think your previous patch was correct in this regard.
Quoted 17 lines
Index:
linux-git/drivers/pci/msi.c
===================================================================drivers/pci/msi.c +2
-2@@ -905,19 +905,24 @@* @dev: pointer to the pci_dev data structure of MSI device function * * MSI must be globally enabled and supported by the device and -* its parent busses. +* its root chipset. **/ static int pci_msi_supported (struct pci_dev * dev) { -struct pci_bus *bus; +struct pci_dev *pdev;
drivers/pci/msi.c line 921
Quoted 10 lines
drivers/pci/msi.c +4
-3if (!pci_msi_enable || !dev || dev->no_msi)return -1 ; -for (bus = dev->bus; bus; bus = bus->parent) -if (bus->bus_flags &PCI_BUS_FLAGS_NO_MSI ) -return -1 ; +/* find root complex for our device */ + pdev = dev; +while (pdev->bus && pdev->bus->self) + pdev = pdev->bus->self;
In particular, I'm thinking this loop isn't correct though I'm not in a particular, erm, "certain" frame of mind right now. Under a parisc root device, pdev->bus->self would be NULL.
Maybe that's why parisc uses pci_scan_bus_parented() instead of pci_scan_bus(). (I've forgot the background behind that change).
thanks,
grant
Re: [patch 3/7] Check root chipset no_msi flag instead of all parent busses flags
Quoted 8 lines · Grant Grundler
If the "root chipset" is not a PCI device and the architecture doesn't fake it, the root chipset (aka "PCI Host bus controller") is not visible to PCI subsystem. Some of the arch code (e.g.
drivers/parisc/dino.c) uses "bus->self== NULL" to differentiate between PCI-PCI secondary busses and PCI bus below a "root chipset". ISTR alpha and sparc doing the same.Can you confirm I'm remembering/understanding this bit correctly?
I am not familiar enough with these architectures, but I guess somebody else is.
Are MSI working on these architectures? The MSI code in Linux seems to be very specific so far. And CONFIG_PCI_MSI currently depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
Quoted 9 lines
Quoted 4 lines
pci_msi_supported()now checks theno_msiflag in theroot_chipsetpci_devstruct instead of thePCI_BUS_FLAGS_NO_MSIflag of all its parent busses. The MSI quirk now sets theno_msiflag accordingly.I don't see how this could work for alpha/parisc/sparc (IIRC) or any other architecture that doesn't create "fake" PCI Root busses.
I think your previous patch was correct in this regard.
I don't think it was better. I had the same loop to find the root chipset. Only the check afterwards has been changed: instead of checking the subordinate bus flags on the root chipset, I checks its no_msi. Both patches applied to these architectures would fail to find the root chipset in the while loop. They will find a bridge right under the root chipset (or the device itself). The flags are then checked on the bridge bus, not on the bus that is right under the root chipset.
Anyway, assuming that Linux supports MSI on any of these architectures and that we find a root chipset that does not support MSI, how would we blacklist it? There's no way to add a quirk if there is no pci_dev associated to this root chipset, right?
Assuming we find a place to add some code to disable MSI (pcibios_fixup_foo?), we would have to set a no_msi flag somewhere. It might be good to revive the bus flags for this case. But, that's a lot of "assuming", I'd rather know whether all this is possible first :)
Thanks,
Brice
Re: [patch 3/7] Check root chipset no_msi flag instead of all parent busses flags
Quoted 7 lines · Brice Goglin
Quoted 6 lines · Grant Grundler
If the "root chipset" is not a PCI device and the architecture doesn't fake it, the root chipset (aka "PCI Host bus controller") is not visible to PCI subsystem. Some of the arch code (e.g.
drivers/parisc/dino.c) uses "bus->self== NULL" to differentiate between PCI-PCI secondary busses and PCI bus below a "root chipset". ISTR alpha and sparc doing the same.
Quoted 5 lines
Quoted 2 lines
Can you confirm I'm remembering/understanding this bit correctly?
I am not familiar enough with these architectures, but I guess somebody else is.
I've looked at alpha PCI code in the past (never changed it) and wrote nearly all of the parisc PCI support.
Quoted 1 line
Are MSI working on these architectures?
Not yet. But MSI support on parisc will be a summer project for me. Alpha and SPARC also use transaction based interrupts to get the attention of the CPU. So I expect MSI is possible on them.
Quoted 3 lines
The MSI code in Linux seems to
be very specific so far. AndCONFIG_PCI_MSIcurrently depends on (X86_LOCAL_APIC&&X86_IO_APIC) || IA64
I believe PPC folks are also working on support.
Quoted 11 lines
Quoted 3 lines
I don't see how this could work for alpha/parisc/sparc (IIRC) or any other architecture that doesn't create "fake" PCI Root busses.
I think your previous patch was correct in this regard.I don't think it was better. I had the same loop to find the root chipset. Only the check afterwards has been changed: instead of checking the subordinate bus flags on the root chipset, I checks its
no_msi. Both patches applied to these architectures would fail to find the root chipset in the while loop. They will find a bridge right under the root chipset (or the device itself). The flags are then checked on the bridge bus, not on the bus that is right under the root chipset.
Right - the "bridge bus" check is different than a "PCI Host bus controller" device check.
Quoted 4 lines
Anyway, assuming that Linux supports MSI on any of these architectures and that we find a root chipset that does not support MSI, how would we blacklist it? There's no way to add a quirk if there is no
pci_devassociated to this root chipset, right?
Right. parisc/ia64/et al don't need a generic black list. It's x86 or x86-64 specific.
At least until the various "x86-like" architectures use the same chipsets.
The arch support _could_ mark a flag in the "root" struct pci_bus. We wouldn't (yet) need a quirk on those arches.
I think I might have a better idea below to implement parisc support that works with the MSI flag in struct pci_dev like you want it.
Quoted 2 lines
Assuming we find a place to add some code to disable MSI (
pcibios_fixup_foo?),
Yes, pcibios_fixup_bus is normally the first chance for the arch specific code to mangle the struct pci_bus allocated by generic PCI code.
Quoted 3 lines
we would have to set a
no_msiflag somewhere.
It might be good to revive the bus flags for this case. But, that's a lot of "assuming", I'd rather know whether all this is possible first :)
MSI is certainly possible on parisc. I'm pretty sure it's possible on ppc, alpha and sparc though I don't know details. This has been discussed before...but I can't find the references.
Maybe the right "somewhere" is for pcibios_fixup_bus() to enable (or disable) MSI on each real PCI device if/when the arch can determine MSI in fact works.
I didn't think of this option last night.
I still don't want the generic PCI code to assume a "root" PCI Host bus controller was found after that loop.
thanks,
grant
Re: [patch 3/7] Check root chipset no_msi flag instead of all parent busses flags
Quoted 2 lines · Grant Grundler
I still don't want the generic PCI code to assume a "root" PCI Host bus controller was found after that loop.
If I am not mistaken, we can use the following code to check whether we found a root chipset:
unsigned cap;
u16 val;
u8 ext_type;
cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
if (cap) {
pci_read_config_word(pdev, cap + PCI_CAP_FLAGS, &val);
ext_type = (val & PCI_EXP_FLAGS_TYPE) >> 4;
if (ext_type == PCI_EXP_TYPE_ROOT_PORT)
<check no_msi flag>
}Brice
Re: [patch 3/7] Check root chipset no_msi flag instead of all parent busses flags
Quoted 10 lines · Brice Goglin
Quoted 2 lines · Grant Grundler
I still don't want the generic PCI code to assume a "root" PCI Host bus controller was found after that loop.
If I am not mistaken, we can use the following code to check whether we found a root chipset:
unsigned cap; u16 val; u8 ext_type; cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
That might work fine on x86 boxen where firmware fakes all devices to show up in PCI config space. That's not the case on many other architectures. My whole point was the pdev doesn't exist for a root chipset on those other arch's.
grant
Quoted 8 lines
if (cap) { pci_read_config_word(pdev, cap + PCI_CAP_FLAGS, &val); ext_type = (val & PCI_EXP_FLAGS_TYPE) >> 4; if (ext_type == PCI_EXP_TYPE_ROOT_PORT) <check no_msi flag> }Brice
Re: [patch 3/7] Check root chipset no_msi flag instead of all parent busses flags
Quoted 15 lines · Grant Grundler
Quoted 5 lines · Brice Goglin
Quoted 3 lines · Grant Grundler
I still don't want the generic PCI code to assume a "root" PCI Host bus controller was found after that loop.
Quoted 7 lines
If I am not mistaken, we can use the following code to check whether we found a root chipset:
unsigned cap; u16 val; u8 ext_type; cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
Quoted 5 lines
That might work fine on x86 boxen where firmware fakes all devices to show up in PCI config space. That's not the case on many other architectures. My whole point was the pdev doesn't exist for a root chipset on those other arch's.
Right, and the whole point of this check is to detect this case: my while loop cannot find a root chipset on these architectures since there is no pci_dev. So the while loop will return another pci_dev, either the device or another bridge. When we detect that this pci_dev has a wrong exp_type (not PCI_EXP_TYPE_ROOT_PORT), we know it is not a root chipset, thus we do not check its no_msi flag.
Brice
Re: [patch 3/7] Check root chipset no_msi flag instead of all parent busses flags
In reply to Brice GoglinQuoted 7 lines · Brice Goglin
plain text document attachment (03-use_root_chipset_dev_no_msi_instead_of_pci_bus_flags.patch) MSI only requires support in the root chipset, which may not even have a subordinate bus.
pci_msi_supported()now checks theno_msiflag in theroot_chipsetpci_devstruct instead of thePCI_BUS_FLAGS_NO_MSIflag of all its parent busses. The MSI quirk now sets theno_msiflag accordingly.
I think we shall have msi_ops hanging off struct pci_bus.
That way, MSI support can be "installed" off a given bus and can be handled differently when necessary. On many platforms, the MSI handling will actually be different from one bus to the next (the Apple G5 comes to mind with its PCIe off the northbridge on one side and it's HT<->PCIe tunnels on the other, using different mecanisms for MSIs, but there are or will be others).
Ben.
PATCH 4/7 Rename PCI_CAP_ID_HT_IRQCONF into PCI_CAP_ID_HT
In reply to Brice Goglin0x08 is the HT capability, while PCI_CAP_ID_HT_IRQCONF would be the subtype 0x80 that mpic_scan_ht_pic() uses.
Rename PCI_CAP_ID_HT_IRQCONF into PCI_CAP_ID_HT.
And by the way, use it in the ipath driver instead of defining its own HT_CAPABILITY_ID.
--- arch/powerpc/sysdev/mpic.c | 2 +- drivers/infiniband/hw/ipath/ipath_ht400.c | 5 ++--- include/linux/pci_regs.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-)
arch/powerpc/sysdev/mpic.c +1 -1
@@ -249,7 +249,7 @@for (pos =readb (devbase +PCI_CAPABILITY_LIST ); pos !=0 ; pos =readb (devbase + pos +PCI_CAP_LIST_NEXT )) {u8 id =readb (devbase + pos +PCI_CAP_LIST_ID ); -if (id ==PCI_CAP_ID_HT_IRQCONF ) { +if (id ==PCI_CAP_ID_HT ) { id =readb (devbase + pos +3 );if (id ==0x80 )break ;
include/linux/pci_regs.h +1 -1
@@ -196,7 +196,7 @@#define PCI_CAP_ID_MSI 0x05/* Message Signalled Interrupts */ #define PCI_CAP_ID_CHSWP 0x06/* CompactPCI HotSwap */ #define PCI_CAP_ID_PCIX 0x07/* PCI-X */ -#define PCI_CAP_ID_HT_IRQCONF 0x08/* HyperTransport IRQ Configuration */ +#define PCI_CAP_ID_HT 0x08/* HyperTransport */ #define PCI_CAP_ID_VNDR 0x09/* Vendor specific capability */ #define PCI_CAP_ID_SHPC 0x0C/* PCI Standard Hot-Plug Controller */ #define PCI_CAP_ID_EXP 0x10/* PCI Express */
drivers/infiniband/hw/ipath/ipath_ht400.c +2 -3
@@ -742,7 +742,6 @@return 0 ; } -#define HT_CAPABILITY_ID 0x08/* HT capabilities not defined in kernel */ #define HT_INTR_DISC_CONFIG 0x80/* HT interrupt and discovery cap */ #define HT_INTR_REG_INDEX 2/* intconfig requires indirect accesses */
@@ -973,7 +972,7 @@* do this early, before we ever enable errors or hardware errors, * mostly to avoid causing the chip to enter freeze mode. */ - pos =pci_find_capability (pdev,HT_CAPABILITY_ID ); + pos =pci_find_capability (pdev,PCI_CAP_ID_HT );if (!pos) {ipath_dev_err (dd,"Couldn't find HyperTransport " "capability; no interrupts\n" );
@@ -996,7 +995,7 @@else if (cap_type ==HT_INTR_DISC_CONFIG ) ihandler =set_int_handler (dd, pdev, pos); }while ((pos =pci_find_next_capability (pdev, pos, -HT_CAPABILITY_ID ))); +PCI_CAP_ID_HT )));if (!ihandler) { ipath_dev_err(dd, "Couldn't find interrupt handler in "
PATCH 5/7 Blacklist PCI-E chipsets depending on Hypertransport MSI capability
In reply to Brice GoglinIntroduce msi_ht_cap_enabled() to check the MSI capability in the Hypertransport configuration space.
It is used in a generic quirk quirk_msi_ht_cap() to check whether MSI is enabled on hypertransport chipset, and a nVidia specific quirk quirk_nvidia_ck804_msi_ht_cap() where two 2 HT MSI mappings have to be checked.
Both quirks set the no_msi flag when MSI is disabled.
---
In case of broken hardware, there's now a TTL to protect the pci_find_next_capability() loop when looking for the HT MSI cap.
drivers/pci/quirks.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 1 2 files changed, 56 insertions(+)
drivers/pci/quirks.c +55 -0
@@ -1516,6 +1516,61 @@DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_AMD ,PCI_DEVICE_ID_AMD_8131_BRIDGE , quirk_disable_msi);DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_SERVERWORKS ,PCI_DEVICE_ID_SERVERWORKS_GCNB_LE , quirk_disable_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) +{ +u8 pos; +int ttl; +for (pos =pci_find_capability (dev,PCI_CAP_ID_HT ), ttl =48 ; + pos && ttl; + pos =pci_find_next_capability (dev, pos,PCI_CAP_ID_HT ), ttl--) { +u32 cap_hdr; +/* MSI mapping section according to Hypertransport spec */ +if (pci_read_config_dword (dev, pos, &cap_hdr) ==0 + && (cap_hdr &0xf8000000 ) ==0xa8000000 /* MSI mapping */ ) { +printk (KERN_INFO "PCI: Found HT MSI mapping on %s with capability %s\n" , +pci_name (dev), cap_hdr &0x10000 ?"enabled" :"disabled" ); +return (cap_hdr &0x10000 ) !=0 ;/* MSI mapping cap enabled */ + } + } +return 0 ; +} + +/* Check the hypertransport MSI mapping to know whether MSI is enabled or not */ +static void __devinit quirk_msi_ht_cap (struct pci_dev *dev) +{ +if (!msi_ht_cap_enabled (dev)) { +printk (KERN_WARNING "PCI: MSI quirk detected. " +"MSI disabled on chipset %s.\n" , +pci_name (dev)); + dev->no_msi =1 ; + } +} +DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_SERVERWORKS ,PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE , + quirk_msi_ht_cap); + +/* 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) +{ +struct pci_dev *pdev; + +/* 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_find_slot (dev->bus->number,0 ); +if (!msi_ht_cap_enabled (dev) && !msi_ht_cap_enabled (pdev)) { +printk (KERN_WARNING "PCI: MSI quirk detected. " +"MSI disabled on chipset %s.\n" , +pci_name (dev)); + dev->no_msi =1 ; + } +} +DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_NVIDIA ,PCI_DEVICE_ID_NVIDIA_CK804_PCIE , + quirk_nvidia_ck804_msi_ht_cap);#endif /* CONFIG_PCI_MSI */ EXPORT_SYMBOL (pcie_mch_quirk);
include/linux/pci_ids.h +1 -0
@@ -1407,6 +1407,7 @@#define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009#define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017#define PCI_DEVICE_ID_SERVERWORKS_EPB 0x0103 +#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200#define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201#define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203
PATCH 6/7 Drop pci_msi_quirk
In reply to Brice Goglinpci_msi_quirk is not used anymore, the no_msi flag in the pci_dev structure of the chipset should be preferred.
Drop pci_msi_quirk completely.
--- drivers/pci/msi.c | 7 ------- drivers/pci/pci.h | 6 ------ drivers/pci/quirks.c | 2 -- 3 files changed, 15 deletions(-)
drivers/pci/msi.c +0 -7
@@ -351,13 +351,6 @@if (!status)return status; -if (pci_msi_quirk) { - pci_msi_enable =0 ; -printk (KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n" ); - status = -EINVAL ; -return status; - } - status =msi_arch_init ();if (status <0 ) { pci_msi_enable =0 ;
drivers/pci/pci.h +0 -6
@@ -42,12 +42,6 @@/* Lock for read/write access to pci device and bus lists */ extern struct rw_semaphore pci_bus_sem; -#ifdef CONFIG_X86_IO_APIC -extern int pci_msi_quirk; -#else -#define pci_msi_quirk 0 -#endif -#ifdef CONFIG_PCI_MSI void disable_msi_mode (struct pci_dev *dev,int pos,int type);void pci_no_msi (void );
drivers/pci/quirks.c +0 -2
@@ -575,8 +575,6 @@ }DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_SI ,PCI_ANY_ID , quirk_ioapic_rmw ); -int pci_msi_quirk; -#define AMD8131_revA0 0x01#define AMD8131_revB0 0x11#define AMD8131_MISC 0x40
PATCH 7/7 Drop pci bus_flags
In reply to Brice GoglinPCI_BUS_FLAGS_NO_MSI is not used anymore, and gcc does not like empty enums. Drop the bus_flags field entirely.
--- drivers/pci/probe.c | 1 - include/linux/pci.h | 6 ------ 2 files changed, 7 deletions(-)
drivers/pci/probe.c +0 -1
@@ -351,7 +351,6 @@ child->parent = parent; child->ops = parent->ops; child->sysdata = parent->sysdata; - child->bus_flags = parent->bus_flags; child->bridge =get_device (&bridge->dev); child->class_dev.class = &pcibus_class;
include/linux/pci.h +0 -6
@@ -94,11 +94,6 @@ pci_channel_io_perm_failure = (__force pci_channel_state_t) 3, }; -typedef unsigned short __bitwise pci_bus_flags_t ; -enum pci_bus_flags { -PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t )1 , -}; -struct pci_cap_saved_state {struct hlist_node next;char cap_nr;
@@ -241,7 +236,6 @@char name[48 ];unsigned short bridge_ctl;/* manage NO_ISA/FBB/et al behaviors */ -pci_bus_flags_t bus_flags;/* Inherited by child busses */ struct device *bridge;struct class_device class_dev;struct bin_attribute *legacy_io;/* legacy I/O for this bus */