mirror of https://gitee.com/openkylin/linux.git
Merge branch 'pci/virtualization' into next
* pci/virtualization: PCI: Enable quirks for PCIe ACS on Intel PCH root ports PCI: Add pci_dev_flag for ACS enable quirks PCI: Add device-specific PCI ACS enable
This commit is contained in:
commit
c80ef97ae4
|
@ -2180,21 +2180,18 @@ void pci_request_acs(void)
|
|||
}
|
||||
|
||||
/**
|
||||
* pci_enable_acs - enable ACS if hardware support it
|
||||
* pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
|
||||
* @dev: the PCI device
|
||||
*/
|
||||
void pci_enable_acs(struct pci_dev *dev)
|
||||
static int pci_std_enable_acs(struct pci_dev *dev)
|
||||
{
|
||||
int pos;
|
||||
u16 cap;
|
||||
u16 ctrl;
|
||||
|
||||
if (!pci_acs_enable)
|
||||
return;
|
||||
|
||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
|
||||
if (!pos)
|
||||
return;
|
||||
return -ENODEV;
|
||||
|
||||
pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
|
||||
pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
|
||||
|
@ -2212,6 +2209,23 @@ void pci_enable_acs(struct pci_dev *dev)
|
|||
ctrl |= (cap & PCI_ACS_UF);
|
||||
|
||||
pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_enable_acs - enable ACS if hardware support it
|
||||
* @dev: the PCI device
|
||||
*/
|
||||
void pci_enable_acs(struct pci_dev *dev)
|
||||
{
|
||||
if (!pci_acs_enable)
|
||||
return;
|
||||
|
||||
if (!pci_std_enable_acs(dev))
|
||||
return;
|
||||
|
||||
pci_dev_specific_enable_acs(dev);
|
||||
}
|
||||
|
||||
static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
|
||||
|
|
|
@ -3423,6 +3423,61 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
|
|||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
static const u16 pci_quirk_intel_pch_acs_ids[] = {
|
||||
/* Ibexpeak PCH */
|
||||
0x3b42, 0x3b43, 0x3b44, 0x3b45, 0x3b46, 0x3b47, 0x3b48, 0x3b49,
|
||||
0x3b4a, 0x3b4b, 0x3b4c, 0x3b4d, 0x3b4e, 0x3b4f, 0x3b50, 0x3b51,
|
||||
/* Cougarpoint PCH */
|
||||
0x1c10, 0x1c11, 0x1c12, 0x1c13, 0x1c14, 0x1c15, 0x1c16, 0x1c17,
|
||||
0x1c18, 0x1c19, 0x1c1a, 0x1c1b, 0x1c1c, 0x1c1d, 0x1c1e, 0x1c1f,
|
||||
/* Pantherpoint PCH */
|
||||
0x1e10, 0x1e11, 0x1e12, 0x1e13, 0x1e14, 0x1e15, 0x1e16, 0x1e17,
|
||||
0x1e18, 0x1e19, 0x1e1a, 0x1e1b, 0x1e1c, 0x1e1d, 0x1e1e, 0x1e1f,
|
||||
/* Lynxpoint-H PCH */
|
||||
0x8c10, 0x8c11, 0x8c12, 0x8c13, 0x8c14, 0x8c15, 0x8c16, 0x8c17,
|
||||
0x8c18, 0x8c19, 0x8c1a, 0x8c1b, 0x8c1c, 0x8c1d, 0x8c1e, 0x8c1f,
|
||||
/* Lynxpoint-LP PCH */
|
||||
0x9c10, 0x9c11, 0x9c12, 0x9c13, 0x9c14, 0x9c15, 0x9c16, 0x9c17,
|
||||
0x9c18, 0x9c19, 0x9c1a, 0x9c1b,
|
||||
/* Wildcat PCH */
|
||||
0x9c90, 0x9c91, 0x9c92, 0x9c93, 0x9c94, 0x9c95, 0x9c96, 0x9c97,
|
||||
0x9c98, 0x9c99, 0x9c9a, 0x9c9b,
|
||||
};
|
||||
|
||||
static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Filter out a few obvious non-matches first */
|
||||
if (!pci_is_pcie(dev) || pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pci_quirk_intel_pch_acs_ids); i++)
|
||||
if (pci_quirk_intel_pch_acs_ids[i] == dev->device)
|
||||
return true;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static const struct pci_dev_acs_enabled {
|
||||
u16 vendor;
|
||||
u16 device;
|
||||
|
@ -3434,6 +3489,7 @@ static const struct pci_dev_acs_enabled {
|
|||
{ PCI_VENDOR_ID_ATI, 0x439d, pci_quirk_amd_sb_acs },
|
||||
{ PCI_VENDOR_ID_ATI, 0x4384, pci_quirk_amd_sb_acs },
|
||||
{ PCI_VENDOR_ID_ATI, 0x4399, pci_quirk_amd_sb_acs },
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
@ -3461,3 +3517,132 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
|
|||
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
/* Config space offset of Root Complex Base Address register */
|
||||
#define INTEL_LPC_RCBA_REG 0xf0
|
||||
/* 31:14 RCBA address */
|
||||
#define INTEL_LPC_RCBA_MASK 0xffffc000
|
||||
/* RCBA Enable */
|
||||
#define INTEL_LPC_RCBA_ENABLE (1 << 0)
|
||||
|
||||
/* Backbone Scratch Pad Register */
|
||||
#define INTEL_BSPR_REG 0x1104
|
||||
/* Backbone Peer Non-Posted Disable */
|
||||
#define INTEL_BSPR_REG_BPNPD (1 << 8)
|
||||
/* Backbone Peer Posted Disable */
|
||||
#define INTEL_BSPR_REG_BPPD (1 << 9)
|
||||
|
||||
/* Upstream Peer Decode Configuration Register */
|
||||
#define INTEL_UPDCR_REG 0x1114
|
||||
/* 5:0 Peer Decode Enable bits */
|
||||
#define INTEL_UPDCR_REG_MASK 0x3f
|
||||
|
||||
static int pci_quirk_enable_intel_lpc_acs(struct pci_dev *dev)
|
||||
{
|
||||
u32 rcba, bspr, updcr;
|
||||
void __iomem *rcba_mem;
|
||||
|
||||
/*
|
||||
* Read the RCBA register from the LPC (D31:F0). PCH root ports
|
||||
* are D28:F* and therefore get probed before LPC, thus we can't
|
||||
* use pci_get_slot/pci_read_config_dword here.
|
||||
*/
|
||||
pci_bus_read_config_dword(dev->bus, PCI_DEVFN(31, 0),
|
||||
INTEL_LPC_RCBA_REG, &rcba);
|
||||
if (!(rcba & INTEL_LPC_RCBA_ENABLE))
|
||||
return -EINVAL;
|
||||
|
||||
rcba_mem = ioremap_nocache(rcba & INTEL_LPC_RCBA_MASK,
|
||||
PAGE_ALIGN(INTEL_UPDCR_REG));
|
||||
if (!rcba_mem)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* The BSPR can disallow peer cycles, but it's set by soft strap and
|
||||
* therefore read-only. If both posted and non-posted peer cycles are
|
||||
* disallowed, we're ok. If either are allowed, then we need to use
|
||||
* the UPDCR to disable peer decodes for each port. This provides the
|
||||
* PCIe ACS equivalent of PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF
|
||||
*/
|
||||
bspr = readl(rcba_mem + INTEL_BSPR_REG);
|
||||
bspr &= INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD;
|
||||
if (bspr != (INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD)) {
|
||||
updcr = readl(rcba_mem + INTEL_UPDCR_REG);
|
||||
if (updcr & INTEL_UPDCR_REG_MASK) {
|
||||
dev_info(&dev->dev, "Disabling UPDCR peer decodes\n");
|
||||
updcr &= ~INTEL_UPDCR_REG_MASK;
|
||||
writel(updcr, rcba_mem + INTEL_UPDCR_REG);
|
||||
}
|
||||
}
|
||||
|
||||
iounmap(rcba_mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Miscellaneous Port Configuration register */
|
||||
#define INTEL_MPC_REG 0xd8
|
||||
/* MPC: Invalid Receive Bus Number Check Enable */
|
||||
#define INTEL_MPC_REG_IRBNCE (1 << 26)
|
||||
|
||||
static void pci_quirk_enable_intel_rp_mpc_acs(struct pci_dev *dev)
|
||||
{
|
||||
u32 mpc;
|
||||
|
||||
/*
|
||||
* When enabled, the IRBNCE bit of the MPC register enables the
|
||||
* equivalent of PCI ACS Source Validation (PCI_ACS_SV), which
|
||||
* ensures that requester IDs fall within the bus number range
|
||||
* of the bridge. Enable if not already.
|
||||
*/
|
||||
pci_read_config_dword(dev, INTEL_MPC_REG, &mpc);
|
||||
if (!(mpc & INTEL_MPC_REG_IRBNCE)) {
|
||||
dev_info(&dev->dev, "Enabling MPC IRBNCE\n");
|
||||
mpc |= INTEL_MPC_REG_IRBNCE;
|
||||
pci_write_config_word(dev, INTEL_MPC_REG, mpc);
|
||||
}
|
||||
}
|
||||
|
||||
static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev)
|
||||
{
|
||||
if (!pci_quirk_intel_pch_acs_match(dev))
|
||||
return -ENOTTY;
|
||||
|
||||
if (pci_quirk_enable_intel_lpc_acs(dev)) {
|
||||
dev_warn(&dev->dev, "Failed to enable Intel PCH ACS quirk\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pci_quirk_enable_intel_rp_mpc_acs(dev);
|
||||
|
||||
dev->dev_flags |= PCI_DEV_FLAGS_ACS_ENABLED_QUIRK;
|
||||
|
||||
dev_info(&dev->dev, "Intel PCH root port ACS workaround enabled\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pci_dev_enable_acs {
|
||||
u16 vendor;
|
||||
u16 device;
|
||||
int (*enable_acs)(struct pci_dev *dev);
|
||||
} pci_dev_enable_acs[] = {
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_pch_acs },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
void pci_dev_specific_enable_acs(struct pci_dev *dev)
|
||||
{
|
||||
const struct pci_dev_enable_acs *i;
|
||||
int ret;
|
||||
|
||||
for (i = pci_dev_enable_acs; i->enable_acs; i++) {
|
||||
if ((i->vendor == dev->vendor ||
|
||||
i->vendor == (u16)PCI_ANY_ID) &&
|
||||
(i->device == dev->device ||
|
||||
i->device == (u16)PCI_ANY_ID)) {
|
||||
ret = i->enable_acs(dev);
|
||||
if (ret >= 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,6 +170,8 @@ enum pci_dev_flags {
|
|||
PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2,
|
||||
/* Provide indication device is assigned by a Virtual Machine Manager */
|
||||
PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4,
|
||||
/* Flag for quirk use to store if quirk-specific ACS is enabled */
|
||||
PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) 8,
|
||||
};
|
||||
|
||||
enum pci_irq_reroute_variant {
|
||||
|
@ -1510,6 +1512,7 @@ enum pci_fixup_pass {
|
|||
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
|
||||
struct pci_dev *pci_get_dma_source(struct pci_dev *dev);
|
||||
int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
|
||||
void pci_dev_specific_enable_acs(struct pci_dev *dev);
|
||||
#else
|
||||
static inline void pci_fixup_device(enum pci_fixup_pass pass,
|
||||
struct pci_dev *dev) { }
|
||||
|
@ -1522,6 +1525,7 @@ static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev,
|
|||
{
|
||||
return -ENOTTY;
|
||||
}
|
||||
static inline void pci_dev_specific_enable_acs(struct pci_dev *dev) { }
|
||||
#endif
|
||||
|
||||
void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
|
||||
|
|
Loading…
Reference in New Issue