mirror of https://gitee.com/openkylin/linux.git
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:
commit
f52412b151
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue