diff options
Diffstat (limited to 'drivers/pci/quirks.c')
| -rw-r--r-- | drivers/pci/quirks.c | 157 | 
1 files changed, 108 insertions, 49 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 320255e5e8f8..4937a088d7d8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -474,7 +474,7 @@ static void quirk_extend_bar_to_page(struct pci_dev *dev)  {  	int i; -	for (i = 0; i <= PCI_STD_RESOURCE_END; i++) { +	for (i = 0; i < PCI_STD_NUM_BARS; i++) {  		struct resource *r = &dev->resource[i];  		if (r->flags & IORESOURCE_MEM && resource_size(r) < PAGE_SIZE) { @@ -1809,7 +1809,7 @@ static void quirk_alder_ioapic(struct pci_dev *pdev)  	 * The next five BARs all seem to be rubbish, so just clean  	 * them out.  	 */ -	for (i = 1; i < 6; i++) +	for (i = 1; i < PCI_STD_NUM_BARS; i++)  		memset(&pdev->resource[i], 0, sizeof(pdev->resource[i]));  }  DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_EESSC,	quirk_alder_ioapic); @@ -4033,7 +4033,6 @@ static void quirk_fixed_dma_alias(struct pci_dev *dev)  	if (id)  		pci_add_dma_alias(dev, id->driver_data);  } -  DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADAPTEC2, 0x0285, quirk_fixed_dma_alias);  /* @@ -4081,6 +4080,40 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2260, quirk_mic_x200_dma_alias);  DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, quirk_mic_x200_dma_alias);  /* + * Intel Visual Compute Accelerator (VCA) is a family of PCIe add-in devices + * exposing computational units via Non Transparent Bridges (NTB, PEX 87xx). + * + * Similarly to MIC x200, we need to add DMA aliases to allow buffer access + * when IOMMU is enabled.  These aliases allow computational unit access to + * host memory.  These aliases mark the whole VCA device as one IOMMU + * group. + * + * All possible slot numbers (0x20) are used, since we are unable to tell + * what slot is used on other side.  This quirk is intended for both host + * and computational unit sides.  The VCA devices have up to five functions + * (four for DMA channels and one additional). + */ +static void quirk_pex_vca_alias(struct pci_dev *pdev) +{ +	const unsigned int num_pci_slots = 0x20; +	unsigned int slot; + +	for (slot = 0; slot < num_pci_slots; slot++) { +		pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x0)); +		pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x1)); +		pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x2)); +		pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x3)); +		pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x4)); +	} +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2954, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2955, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2956, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2958, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2959, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x295A, quirk_pex_vca_alias); + +/*   * The IOMMU and interrupt controller on Broadcom Vulcan/Cavium ThunderX2 are   * associated not at the root bus, but at a bridge below. This quirk avoids   * generating invalid DMA aliases. @@ -4263,6 +4296,24 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,  			 quirk_chelsio_T5_disable_root_port_attributes);  /* + * pci_acs_ctrl_enabled - compare desired ACS controls with those provided + *			  by a device + * @acs_ctrl_req: Bitmask of desired ACS controls + * @acs_ctrl_ena: Bitmask of ACS controls enabled or provided implicitly by + *		  the hardware design + * + * Return 1 if all ACS controls in the @acs_ctrl_req bitmask are included + * in @acs_ctrl_ena, i.e., the device provides all the access controls the + * caller desires.  Return 0 otherwise. + */ +static int pci_acs_ctrl_enabled(u16 acs_ctrl_req, u16 acs_ctrl_ena) +{ +	if ((acs_ctrl_req & acs_ctrl_ena) == acs_ctrl_req) +		return 1; +	return 0; +} + +/*   * AMD has indicated that the devices below do not support peer-to-peer   * in any system where they are found in the southbridge with an AMD   * IOMMU in the system.  Multifunction devices that do not support @@ -4305,7 +4356,7 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)  	/* Filter out flags not applicable to multifunction */  	acs_flags &= (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC | PCI_ACS_DT); -	return acs_flags & ~(PCI_ACS_RR | PCI_ACS_CR) ? 0 : 1; +	return pci_acs_ctrl_enabled(acs_flags, PCI_ACS_RR | PCI_ACS_CR);  #else  	return -ENODEV;  #endif @@ -4313,33 +4364,38 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)  static bool pci_quirk_cavium_acs_match(struct pci_dev *dev)  { +	if (!pci_is_pcie(dev) || pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) +		return false; + +	switch (dev->device) {  	/* -	 * Effectively selects all downstream ports for whole ThunderX 1 -	 * family by 0xf800 mask (which represents 8 SoCs), while the lower -	 * bits of device ID are used to indicate which subdevice is used -	 * within the SoC. +	 * Effectively selects all downstream ports for whole ThunderX1 +	 * (which represents 8 SoCs).  	 */ -	return (pci_is_pcie(dev) && -		(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) && -		((dev->device & 0xf800) == 0xa000)); +	case 0xa000 ... 0xa7ff: /* ThunderX1 */ +	case 0xaf84:  /* ThunderX2 */ +	case 0xb884:  /* ThunderX3 */ +		return true; +	default: +		return false; +	}  }  static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags)  { +	if (!pci_quirk_cavium_acs_match(dev)) +		return -ENOTTY; +  	/* -	 * Cavium root ports don't advertise an ACS capability.  However, +	 * Cavium Root Ports don't advertise an ACS capability.  However,  	 * the RTL internally implements similar protection as if ACS had -	 * Request Redirection, Completion Redirection, Source Validation, +	 * Source Validation, Request Redirection, Completion Redirection,  	 * and Upstream Forwarding features enabled.  Assert that the  	 * hardware implements and enables equivalent ACS functionality for  	 * these flags.  	 */ -	acs_flags &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_SV | PCI_ACS_UF); - -	if (!pci_quirk_cavium_acs_match(dev)) -		return -ENOTTY; - -	return acs_flags ? 0 : 1; +	return pci_acs_ctrl_enabled(acs_flags, +		PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);  }  static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags) @@ -4349,13 +4405,12 @@ static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags)  	 * transactions with others, allowing masking out these bits as if they  	 * were unimplemented in the ACS capability.  	 */ -	acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); - -	return acs_flags ? 0 : 1; +	return pci_acs_ctrl_enabled(acs_flags, +		PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);  }  /* - * Many Intel PCH root ports do provide ACS-like features to disable peer + * Many Intel PCH Root Ports do provide ACS-like features to disable peer   * transactions and validate bus numbers in requests, but do not provide an   * actual PCIe ACS capability.  This is the list of device IDs known to fall   * into that category as provided by Intel in Red Hat bugzilla 1037684. @@ -4403,37 +4458,32 @@ static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)  	return false;  } -#define INTEL_PCH_ACS_FLAGS (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_SV) -  static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)  { -	u16 flags = dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK ? -		    INTEL_PCH_ACS_FLAGS : 0; -  	if (!pci_quirk_intel_pch_acs_match(dev))  		return -ENOTTY; -	return acs_flags & ~flags ? 0 : 1; +	if (dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK) +		return pci_acs_ctrl_enabled(acs_flags, +			PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); + +	return pci_acs_ctrl_enabled(acs_flags, 0);  }  /* - * These QCOM root ports do provide ACS-like features to disable peer + * These QCOM Root Ports do provide ACS-like features to disable peer   * transactions and validate bus numbers in requests, but do not provide an   * actual PCIe ACS capability.  Hardware supports source validation but it   * will report the issue as Completer Abort instead of ACS Violation. - * Hardware doesn't support peer-to-peer and each root port is a root - * complex with unique segment numbers.  It is not possible for one root - * port to pass traffic to another root port.  All PCIe transactions are - * terminated inside the root port. + * Hardware doesn't support peer-to-peer and each Root Port is a Root + * Complex with unique segment numbers.  It is not possible for one Root + * Port to pass traffic to another Root Port.  All PCIe transactions are + * terminated inside the Root Port.   */  static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags)  { -	u16 flags = (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_SV); -	int ret = acs_flags & ~flags ? 0 : 1; - -	pci_info(dev, "Using QCOM ACS Quirk (%d)\n", ret); - -	return ret; +	return pci_acs_ctrl_enabled(acs_flags, +		PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);  }  static int pci_quirk_al_acs(struct pci_dev *dev, u16 acs_flags) @@ -4534,7 +4584,7 @@ static int pci_quirk_intel_spt_pch_acs(struct pci_dev *dev, u16 acs_flags)  	pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl); -	return acs_flags & ~ctrl ? 0 : 1; +	return pci_acs_ctrl_enabled(acs_flags, ctrl);  }  static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags) @@ -4548,10 +4598,9 @@ static int pci_quirk_mf_endpoint_acs(struct pci_dev *dev, u16 acs_flags)  	 * perform peer-to-peer with other functions, allowing us to mask out  	 * these bits as if they were unimplemented in the ACS capability.  	 */ -	acs_flags &= ~(PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR | -		       PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT); - -	return acs_flags ? 0 : 1; +	return pci_acs_ctrl_enabled(acs_flags, +		PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR | +		PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT);  }  static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags) @@ -4562,9 +4611,8 @@ static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags)  	 * Allow each Root Port to be in a separate IOMMU group by masking  	 * SV/RR/CR/UF bits.  	 */ -	acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); - -	return acs_flags ? 0 : 1; +	return pci_acs_ctrl_enabled(acs_flags, +		PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);  }  static const struct pci_dev_acs_enabled { @@ -4666,6 +4714,17 @@ static const struct pci_dev_acs_enabled {  	{ 0 }  }; +/* + * pci_dev_specific_acs_enabled - check whether device provides ACS controls + * @dev:	PCI device + * @acs_flags:	Bitmask of desired ACS controls + * + * Returns: + *   -ENOTTY:	No quirk applies to this device; we can't tell whether the + *		device provides the desired controls + *   0:		Device does not provide all the desired controls + *   >0:	Device provides all the controls in @acs_flags + */  int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)  {  	const struct pci_dev_acs_enabled *i; @@ -4706,7 +4765,7 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)  #define INTEL_BSPR_REG_BPPD  (1 << 9)  /* Upstream Peer Decode Configuration Register */ -#define INTEL_UPDCR_REG 0x1114 +#define INTEL_UPDCR_REG 0x1014  /* 5:0 Peer Decode Enable bits */  #define INTEL_UPDCR_REG_MASK 0x3f  |