diff options
Diffstat (limited to 'drivers/pci/quirks.c')
| -rw-r--r-- | drivers/pci/quirks.c | 151 | 
1 files changed, 135 insertions, 16 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index baad093aafe3..92b9efe9bcaf 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -23,6 +23,7 @@  #include <linux/acpi.h>  #include <linux/kallsyms.h>  #include <linux/dmi.h> +#include <linux/pci-aspm.h>  #include "pci.h"  int isa_dma_bridge_buggy; @@ -1584,6 +1585,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SERVERWORKS,   PCI_DEVICE_ID_SERVERWORKS_   */  #define AMD_813X_MISC			0x40  #define AMD_813X_NOIOAMODE		(1<<0) +#define AMD_813X_REV_B2			0x13  static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev)  { @@ -1591,6 +1593,8 @@ static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev)  	if (noioapicquirk)  		return; +	if (dev->revision == AMD_813X_REV_B2) +		return;  	pci_read_config_dword(dev, AMD_813X_MISC, &pci_config_dword);  	pci_config_dword &= ~AMD_813X_NOIOAMODE; @@ -1746,6 +1750,30 @@ static void __devinit quirk_e100_interrupt(struct pci_dev *dev)  }  DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_e100_interrupt); +/* + * The 82575 and 82598 may experience data corruption issues when transitioning + * out of L0S.  To prevent this we need to disable L0S on the pci-e link + */ +static void __devinit quirk_disable_aspm_l0s(struct pci_dev *dev) +{ +	dev_info(&dev->dev, "Disabling L0s\n"); +	pci_disable_link_state(dev, PCIE_LINK_STATE_L0S); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10a7, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10a9, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10b6, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10c6, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10c7, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10c8, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10d6, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10db, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10dd, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10e1, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10ec, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10f1, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10f4, quirk_disable_aspm_l0s); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1508, quirk_disable_aspm_l0s); +  static void __devinit fixup_rev1_53c810(struct pci_dev* dev)  {  	/* rev 1 ncr53c810 chips don't set the class at all which means @@ -1981,7 +2009,6 @@ static void __devinit quirk_msi_ht_cap(struct pci_dev *dev)  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.   */ @@ -2032,6 +2059,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS,  			 PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB,  			 ht_enable_msi_mapping); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, +			 ht_enable_msi_mapping); +  /* The P5N32-SLI Premium motherboard from Asus has a problem with msi   * for the MCP55 NIC. It is not yet determined whether the msi problem   * also affects other devices. As for now, turn off msi for this device. @@ -2048,11 +2078,105 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA,  			PCI_DEVICE_ID_NVIDIA_NVENET_15,  			nvenet_msi_disable); -static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) +static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev)  {  	struct pci_dev *host_bridge; +	int pos; +	int i, dev_no; +	int found = 0; + +	dev_no = dev->devfn >> 3; +	for (i = dev_no; i >= 0; i--) { +		host_bridge = pci_get_slot(dev->bus, PCI_DEVFN(i, 0)); +		if (!host_bridge) +			continue; + +		pos = pci_find_ht_capability(host_bridge, HT_CAPTYPE_SLAVE); +		if (pos != 0) { +			found = 1; +			break; +		} +		pci_dev_put(host_bridge); +	} + +	if (!found) +		return; + +	/* root did that ! */ +	if (msi_ht_cap_enabled(host_bridge)) +		goto out; + +	ht_enable_msi_mapping(dev); + +out: +	pci_dev_put(host_bridge); +} + +static void __devinit ht_disable_msi_mapping(struct pci_dev *dev) +{  	int pos, ttl = 48; +	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\n"); + +			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); +	} +} + +static int __devinit ht_check_msi_mapping(struct pci_dev *dev) +{ +	int pos, ttl = 48; +	int found = 0; + +	/* check if there is HT MSI cap or enabled on this device */ +	pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); +	while (pos && ttl--) { +		u8 flags; + +		if (found < 1) +			found = 1; +		if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, +					 &flags) == 0) { +			if (flags & HT_MSI_FLAGS_ENABLE) { +				if (found < 2) { +					found = 2; +					break; +				} +			} +		} +		pos = pci_find_next_ht_capability(dev, pos, +						  HT_CAPTYPE_MSI_MAPPING); +	} + +	return found; +} + +static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) +{ +	struct pci_dev *host_bridge; +	int pos; +	int found; + +	/* Enabling HT MSI mapping on this device breaks MCP51 */ +	if (dev->device == 0x270) +		return; + +	/* check if there is HT MSI cap or enabled on this device */ +	found = ht_check_msi_mapping(dev); + +	/* no HT MSI CAP */ +	if (found == 0) +		return; +  	/*  	 * HT MSI mapping should be disabled on devices that are below  	 * a non-Hypertransport host bridge. Locate the host bridge... @@ -2067,24 +2191,19 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)  	pos = pci_find_ht_capability(host_bridge, HT_CAPTYPE_SLAVE);  	if (pos != 0) {  		/* Host bridge is to HT */ -		ht_enable_msi_mapping(dev); +		if (found == 1) { +			/* it is not enabled, try to enable it */ +			nv_ht_enable_msi_mapping(dev); +		}  		return;  	} -	/* 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; +	/* HT MSI is not enabled */ +	if (found == 1) +		return; -		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); -	} +	/* Host bridge is not to HT, disable HT MSI mapping on this device */ +	ht_disable_msi_mapping(dev);  }  DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk);  DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk);  |