Merge branch 'pci/virtualization'

- Fix erroneous intel-iommu dependency on CONFIG_AMD_IOMMU (Bjorn
    Helgaas)

  - Move pci_prg_resp_pasid_required() to CONFIG_PCI_PRI (Bjorn Helgaas)

  - Allow VFs to use PRI (the PF PRI is shared by the VFs, but the code
    previously didn't recognize that) (Kuppuswamy Sathyanarayanan)

  - Allow VFs to use PASID (the PF PASID capability is shared by the VFs,
    but the code previously didn't recognize that) (Kuppuswamy
    Sathyanarayanan)

  - Disconnect PF and VF ATS enablement, since ATS in PFs and associated
    VFs can be enabled independently (Kuppuswamy Sathyanarayanan)

  - Cache PRI and PASID capability offsets (Kuppuswamy Sathyanarayanan)

  - Cache the PRI PRG Response PASID Required bit (Bjorn Helgaas)

  - Consolidate ATS declarations in linux/pci-ats.h (Krzysztof Wilczynski)

  - Remove unused PRI and PASID stubs (Bjorn Helgaas)

  - Removed unnecessary EXPORT_SYMBOL_GPL() from ATS, PRI, and PASID
    interfaces that are only used by built-in IOMMU drivers (Bjorn Helgaas)

  - Hide PRI and PASID state restoration functions used only inside the PCI
    core (Bjorn Helgaas)

  - Fix the UPDCR register address in the Intel ACS quirk (Steffen
    Liebergeld)

  - Add a DMA alias quirk for the Intel VCA NTB (Slawomir Pawlowski)

  - Serialize sysfs sriov_numvfs reads vs writes (Pierre Crégut)

  - Update Cavium ACS quirk for ThunderX2 and ThunderX3 (George Cherian)

  - Unify ACS quirk implementations (Bjorn Helgaas)

* pci/virtualization:
  PCI: Unify ACS quirk desired vs provided checking
  PCI: Make ACS quirk implementations more uniform
  PCI: Apply Cavium ACS quirk to ThunderX2 and ThunderX3
  PCI/IOV: Serialize sysfs sriov_numvfs reads vs writes
  PCI: Add DMA alias quirk for Intel VCA NTB
  PCI: Fix Intel ACS quirk UPDCR register address
  PCI/ATS: Make pci_restore_pri_state(), pci_restore_pasid_state() private
  PCI/ATS: Remove unnecessary EXPORT_SYMBOL_GPL()
  PCI/ATS: Remove unused PRI and PASID stubs
  PCI/ATS: Consolidate ATS declarations in linux/pci-ats.h
  PCI/ATS: Cache PRI PRG Response PASID Required bit
  PCI/ATS: Cache PASID Capability offset
  PCI/ATS: Cache PRI Capability offset
  PCI/ATS: Disable PF/VF ATS service independently
  PCI/ATS: Handle sharing of PF PASID Capability with all VFs
  PCI/ATS: Handle sharing of PF PRI Capability with all VFs
  PCI/ATS: Move pci_prg_resp_pasid_required() to CONFIG_PCI_PRI
  iommu/vt-d: Select PCI_PRI for INTEL_IOMMU_SVM
This commit is contained in:
Bjorn Helgaas 2019-11-28 08:54:38 -06:00
commit f52412b151
8 changed files with 271 additions and 214 deletions

View File

@ -207,6 +207,7 @@ config INTEL_IOMMU_SVM
bool "Support for Shared Virtual Memory with Intel IOMMU"
depends on INTEL_IOMMU && X86
select PCI_PASID
select PCI_PRI
select MMU_NOTIFIER
help
Shared Virtual Memory (SVM) provides a facility for devices

View File

@ -60,8 +60,6 @@ int pci_enable_ats(struct pci_dev *dev, int ps)
pdev = pci_physfn(dev);
if (pdev->ats_stu != ps)
return -EINVAL;
atomic_inc(&pdev->ats_ref_cnt); /* count enabled VFs */
} else {
dev->ats_stu = ps;
ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
@ -71,7 +69,6 @@ int pci_enable_ats(struct pci_dev *dev, int ps)
dev->ats_enabled = 1;
return 0;
}
EXPORT_SYMBOL_GPL(pci_enable_ats);
/**
* pci_disable_ats - disable the ATS capability
@ -79,27 +76,17 @@ EXPORT_SYMBOL_GPL(pci_enable_ats);
*/
void pci_disable_ats(struct pci_dev *dev)
{
struct pci_dev *pdev;
u16 ctrl;
if (WARN_ON(!dev->ats_enabled))
return;
if (atomic_read(&dev->ats_ref_cnt))
return; /* VFs still enabled */
if (dev->is_virtfn) {
pdev = pci_physfn(dev);
atomic_dec(&pdev->ats_ref_cnt);
}
pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, &ctrl);
ctrl &= ~PCI_ATS_CTRL_ENABLE;
pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
dev->ats_enabled = 0;
}
EXPORT_SYMBOL_GPL(pci_disable_ats);
void pci_restore_ats_state(struct pci_dev *dev)
{
@ -113,7 +100,6 @@ void pci_restore_ats_state(struct pci_dev *dev)
ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
}
EXPORT_SYMBOL_GPL(pci_restore_ats_state);
/**
* pci_ats_queue_depth - query the ATS Invalidate Queue Depth
@ -140,7 +126,6 @@ int pci_ats_queue_depth(struct pci_dev *dev)
pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CAP, &cap);
return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : PCI_ATS_MAX_QDEP;
}
EXPORT_SYMBOL_GPL(pci_ats_queue_depth);
/**
* pci_ats_page_aligned - Return Page Aligned Request bit status.
@ -167,9 +152,22 @@ int pci_ats_page_aligned(struct pci_dev *pdev)
return 0;
}
EXPORT_SYMBOL_GPL(pci_ats_page_aligned);
#ifdef CONFIG_PCI_PRI
void pci_pri_init(struct pci_dev *pdev)
{
u16 status;
pdev->pri_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pdev->pri_cap)
return;
pci_read_config_word(pdev, pdev->pri_cap + PCI_PRI_STATUS, &status);
if (status & PCI_PRI_STATUS_PASID)
pdev->pasid_required = 1;
}
/**
* pci_enable_pri - Enable PRI capability
* @ pdev: PCI device structure
@ -180,32 +178,41 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
{
u16 control, status;
u32 max_requests;
int pos;
int pri = pdev->pri_cap;
/*
* VFs must not implement the PRI Capability. If their PF
* implements PRI, it is shared by the VFs, so if the PF PRI is
* enabled, it is also enabled for the VF.
*/
if (pdev->is_virtfn) {
if (pci_physfn(pdev)->pri_enabled)
return 0;
return -EINVAL;
}
if (WARN_ON(pdev->pri_enabled))
return -EBUSY;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos)
if (!pri)
return -EINVAL;
pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
pci_read_config_word(pdev, pri + PCI_PRI_STATUS, &status);
if (!(status & PCI_PRI_STATUS_STOPPED))
return -EBUSY;
pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ, &max_requests);
pci_read_config_dword(pdev, pri + PCI_PRI_MAX_REQ, &max_requests);
reqs = min(max_requests, reqs);
pdev->pri_reqs_alloc = reqs;
pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
pci_write_config_dword(pdev, pri + PCI_PRI_ALLOC_REQ, reqs);
control = PCI_PRI_CTRL_ENABLE;
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
pdev->pri_enabled = 1;
return 0;
}
EXPORT_SYMBOL_GPL(pci_enable_pri);
/**
* pci_disable_pri - Disable PRI capability
@ -216,18 +223,21 @@ EXPORT_SYMBOL_GPL(pci_enable_pri);
void pci_disable_pri(struct pci_dev *pdev)
{
u16 control;
int pos;
int pri = pdev->pri_cap;
/* VFs share the PF PRI */
if (pdev->is_virtfn)
return;
if (WARN_ON(!pdev->pri_enabled))
return;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos)
if (!pri)
return;
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
pci_read_config_word(pdev, pri + PCI_PRI_CTRL, &control);
control &= ~PCI_PRI_CTRL_ENABLE;
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
pdev->pri_enabled = 0;
}
@ -241,19 +251,20 @@ void pci_restore_pri_state(struct pci_dev *pdev)
{
u16 control = PCI_PRI_CTRL_ENABLE;
u32 reqs = pdev->pri_reqs_alloc;
int pos;
int pri = pdev->pri_cap;
if (pdev->is_virtfn)
return;
if (!pdev->pri_enabled)
return;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos)
if (!pri)
return;
pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
pci_write_config_dword(pdev, pri + PCI_PRI_ALLOC_REQ, reqs);
pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
}
EXPORT_SYMBOL_GPL(pci_restore_pri_state);
/**
* pci_reset_pri - Resets device's PRI state
@ -265,24 +276,45 @@ EXPORT_SYMBOL_GPL(pci_restore_pri_state);
int pci_reset_pri(struct pci_dev *pdev)
{
u16 control;
int pos;
int pri = pdev->pri_cap;
if (pdev->is_virtfn)
return 0;
if (WARN_ON(pdev->pri_enabled))
return -EBUSY;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos)
if (!pri)
return -EINVAL;
control = PCI_PRI_CTRL_RESET;
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
return 0;
}
EXPORT_SYMBOL_GPL(pci_reset_pri);
/**
* pci_prg_resp_pasid_required - Return PRG Response PASID Required bit
* status.
* @pdev: PCI device structure
*
* Returns 1 if PASID is required in PRG Response Message, 0 otherwise.
*/
int pci_prg_resp_pasid_required(struct pci_dev *pdev)
{
if (pdev->is_virtfn)
pdev = pci_physfn(pdev);
return pdev->pasid_required;
}
#endif /* CONFIG_PCI_PRI */
#ifdef CONFIG_PCI_PASID
void pci_pasid_init(struct pci_dev *pdev)
{
pdev->pasid_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
}
/**
* pci_enable_pasid - Enable the PASID capability
* @pdev: PCI device structure
@ -295,7 +327,17 @@ EXPORT_SYMBOL_GPL(pci_reset_pri);
int pci_enable_pasid(struct pci_dev *pdev, int features)
{
u16 control, supported;
int pos;
int pasid = pdev->pasid_cap;
/*
* VFs must not implement the PASID Capability, but if a PF
* supports PASID, its VFs share the PF PASID configuration.
*/
if (pdev->is_virtfn) {
if (pci_physfn(pdev)->pasid_enabled)
return 0;
return -EINVAL;
}
if (WARN_ON(pdev->pasid_enabled))
return -EBUSY;
@ -303,11 +345,10 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
if (!pdev->eetlp_prefix_path)
return -EINVAL;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
if (!pos)
if (!pasid)
return -EINVAL;
pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
/* User wants to enable anything unsupported? */
@ -317,13 +358,12 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
control = PCI_PASID_CTRL_ENABLE | features;
pdev->pasid_features = features;
pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
pdev->pasid_enabled = 1;
return 0;
}
EXPORT_SYMBOL_GPL(pci_enable_pasid);
/**
* pci_disable_pasid - Disable the PASID capability
@ -332,20 +372,22 @@ EXPORT_SYMBOL_GPL(pci_enable_pasid);
void pci_disable_pasid(struct pci_dev *pdev)
{
u16 control = 0;
int pos;
int pasid = pdev->pasid_cap;
/* VFs share the PF PASID configuration */
if (pdev->is_virtfn)
return;
if (WARN_ON(!pdev->pasid_enabled))
return;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
if (!pos)
if (!pasid)
return;
pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
pdev->pasid_enabled = 0;
}
EXPORT_SYMBOL_GPL(pci_disable_pasid);
/**
* pci_restore_pasid_state - Restore PASID capabilities
@ -354,19 +396,20 @@ EXPORT_SYMBOL_GPL(pci_disable_pasid);
void pci_restore_pasid_state(struct pci_dev *pdev)
{
u16 control;
int pos;
int pasid = pdev->pasid_cap;
if (pdev->is_virtfn)
return;
if (!pdev->pasid_enabled)
return;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
if (!pos)
if (!pasid)
return;
control = PCI_PASID_CTRL_ENABLE | pdev->pasid_features;
pci_write_config_word(pdev, pos + PCI_PASID_CTRL, control);
pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
}
EXPORT_SYMBOL_GPL(pci_restore_pasid_state);
/**
* pci_pasid_features - Check which PASID features are supported
@ -381,49 +424,20 @@ EXPORT_SYMBOL_GPL(pci_restore_pasid_state);
int pci_pasid_features(struct pci_dev *pdev)
{
u16 supported;
int pos;
int pasid = pdev->pasid_cap;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
if (!pos)
if (pdev->is_virtfn)
pdev = pci_physfn(pdev);
if (!pasid)
return -EINVAL;
pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
return supported;
}
EXPORT_SYMBOL_GPL(pci_pasid_features);
/**
* pci_prg_resp_pasid_required - Return PRG Response PASID Required bit
* status.
* @pdev: PCI device structure
*
* Returns 1 if PASID is required in PRG Response Message, 0 otherwise.
*
* Even though the PRG response PASID status is read from PRI Status
* Register, since this API will mainly be used by PASID users, this
* function is defined within #ifdef CONFIG_PCI_PASID instead of
* CONFIG_PCI_PRI.
*/
int pci_prg_resp_pasid_required(struct pci_dev *pdev)
{
u16 status;
int pos;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos)
return 0;
pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
if (status & PCI_PRI_STATUS_PASID)
return 1;
return 0;
}
EXPORT_SYMBOL_GPL(pci_prg_resp_pasid_required);
#define PASID_NUMBER_SHIFT 8
#define PASID_NUMBER_MASK (0x1f << PASID_NUMBER_SHIFT)
@ -437,17 +451,18 @@ EXPORT_SYMBOL_GPL(pci_prg_resp_pasid_required);
int pci_max_pasids(struct pci_dev *pdev)
{
u16 supported;
int pos;
int pasid = pdev->pasid_cap;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
if (!pos)
if (pdev->is_virtfn)
pdev = pci_physfn(pdev);
if (!pasid)
return -EINVAL;
pci_read_config_word(pdev, pos + PCI_PASID_CAP, &supported);
pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
return (1 << supported);
}
EXPORT_SYMBOL_GPL(pci_max_pasids);
#endif /* CONFIG_PCI_PASID */

View File

@ -254,8 +254,14 @@ static ssize_t sriov_numvfs_show(struct device *dev,
char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
u16 num_vfs;
return sprintf(buf, "%u\n", pdev->sriov->num_VFs);
/* Serialize vs sriov_numvfs_store() so readers see valid num_VFs */
device_lock(&pdev->dev);
num_vfs = pdev->sriov->num_VFs;
device_unlock(&pdev->dev);
return sprintf(buf, "%u\n", num_vfs);
}
/*

View File

@ -459,6 +459,22 @@ static inline void pci_ats_init(struct pci_dev *d) { }
static inline void pci_restore_ats_state(struct pci_dev *dev) { }
#endif /* CONFIG_PCI_ATS */
#ifdef CONFIG_PCI_PRI
void pci_pri_init(struct pci_dev *dev);
void pci_restore_pri_state(struct pci_dev *pdev);
#else
static inline void pci_pri_init(struct pci_dev *dev) { }
static inline void pci_restore_pri_state(struct pci_dev *pdev) { }
#endif
#ifdef CONFIG_PCI_PASID
void pci_pasid_init(struct pci_dev *dev);
void pci_restore_pasid_state(struct pci_dev *pdev);
#else
static inline void pci_pasid_init(struct pci_dev *dev) { }
static inline void pci_restore_pasid_state(struct pci_dev *pdev) { }
#endif
#ifdef CONFIG_PCI_IOV
int pci_iov_init(struct pci_dev *dev);
void pci_iov_release(struct pci_dev *dev);

View File

@ -2335,6 +2335,12 @@ static void pci_init_capabilities(struct pci_dev *dev)
/* Address Translation Services */
pci_ats_init(dev);
/* Page Request Interface */
pci_pri_init(dev);
/* Process Address Space ID */
pci_pasid_init(dev);
/* Enable ACS P2P upstream forwarding */
pci_enable_acs(dev);

View File

@ -4080,6 +4080,40 @@ static void quirk_mic_x200_dma_alias(struct pci_dev *pdev)
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
@ -4262,6 +4296,24 @@ static void quirk_chelsio_T5_disable_root_port_attributes(struct pci_dev *pdev)
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
@ -4305,7 +4357,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 +4365,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 +4406,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 +4459,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 +4585,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 +4599,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 +4612,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 +4715,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 +4766,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

View File

@ -4,74 +4,39 @@
#include <linux/pci.h>
#ifdef CONFIG_PCI_PRI
#ifdef CONFIG_PCI_ATS
/* Address Translation Service */
int pci_enable_ats(struct pci_dev *dev, int ps);
void pci_disable_ats(struct pci_dev *dev);
int pci_ats_queue_depth(struct pci_dev *dev);
int pci_ats_page_aligned(struct pci_dev *dev);
#else /* CONFIG_PCI_ATS */
static inline int pci_enable_ats(struct pci_dev *d, int ps)
{ return -ENODEV; }
static inline void pci_disable_ats(struct pci_dev *d) { }
static inline int pci_ats_queue_depth(struct pci_dev *d)
{ return -ENODEV; }
static inline int pci_ats_page_aligned(struct pci_dev *dev)
{ return 0; }
#endif /* CONFIG_PCI_ATS */
#ifdef CONFIG_PCI_PRI
int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
void pci_disable_pri(struct pci_dev *pdev);
void pci_restore_pri_state(struct pci_dev *pdev);
int pci_reset_pri(struct pci_dev *pdev);
#else /* CONFIG_PCI_PRI */
static inline int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
{
return -ENODEV;
}
static inline void pci_disable_pri(struct pci_dev *pdev)
{
}
static inline void pci_restore_pri_state(struct pci_dev *pdev)
{
}
static inline int pci_reset_pri(struct pci_dev *pdev)
{
return -ENODEV;
}
int pci_prg_resp_pasid_required(struct pci_dev *pdev);
#endif /* CONFIG_PCI_PRI */
#ifdef CONFIG_PCI_PASID
int pci_enable_pasid(struct pci_dev *pdev, int features);
void pci_disable_pasid(struct pci_dev *pdev);
void pci_restore_pasid_state(struct pci_dev *pdev);
int pci_pasid_features(struct pci_dev *pdev);
int pci_max_pasids(struct pci_dev *pdev);
int pci_prg_resp_pasid_required(struct pci_dev *pdev);
#else /* CONFIG_PCI_PASID */
static inline int pci_enable_pasid(struct pci_dev *pdev, int features)
{
return -EINVAL;
}
static inline void pci_disable_pasid(struct pci_dev *pdev)
{
}
static inline void pci_restore_pasid_state(struct pci_dev *pdev)
{
}
#else /* CONFIG_PCI_PASID */
static inline int pci_pasid_features(struct pci_dev *pdev)
{
return -EINVAL;
}
{ return -EINVAL; }
static inline int pci_max_pasids(struct pci_dev *pdev)
{
return -EINVAL;
}
static inline int pci_prg_resp_pasid_required(struct pci_dev *pdev)
{
return 0;
}
{ return -EINVAL; }
#endif /* CONFIG_PCI_PASID */
#endif /* LINUX_PCI_ATS_H*/
#endif /* LINUX_PCI_ATS_H */

View File

@ -284,7 +284,6 @@ struct irq_affinity;
struct pcie_link_state;
struct pci_vpd;
struct pci_sriov;
struct pci_ats;
struct pci_p2pdma;
/* The pci_dev structure describes PCI devices */
@ -452,12 +451,14 @@ struct pci_dev {
};
u16 ats_cap; /* ATS Capability offset */
u8 ats_stu; /* ATS Smallest Translation Unit */
atomic_t ats_ref_cnt; /* Number of VFs with ATS enabled */
#endif
#ifdef CONFIG_PCI_PRI
u16 pri_cap; /* PRI Capability offset */
u32 pri_reqs_alloc; /* Number of PRI requests allocated */
unsigned int pasid_required:1; /* PRG Response PASID Required */
#endif
#ifdef CONFIG_PCI_PASID
u16 pasid_cap; /* PASID Capability offset */
u16 pasid_features;
#endif
#ifdef CONFIG_PCI_P2PDMA
@ -1770,19 +1771,6 @@ pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
NULL);
}
#ifdef CONFIG_PCI_ATS
/* Address Translation Service */
int pci_enable_ats(struct pci_dev *dev, int ps);
void pci_disable_ats(struct pci_dev *dev);
int pci_ats_queue_depth(struct pci_dev *dev);
int pci_ats_page_aligned(struct pci_dev *dev);
#else
static inline int pci_enable_ats(struct pci_dev *d, int ps) { return -ENODEV; }
static inline void pci_disable_ats(struct pci_dev *d) { }
static inline int pci_ats_queue_depth(struct pci_dev *d) { return -ENODEV; }
static inline int pci_ats_page_aligned(struct pci_dev *dev) { return 0; }
#endif
/* Include architecture-dependent settings and functions */
#include <asm/pci.h>