mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-22 06:32:08 +00:00
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
8 changed files with 271 additions and 214 deletions
|
@ -207,6 +207,7 @@ config INTEL_IOMMU_SVM
|
||||||
bool "Support for Shared Virtual Memory with Intel IOMMU"
|
bool "Support for Shared Virtual Memory with Intel IOMMU"
|
||||||
depends on INTEL_IOMMU && X86
|
depends on INTEL_IOMMU && X86
|
||||||
select PCI_PASID
|
select PCI_PASID
|
||||||
|
select PCI_PRI
|
||||||
select MMU_NOTIFIER
|
select MMU_NOTIFIER
|
||||||
help
|
help
|
||||||
Shared Virtual Memory (SVM) provides a facility for devices
|
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);
|
pdev = pci_physfn(dev);
|
||||||
if (pdev->ats_stu != ps)
|
if (pdev->ats_stu != ps)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
atomic_inc(&pdev->ats_ref_cnt); /* count enabled VFs */
|
|
||||||
} else {
|
} else {
|
||||||
dev->ats_stu = ps;
|
dev->ats_stu = ps;
|
||||||
ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
|
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;
|
dev->ats_enabled = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_enable_ats);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_disable_ats - disable the ATS capability
|
* 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)
|
void pci_disable_ats(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
struct pci_dev *pdev;
|
|
||||||
u16 ctrl;
|
u16 ctrl;
|
||||||
|
|
||||||
if (WARN_ON(!dev->ats_enabled))
|
if (WARN_ON(!dev->ats_enabled))
|
||||||
return;
|
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);
|
pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, &ctrl);
|
||||||
ctrl &= ~PCI_ATS_CTRL_ENABLE;
|
ctrl &= ~PCI_ATS_CTRL_ENABLE;
|
||||||
pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
|
pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
|
||||||
|
|
||||||
dev->ats_enabled = 0;
|
dev->ats_enabled = 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_disable_ats);
|
|
||||||
|
|
||||||
void pci_restore_ats_state(struct pci_dev *dev)
|
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);
|
ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
|
||||||
pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
|
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
|
* 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);
|
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;
|
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.
|
* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_ats_page_aligned);
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_PRI
|
#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
|
* pci_enable_pri - Enable PRI capability
|
||||||
* @ pdev: PCI device structure
|
* @ pdev: PCI device structure
|
||||||
|
@ -180,32 +178,41 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
|
||||||
{
|
{
|
||||||
u16 control, status;
|
u16 control, status;
|
||||||
u32 max_requests;
|
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))
|
if (WARN_ON(pdev->pri_enabled))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
if (!pri)
|
||||||
if (!pos)
|
|
||||||
return -EINVAL;
|
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))
|
if (!(status & PCI_PRI_STATUS_STOPPED))
|
||||||
return -EBUSY;
|
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);
|
reqs = min(max_requests, reqs);
|
||||||
pdev->pri_reqs_alloc = 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;
|
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;
|
pdev->pri_enabled = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_enable_pri);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_disable_pri - Disable PRI capability
|
* pci_disable_pri - Disable PRI capability
|
||||||
|
@ -216,18 +223,21 @@ EXPORT_SYMBOL_GPL(pci_enable_pri);
|
||||||
void pci_disable_pri(struct pci_dev *pdev)
|
void pci_disable_pri(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
u16 control;
|
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))
|
if (WARN_ON(!pdev->pri_enabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
if (!pri)
|
||||||
if (!pos)
|
|
||||||
return;
|
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;
|
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;
|
pdev->pri_enabled = 0;
|
||||||
}
|
}
|
||||||
|
@ -241,19 +251,20 @@ void pci_restore_pri_state(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
u16 control = PCI_PRI_CTRL_ENABLE;
|
u16 control = PCI_PRI_CTRL_ENABLE;
|
||||||
u32 reqs = pdev->pri_reqs_alloc;
|
u32 reqs = pdev->pri_reqs_alloc;
|
||||||
int pos;
|
int pri = pdev->pri_cap;
|
||||||
|
|
||||||
|
if (pdev->is_virtfn)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!pdev->pri_enabled)
|
if (!pdev->pri_enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
if (!pri)
|
||||||
if (!pos)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ, reqs);
|
pci_write_config_dword(pdev, pri + PCI_PRI_ALLOC_REQ, reqs);
|
||||||
pci_write_config_word(pdev, pos + PCI_PRI_CTRL, control);
|
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
|
* 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)
|
int pci_reset_pri(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
u16 control;
|
u16 control;
|
||||||
int pos;
|
int pri = pdev->pri_cap;
|
||||||
|
|
||||||
|
if (pdev->is_virtfn)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (WARN_ON(pdev->pri_enabled))
|
if (WARN_ON(pdev->pri_enabled))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
if (!pri)
|
||||||
if (!pos)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
control = PCI_PRI_CTRL_RESET;
|
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;
|
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 */
|
#endif /* CONFIG_PCI_PRI */
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_PASID
|
#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
|
* pci_enable_pasid - Enable the PASID capability
|
||||||
* @pdev: PCI device structure
|
* @pdev: PCI device structure
|
||||||
|
@ -295,7 +327,17 @@ EXPORT_SYMBOL_GPL(pci_reset_pri);
|
||||||
int pci_enable_pasid(struct pci_dev *pdev, int features)
|
int pci_enable_pasid(struct pci_dev *pdev, int features)
|
||||||
{
|
{
|
||||||
u16 control, supported;
|
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))
|
if (WARN_ON(pdev->pasid_enabled))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
@ -303,11 +345,10 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
|
||||||
if (!pdev->eetlp_prefix_path)
|
if (!pdev->eetlp_prefix_path)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
if (!pasid)
|
||||||
if (!pos)
|
|
||||||
return -EINVAL;
|
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;
|
supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
|
||||||
|
|
||||||
/* User wants to enable anything unsupported? */
|
/* 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;
|
control = PCI_PASID_CTRL_ENABLE | features;
|
||||||
pdev->pasid_features = 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;
|
pdev->pasid_enabled = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_enable_pasid);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_disable_pasid - Disable the PASID capability
|
* 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)
|
void pci_disable_pasid(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
u16 control = 0;
|
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))
|
if (WARN_ON(!pdev->pasid_enabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
if (!pasid)
|
||||||
if (!pos)
|
|
||||||
return;
|
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;
|
pdev->pasid_enabled = 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_disable_pasid);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_restore_pasid_state - Restore PASID capabilities
|
* 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)
|
void pci_restore_pasid_state(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
u16 control;
|
u16 control;
|
||||||
int pos;
|
int pasid = pdev->pasid_cap;
|
||||||
|
|
||||||
|
if (pdev->is_virtfn)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!pdev->pasid_enabled)
|
if (!pdev->pasid_enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
if (!pasid)
|
||||||
if (!pos)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
control = PCI_PASID_CTRL_ENABLE | pdev->pasid_features;
|
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
|
* 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)
|
int pci_pasid_features(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
u16 supported;
|
u16 supported;
|
||||||
int pos;
|
int pasid = pdev->pasid_cap;
|
||||||
|
|
||||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
if (pdev->is_virtfn)
|
||||||
if (!pos)
|
pdev = pci_physfn(pdev);
|
||||||
|
|
||||||
|
if (!pasid)
|
||||||
return -EINVAL;
|
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;
|
supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
|
||||||
|
|
||||||
return supported;
|
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_SHIFT 8
|
||||||
#define PASID_NUMBER_MASK (0x1f << PASID_NUMBER_SHIFT)
|
#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)
|
int pci_max_pasids(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
u16 supported;
|
u16 supported;
|
||||||
int pos;
|
int pasid = pdev->pasid_cap;
|
||||||
|
|
||||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
if (pdev->is_virtfn)
|
||||||
if (!pos)
|
pdev = pci_physfn(pdev);
|
||||||
|
|
||||||
|
if (!pasid)
|
||||||
return -EINVAL;
|
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;
|
supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
|
||||||
|
|
||||||
return (1 << supported);
|
return (1 << supported);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_max_pasids);
|
|
||||||
#endif /* CONFIG_PCI_PASID */
|
#endif /* CONFIG_PCI_PASID */
|
||||||
|
|
|
@ -254,8 +254,14 @@ static ssize_t sriov_numvfs_show(struct device *dev,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
struct pci_dev *pdev = to_pci_dev(dev);
|
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) { }
|
static inline void pci_restore_ats_state(struct pci_dev *dev) { }
|
||||||
#endif /* CONFIG_PCI_ATS */
|
#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
|
#ifdef CONFIG_PCI_IOV
|
||||||
int pci_iov_init(struct pci_dev *dev);
|
int pci_iov_init(struct pci_dev *dev);
|
||||||
void pci_iov_release(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 */
|
/* Address Translation Services */
|
||||||
pci_ats_init(dev);
|
pci_ats_init(dev);
|
||||||
|
|
||||||
|
/* Page Request Interface */
|
||||||
|
pci_pri_init(dev);
|
||||||
|
|
||||||
|
/* Process Address Space ID */
|
||||||
|
pci_pasid_init(dev);
|
||||||
|
|
||||||
/* Enable ACS P2P upstream forwarding */
|
/* Enable ACS P2P upstream forwarding */
|
||||||
pci_enable_acs(dev);
|
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, 0x2260, quirk_mic_x200_dma_alias);
|
||||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, 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
|
* 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
|
* 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,
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
|
||||||
quirk_chelsio_T5_disable_root_port_attributes);
|
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
|
* 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
|
* 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 */
|
/* Filter out flags not applicable to multifunction */
|
||||||
acs_flags &= (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC | PCI_ACS_DT);
|
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
|
#else
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
#endif
|
#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)
|
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
|
* Effectively selects all downstream ports for whole ThunderX1
|
||||||
* family by 0xf800 mask (which represents 8 SoCs), while the lower
|
* (which represents 8 SoCs).
|
||||||
* bits of device ID are used to indicate which subdevice is used
|
|
||||||
* within the SoC.
|
|
||||||
*/
|
*/
|
||||||
return (pci_is_pcie(dev) &&
|
case 0xa000 ... 0xa7ff: /* ThunderX1 */
|
||||||
(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) &&
|
case 0xaf84: /* ThunderX2 */
|
||||||
((dev->device & 0xf800) == 0xa000));
|
case 0xb884: /* ThunderX3 */
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags)
|
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
|
* 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
|
* and Upstream Forwarding features enabled. Assert that the
|
||||||
* hardware implements and enables equivalent ACS functionality for
|
* hardware implements and enables equivalent ACS functionality for
|
||||||
* these flags.
|
* these flags.
|
||||||
*/
|
*/
|
||||||
acs_flags &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_SV | PCI_ACS_UF);
|
return pci_acs_ctrl_enabled(acs_flags,
|
||||||
|
PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
|
||||||
if (!pci_quirk_cavium_acs_match(dev))
|
|
||||||
return -ENOTTY;
|
|
||||||
|
|
||||||
return acs_flags ? 0 : 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags)
|
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
|
* transactions with others, allowing masking out these bits as if they
|
||||||
* were unimplemented in the ACS capability.
|
* were unimplemented in the ACS capability.
|
||||||
*/
|
*/
|
||||||
acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
|
return pci_acs_ctrl_enabled(acs_flags,
|
||||||
|
PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
|
||||||
return acs_flags ? 0 : 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
* 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
|
* 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.
|
* 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;
|
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)
|
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))
|
if (!pci_quirk_intel_pch_acs_match(dev))
|
||||||
return -ENOTTY;
|
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
|
* transactions and validate bus numbers in requests, but do not provide an
|
||||||
* actual PCIe ACS capability. Hardware supports source validation but it
|
* actual PCIe ACS capability. Hardware supports source validation but it
|
||||||
* will report the issue as Completer Abort instead of ACS Violation.
|
* 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
|
* 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
|
* Complex with unique segment numbers. It is not possible for one Root
|
||||||
* port to pass traffic to another root port. All PCIe transactions are
|
* Port to pass traffic to another Root Port. All PCIe transactions are
|
||||||
* terminated inside the root port.
|
* terminated inside the Root Port.
|
||||||
*/
|
*/
|
||||||
static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags)
|
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);
|
return pci_acs_ctrl_enabled(acs_flags,
|
||||||
int ret = acs_flags & ~flags ? 0 : 1;
|
PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
|
||||||
|
|
||||||
pci_info(dev, "Using QCOM ACS Quirk (%d)\n", ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pci_quirk_al_acs(struct pci_dev *dev, u16 acs_flags)
|
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);
|
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)
|
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
|
* perform peer-to-peer with other functions, allowing us to mask out
|
||||||
* these bits as if they were unimplemented in the ACS capability.
|
* these bits as if they were unimplemented in the ACS capability.
|
||||||
*/
|
*/
|
||||||
acs_flags &= ~(PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
|
return pci_acs_ctrl_enabled(acs_flags,
|
||||||
PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT);
|
PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
|
||||||
|
PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT);
|
||||||
return acs_flags ? 0 : 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags)
|
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
|
* Allow each Root Port to be in a separate IOMMU group by masking
|
||||||
* SV/RR/CR/UF bits.
|
* SV/RR/CR/UF bits.
|
||||||
*/
|
*/
|
||||||
acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
|
return pci_acs_ctrl_enabled(acs_flags,
|
||||||
|
PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
|
||||||
return acs_flags ? 0 : 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pci_dev_acs_enabled {
|
static const struct pci_dev_acs_enabled {
|
||||||
|
@ -4666,6 +4715,17 @@ static const struct pci_dev_acs_enabled {
|
||||||
{ 0 }
|
{ 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)
|
int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
|
||||||
{
|
{
|
||||||
const struct pci_dev_acs_enabled *i;
|
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)
|
#define INTEL_BSPR_REG_BPPD (1 << 9)
|
||||||
|
|
||||||
/* Upstream Peer Decode Configuration Register */
|
/* Upstream Peer Decode Configuration Register */
|
||||||
#define INTEL_UPDCR_REG 0x1114
|
#define INTEL_UPDCR_REG 0x1014
|
||||||
/* 5:0 Peer Decode Enable bits */
|
/* 5:0 Peer Decode Enable bits */
|
||||||
#define INTEL_UPDCR_REG_MASK 0x3f
|
#define INTEL_UPDCR_REG_MASK 0x3f
|
||||||
|
|
||||||
|
|
|
@ -4,74 +4,39 @@
|
||||||
|
|
||||||
#include <linux/pci.h>
|
#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);
|
int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
|
||||||
void pci_disable_pri(struct pci_dev *pdev);
|
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);
|
int pci_reset_pri(struct pci_dev *pdev);
|
||||||
|
int pci_prg_resp_pasid_required(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* CONFIG_PCI_PRI */
|
#endif /* CONFIG_PCI_PRI */
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_PASID
|
#ifdef CONFIG_PCI_PASID
|
||||||
|
|
||||||
int pci_enable_pasid(struct pci_dev *pdev, int features);
|
int pci_enable_pasid(struct pci_dev *pdev, int features);
|
||||||
void pci_disable_pasid(struct pci_dev *pdev);
|
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_pasid_features(struct pci_dev *pdev);
|
||||||
int pci_max_pasids(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 */
|
||||||
|
|
||||||
#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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int pci_pasid_features(struct pci_dev *pdev)
|
static inline int pci_pasid_features(struct pci_dev *pdev)
|
||||||
{
|
{ return -EINVAL; }
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int pci_max_pasids(struct pci_dev *pdev)
|
static inline int pci_max_pasids(struct pci_dev *pdev)
|
||||||
{
|
{ return -EINVAL; }
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int pci_prg_resp_pasid_required(struct pci_dev *pdev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_PCI_PASID */
|
#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 pcie_link_state;
|
||||||
struct pci_vpd;
|
struct pci_vpd;
|
||||||
struct pci_sriov;
|
struct pci_sriov;
|
||||||
struct pci_ats;
|
|
||||||
struct pci_p2pdma;
|
struct pci_p2pdma;
|
||||||
|
|
||||||
/* The pci_dev structure describes PCI devices */
|
/* The pci_dev structure describes PCI devices */
|
||||||
|
@ -452,12 +451,14 @@ struct pci_dev {
|
||||||
};
|
};
|
||||||
u16 ats_cap; /* ATS Capability offset */
|
u16 ats_cap; /* ATS Capability offset */
|
||||||
u8 ats_stu; /* ATS Smallest Translation Unit */
|
u8 ats_stu; /* ATS Smallest Translation Unit */
|
||||||
atomic_t ats_ref_cnt; /* Number of VFs with ATS enabled */
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_PCI_PRI
|
#ifdef CONFIG_PCI_PRI
|
||||||
|
u16 pri_cap; /* PRI Capability offset */
|
||||||
u32 pri_reqs_alloc; /* Number of PRI requests allocated */
|
u32 pri_reqs_alloc; /* Number of PRI requests allocated */
|
||||||
|
unsigned int pasid_required:1; /* PRG Response PASID Required */
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_PCI_PASID
|
#ifdef CONFIG_PCI_PASID
|
||||||
|
u16 pasid_cap; /* PASID Capability offset */
|
||||||
u16 pasid_features;
|
u16 pasid_features;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_PCI_P2PDMA
|
#ifdef CONFIG_PCI_P2PDMA
|
||||||
|
@ -1770,19 +1771,6 @@ pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
|
||||||
NULL);
|
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 architecture-dependent settings and functions */
|
||||||
|
|
||||||
#include <asm/pci.h>
|
#include <asm/pci.h>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue