From 8cbb8a9374a271099bacdc890fb16d374261332b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 9 Oct 2019 14:54:01 -0500 Subject: PCI/ATS: Move pci_prg_resp_pasid_required() to CONFIG_PCI_PRI pci_prg_resp_pasid_required() returns the value of the "PRG Response PASID Required" bit from the PRI capability, but the interface was previously defined under #ifdef CONFIG_PCI_PASID. Move it from CONFIG_PCI_PASID to CONFIG_PCI_PRI so it's with the other PRI-related things. Signed-off-by: Bjorn Helgaas Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Joerg Roedel --- drivers/pci/ats.c | 55 +++++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 30 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index e18499243f84..0d06177252c7 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -280,6 +280,31 @@ int pci_reset_pri(struct pci_dev *pdev) 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) +{ + 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); #endif /* CONFIG_PCI_PRI */ #ifdef CONFIG_PCI_PASID @@ -395,36 +420,6 @@ int pci_pasid_features(struct pci_dev *pdev) } 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) /** -- cgit From 9bf49e36d7183a170a9906d19acc5254818fc574 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Thu, 5 Sep 2019 14:31:42 -0500 Subject: PCI/ATS: Handle sharing of PF PRI Capability with all VFs Per PCIe r5.0, sec 9.3.7.11, VFs must not implement the PRI Capability. If the PF implements PRI, it is shared by the VFs. Since VFs don't have a PRI Capability, pci_enable_pri() always failed, which caused IOMMU setup to fail. Update the PRI interfaces so for VFs they reflect the state of the PF PRI. [bhelgaas: rebase without pri_cap caching, commit log] Suggested-by: Ashok Raj Link: https://lore.kernel.org/r/b971e31f8695980da8e4a7f93e3b6a3edba3edaa.1567029860.git.sathyanarayanan.kuppuswamy@linux.intel.com Link: https://lore.kernel.org/r/20190905193146.90250-2-helgaas@kernel.org Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Bjorn Helgaas Cc: Ashok Raj Cc: Keith Busch --- drivers/pci/ats.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index 0d06177252c7..b0f68c0ea91e 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -182,6 +182,17 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs) u32 max_requests; int pos; + /* + * 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; @@ -218,6 +229,10 @@ void pci_disable_pri(struct pci_dev *pdev) u16 control; int pos; + /* VFs share the PF PRI */ + if (pdev->is_virtfn) + return; + if (WARN_ON(!pdev->pri_enabled)) return; @@ -243,6 +258,9 @@ void pci_restore_pri_state(struct pci_dev *pdev) u32 reqs = pdev->pri_reqs_alloc; int pos; + if (pdev->is_virtfn) + return; + if (!pdev->pri_enabled) return; @@ -267,6 +285,9 @@ int pci_reset_pri(struct pci_dev *pdev) u16 control; int pos; + if (pdev->is_virtfn) + return 0; + if (WARN_ON(pdev->pri_enabled)) return -EBUSY; @@ -293,6 +314,9 @@ int pci_prg_resp_pasid_required(struct pci_dev *pdev) u16 status; int pos; + if (pdev->is_virtfn) + pdev = pci_physfn(pdev); + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); if (!pos) return 0; -- cgit From 2b0ae7cc3bfc3fae124c25870f41291c670b4549 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Thu, 5 Sep 2019 14:31:43 -0500 Subject: PCI/ATS: Handle sharing of PF PASID Capability with all VFs Per PCIe r5.0, sec 9.3.7.14, if a PF implements the PASID Capability, the PF PASID configuration is shared by its VFs. VFs must not implement their own PASID Capability. Since VFs don't have a PASID Capability, pci_enable_pasid() always failed, which caused IOMMU setup to fail. Update the PASID interfaces so for VFs they reflect the state of the PF PASID. [bhelgaas: rebase without pasid_cap caching, commit log] Suggested-by: Ashok Raj Link: https://lore.kernel.org/r/8ba1ac192e4ac737508b6ac15002158e176bab91.1567029860.git.sathyanarayanan.kuppuswamy@linux.intel.com Link: https://lore.kernel.org/r/20190905193146.90250-3-helgaas@kernel.org Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Bjorn Helgaas Cc: Ashok Raj Cc: Keith Busch --- drivers/pci/ats.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index b0f68c0ea91e..fb5cfd27dd3c 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -346,6 +346,16 @@ int pci_enable_pasid(struct pci_dev *pdev, int features) u16 control, supported; int pos; + /* + * 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; @@ -383,6 +393,10 @@ void pci_disable_pasid(struct pci_dev *pdev) u16 control = 0; int pos; + /* VFs share the PF PASID configuration */ + if (pdev->is_virtfn) + return; + if (WARN_ON(!pdev->pasid_enabled)) return; @@ -405,6 +419,9 @@ void pci_restore_pasid_state(struct pci_dev *pdev) u16 control; int pos; + if (pdev->is_virtfn) + return; + if (!pdev->pasid_enabled) return; @@ -432,6 +449,9 @@ int pci_pasid_features(struct pci_dev *pdev) u16 supported; int pos; + if (pdev->is_virtfn) + pdev = pci_physfn(pdev); + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); if (!pos) return -EINVAL; @@ -458,6 +478,9 @@ int pci_max_pasids(struct pci_dev *pdev) u16 supported; int pos; + if (pdev->is_virtfn) + pdev = pci_physfn(pdev); + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID); if (!pos) return -EINVAL; -- cgit From 3ad62192097443e8c3a8e244475bacaecb894d4e Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Thu, 5 Sep 2019 14:31:44 -0500 Subject: PCI/ATS: Disable PF/VF ATS service independently Previously we didn't disable the PF ATS until all associated VFs had disabled it. But per PCIe spec r5.0, sec 9.3.7.8, the ATS Capability in VFs and associated PFs may be enabled independently. Leaving ATS enabled in the PF unnecessarily may have power and performance impacts. Remove this dependency logic in the ATS enable/disable code. [bhelgaas: commit log] Suggested-by: Ashok Raj Link: https://lore.kernel.org/r/8163ab8fa66afd2cba514ae95d29ab12104781aa.1567029860.git.sathyanarayanan.kuppuswamy@linux.intel.com Link: https://lore.kernel.org/r/20190905193146.90250-4-helgaas@kernel.org Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Bjorn Helgaas Cc: Ashok Raj Cc: Keith Busch --- drivers/pci/ats.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index fb5cfd27dd3c..a708ed4146ca 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -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); @@ -79,20 +77,11 @@ 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); -- cgit From c065190bbcd4fb54ce9c5fd34fcad71acf2a0ea4 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Thu, 5 Sep 2019 14:31:45 -0500 Subject: PCI/ATS: Cache PRI Capability offset Previously each PRI interface searched for the PRI Capability. Cache the capability offset the first time we use it instead of searching each time. [bhelgaas: commit log, reorder patch to later, call pci_pri_init() from pci_init_capabilities()] Link: https://lore.kernel.org/r/0c5495d376faf6dbb8eb2165204c474438aaae65.156 7029860.git.sathyanarayanan.kuppuswamy@linux.intel.com Link: https://lore.kernel.org/r/20190905193146.90250-5-helgaas@kernel.org Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Bjorn Helgaas --- drivers/pci/ats.c | 51 ++++++++++++++++++++++++++------------------------- drivers/pci/pci.h | 6 ++++++ drivers/pci/probe.c | 3 +++ 3 files changed, 35 insertions(+), 25 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index a708ed4146ca..c97e862b538a 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -159,6 +159,11 @@ int pci_ats_page_aligned(struct pci_dev *pdev) EXPORT_SYMBOL_GPL(pci_ats_page_aligned); #ifdef CONFIG_PCI_PRI +void pci_pri_init(struct pci_dev *pdev) +{ + pdev->pri_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); +} + /** * pci_enable_pri - Enable PRI capability * @ pdev: PCI device structure @@ -169,7 +174,7 @@ 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 @@ -185,21 +190,20 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs) 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; @@ -216,7 +220,7 @@ 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) @@ -225,13 +229,12 @@ void pci_disable_pri(struct pci_dev *pdev) 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; } @@ -245,7 +248,7 @@ 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; @@ -253,12 +256,11 @@ void pci_restore_pri_state(struct pci_dev *pdev) 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); @@ -272,7 +274,7 @@ 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; @@ -280,12 +282,11 @@ int pci_reset_pri(struct pci_dev *pdev) 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; } @@ -301,16 +302,16 @@ EXPORT_SYMBOL_GPL(pci_reset_pri); int pci_prg_resp_pasid_required(struct pci_dev *pdev) { u16 status; - int pos; + int pri; if (pdev->is_virtfn) pdev = pci_physfn(pdev); - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); - if (!pos) + pri = pdev->pri_cap; + if (!pri) return 0; - 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_PASID) return 1; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 3f6947ee3324..aa08cd35bf87 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -456,6 +456,12 @@ 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); +#else +static inline void pci_pri_init(struct pci_dev *dev) { } +#endif + #ifdef CONFIG_PCI_IOV int pci_iov_init(struct pci_dev *dev); void pci_iov_release(struct pci_dev *dev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 3d5271a7a849..d145165c799c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2324,6 +2324,9 @@ static void pci_init_capabilities(struct pci_dev *dev) /* Address Translation Services */ pci_ats_init(dev); + /* Page Request Interface */ + pci_pri_init(dev); + /* Enable ACS P2P upstream forwarding */ pci_enable_acs(dev); -- cgit From 751035b8dc061ae434c3311bac9cd6d0e5e00f94 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Thu, 5 Sep 2019 14:31:46 -0500 Subject: PCI/ATS: Cache PASID Capability offset Previously each PASID interface searched for the PASID Capability. Cache the capability offset the first time we use it instead of searching each time. [bhelgaas: commit log, reorder patch to later, call pci_pasid_init() from pci_init_capabilities()] Link: https://lore.kernel.org/r/4957778959fa34eab3e8b3065d1951989c61cb0f.1567029860.git.sathyanarayanan.kuppuswamy@linux.intel.com Link: https://lore.kernel.org/r/20190905193146.90250-6-helgaas@kernel.org Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Bjorn Helgaas --- drivers/pci/ats.c | 42 +++++++++++++++++++++--------------------- drivers/pci/pci.h | 6 ++++++ drivers/pci/probe.c | 3 +++ 3 files changed, 30 insertions(+), 21 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index c97e862b538a..d5ac808cae21 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -322,6 +322,11 @@ EXPORT_SYMBOL_GPL(pci_prg_resp_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 @@ -334,7 +339,7 @@ EXPORT_SYMBOL_GPL(pci_prg_resp_pasid_required); 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 @@ -352,11 +357,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? */ @@ -366,7 +370,7 @@ 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; @@ -381,7 +385,7 @@ 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) @@ -390,11 +394,10 @@ void pci_disable_pasid(struct pci_dev *pdev) 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; } @@ -407,7 +410,7 @@ 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; @@ -415,12 +418,11 @@ void pci_restore_pasid_state(struct pci_dev *pdev) 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); @@ -437,16 +439,15 @@ EXPORT_SYMBOL_GPL(pci_restore_pasid_state); int pci_pasid_features(struct pci_dev *pdev) { u16 supported; - int pos; + int pasid = pdev->pasid_cap; if (pdev->is_virtfn) pdev = pci_physfn(pdev); - 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; @@ -466,16 +467,15 @@ EXPORT_SYMBOL_GPL(pci_pasid_features); int pci_max_pasids(struct pci_dev *pdev) { u16 supported; - int pos; + int pasid = pdev->pasid_cap; if (pdev->is_virtfn) pdev = pci_physfn(pdev); - 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 = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index aa08cd35bf87..ae84d28ba03a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -462,6 +462,12 @@ void pci_pri_init(struct pci_dev *dev); static inline void pci_pri_init(struct pci_dev *dev) { } #endif +#ifdef CONFIG_PCI_PASID +void pci_pasid_init(struct pci_dev *dev); +#else +static inline void pci_pasid_init(struct pci_dev *dev) { } +#endif + #ifdef CONFIG_PCI_IOV int pci_iov_init(struct pci_dev *dev); void pci_iov_release(struct pci_dev *dev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index d145165c799c..df2b77866f3b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2327,6 +2327,9 @@ static void pci_init_capabilities(struct pci_dev *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); -- cgit From e5adf79a1d8086aefa56f48eeb08f8fe4e054a3d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 9 Oct 2019 16:07:51 -0500 Subject: PCI/ATS: Cache PRI PRG Response PASID Required bit The PRG Response PASID Required bit in the PRI Capability is read-only. Read it once when we enumerate the device and cache the value so we don't need to read it again. Based-on-patch-by: Kuppuswamy Sathyanarayanan Signed-off-by: Bjorn Helgaas --- drivers/pci/ats.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index d5ac808cae21..76ae518d55f4 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -161,7 +161,16 @@ 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; } /** @@ -301,22 +310,10 @@ EXPORT_SYMBOL_GPL(pci_reset_pri); */ int pci_prg_resp_pasid_required(struct pci_dev *pdev) { - u16 status; - int pri; - if (pdev->is_virtfn) pdev = pci_physfn(pdev); - pri = pdev->pri_cap; - if (!pri) - return 0; - - pci_read_config_word(pdev, pri + PCI_PRI_STATUS, &status); - - if (status & PCI_PRI_STATUS_PASID) - return 1; - - return 0; + return pdev->pasid_required; } EXPORT_SYMBOL_GPL(pci_prg_resp_pasid_required); #endif /* CONFIG_PCI_PRI */ -- cgit From d355bb2097834a977a6f47cec003b7d7748adbd6 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 9 Oct 2019 16:41:04 -0500 Subject: PCI/ATS: Remove unnecessary EXPORT_SYMBOL_GPL() The following functions are only used by the PCI core or by IOMMU drivers that cannot be modular, so there's no need to export them at all: pci_enable_ats() pci_disable_ats() pci_restore_ats_state() pci_ats_queue_depth() pci_ats_page_aligned() pci_enable_pri() pci_restore_pri_state() pci_reset_pri() pci_prg_resp_pasid_required() pci_enable_pasid() pci_disable_pasid() pci_restore_pasid_state() pci_pasid_features() pci_max_pasids() Remove the unnecessary EXPORT_SYMBOL_GPL()s. Signed-off-by: Bjorn Helgaas Reviewed-by: Joerg Roedel --- drivers/pci/ats.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index 76ae518d55f4..982b46f0a54d 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -69,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 @@ -88,7 +87,6 @@ void pci_disable_ats(struct pci_dev *dev) dev->ats_enabled = 0; } -EXPORT_SYMBOL_GPL(pci_disable_ats); void pci_restore_ats_state(struct pci_dev *dev) { @@ -102,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 @@ -129,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. @@ -156,7 +152,6 @@ 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) @@ -218,7 +213,6 @@ int pci_enable_pri(struct pci_dev *pdev, u32 reqs) return 0; } -EXPORT_SYMBOL_GPL(pci_enable_pri); /** * pci_disable_pri - Disable PRI capability @@ -271,7 +265,6 @@ void pci_restore_pri_state(struct pci_dev *pdev) 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 @@ -299,7 +292,6 @@ int pci_reset_pri(struct pci_dev *pdev) return 0; } -EXPORT_SYMBOL_GPL(pci_reset_pri); /** * pci_prg_resp_pasid_required - Return PRG Response PASID Required bit @@ -315,7 +307,6 @@ int pci_prg_resp_pasid_required(struct pci_dev *pdev) return pdev->pasid_required; } -EXPORT_SYMBOL_GPL(pci_prg_resp_pasid_required); #endif /* CONFIG_PCI_PRI */ #ifdef CONFIG_PCI_PASID @@ -373,7 +364,6 @@ int pci_enable_pasid(struct pci_dev *pdev, int features) return 0; } -EXPORT_SYMBOL_GPL(pci_enable_pasid); /** * pci_disable_pasid - Disable the PASID capability @@ -398,7 +388,6 @@ void pci_disable_pasid(struct pci_dev *pdev) pdev->pasid_enabled = 0; } -EXPORT_SYMBOL_GPL(pci_disable_pasid); /** * pci_restore_pasid_state - Restore PASID capabilities @@ -421,7 +410,6 @@ void pci_restore_pasid_state(struct pci_dev *pdev) control = PCI_PASID_CTRL_ENABLE | pdev->pasid_features; 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 @@ -450,7 +438,6 @@ int pci_pasid_features(struct pci_dev *pdev) return supported; } -EXPORT_SYMBOL_GPL(pci_pasid_features); #define PASID_NUMBER_SHIFT 8 #define PASID_NUMBER_MASK (0x1f << PASID_NUMBER_SHIFT) @@ -478,5 +465,4 @@ int pci_max_pasids(struct pci_dev *pdev) return (1 << supported); } -EXPORT_SYMBOL_GPL(pci_max_pasids); #endif /* CONFIG_PCI_PASID */ -- cgit From fef2dd8b3966517172514ea5a89104ba7745678b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 9 Oct 2019 16:47:15 -0500 Subject: PCI/ATS: Make pci_restore_pri_state(), pci_restore_pasid_state() private These interfaces: void pci_restore_pri_state(struct pci_dev *pdev); void pci_restore_pasid_state(struct pci_dev *pdev); are only used in drivers/pci and do not need to be seen by the rest of the kernel. Most them to drivers/pci/pci.h so they're private to the PCI subsystem. Signed-off-by: Bjorn Helgaas Reviewed-by: Joerg Roedel --- drivers/pci/pci.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index ae84d28ba03a..e6b46d2b9846 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -458,14 +458,18 @@ static inline void pci_restore_ats_state(struct pci_dev *dev) { } #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 -- cgit From d8558ac8c93d429d65d7490b512a3a67e559d0d4 Mon Sep 17 00:00:00 2001 From: Steffen Liebergeld Date: Wed, 18 Sep 2019 15:16:52 +0200 Subject: PCI: Fix Intel ACS quirk UPDCR register address According to documentation [0] the correct offset for the Upstream Peer Decode Configuration Register (UPDCR) is 0x1014. It was previously defined as 0x1114. d99321b63b1f ("PCI: Enable quirks for PCIe ACS on Intel PCH root ports") intended to enforce isolation between PCI devices allowing them to be put into separate IOMMU groups. Due to the wrong register offset the intended isolation was not fully enforced. This is fixed with this patch. Please note that I did not test this patch because I have no hardware that implements this register. [0] https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/4th-gen-core-family-mobile-i-o-datasheet.pdf (page 325) Fixes: d99321b63b1f ("PCI: Enable quirks for PCIe ACS on Intel PCH root ports") Link: https://lore.kernel.org/r/7a3505df-79ba-8a28-464c-88b83eefffa6@kernkonzept.com Signed-off-by: Steffen Liebergeld Signed-off-by: Bjorn Helgaas Reviewed-by: Andrew Murray Acked-by: Ashok Raj Cc: stable@vger.kernel.org # v3.15+ --- drivers/pci/quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 320255e5e8f8..cd3e84ae742e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4706,7 +4706,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 -- cgit From 56b4cd4b7da9ee95778eb5c8abea49f641ebfd91 Mon Sep 17 00:00:00 2001 From: Slawomir Pawlowski Date: Tue, 17 Sep 2019 09:20:48 +0000 Subject: PCI: Add DMA alias quirk for Intel VCA NTB 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. Add aliases to 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. Link: https://lore.kernel.org/r/5683A335CC8BE1438C3C30C49DCC38DF637CED8E@IRSMSX102.ger.corp.intel.com Signed-off-by: Slawomir Pawlowski Signed-off-by: Przemek Kitszel Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index cd3e84ae742e..d5d57cd91a5e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -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 -- cgit From 35ff867b76576e32f34c698ccd11343f7d616204 Mon Sep 17 00:00:00 2001 From: Pierre Crégut Date: Wed, 11 Sep 2019 09:27:36 +0200 Subject: PCI/IOV: Serialize sysfs sriov_numvfs reads vs writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When sriov_numvfs is being updated, we call the driver->sriov_configure() function, which may enable VFs and call probe functions, which may make new devices visible. This all happens before before sriov_numvfs_store() updates sriov->num_VFs, so previously, concurrent sysfs reads of sriov_numvfs returned stale values. Serialize the sysfs read vs the write so the read returns the correct num_VFs value. [bhelgaas: hold device_lock instead of checking mutex_is_locked()] Link: https://bugzilla.kernel.org/show_bug.cgi?id=202991 Link: https://lore.kernel.org/r/20190911072736.32091-1-pierre.cregut@orange.com Signed-off-by: Pierre Crégut Signed-off-by: Bjorn Helgaas --- drivers/pci/iov.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index b3f972e8cfed..1d3de1ea081d 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -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; + + /* 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", pdev->sriov->num_VFs); + return sprintf(buf, "%u\n", num_vfs); } /* -- cgit From f338bb9f0179cb959977b74e8331b312264d720b Mon Sep 17 00:00:00 2001 From: George Cherian Date: Mon, 11 Nov 2019 02:43:03 +0000 Subject: PCI: Apply Cavium ACS quirk to ThunderX2 and ThunderX3 Enhance the ACS quirk for Cavium Processors. Add the root port vendor IDs for ThunderX2 and ThunderX3 series of processors. [bhelgaas: add Fixes: and stable tag] Fixes: f2ddaf8dfd4a ("PCI: Apply Cavium ThunderX ACS quirk to more Root Ports") Link: https://lore.kernel.org/r/20191111024243.GA11408@dc5-eodlnx05.marvell.com Signed-off-by: George Cherian Signed-off-by: Bjorn Helgaas Reviewed-by: Robert Richter Cc: stable@vger.kernel.org # v4.12+ --- drivers/pci/quirks.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d5d57cd91a5e..2544e210b984 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4347,15 +4347,21 @@ 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) -- cgit From c8de8ed2dcaac82e5d76d467dc0b02e0ee79809b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 5 Sep 2019 17:54:42 -0500 Subject: PCI: Make ACS quirk implementations more uniform The ACS quirks differ in needless ways, which makes them look more different than they really are. Reorder the ACS flags in order of definitions in the spec: PCI_ACS_SV Source Validation PCI_ACS_TB Translation Blocking PCI_ACS_RR P2P Request Redirect PCI_ACS_CR P2P Completion Redirect PCI_ACS_UF Upstream Forwarding PCI_ACS_EC P2P Egress Control PCI_ACS_DT Direct Translated P2P (PCIe r5.0, sec 7.7.8.2) and use similar code structure in all. No functional change intended. Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe Reviewed-by: Alex Williamson --- drivers/pci/quirks.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 2544e210b984..59f73d084e1d 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4366,18 +4366,18 @@ static bool pci_quirk_cavium_acs_match(struct pci_dev *dev) 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; + acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); return acs_flags ? 0 : 1; } @@ -4395,7 +4395,7 @@ static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags) } /* - * 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. @@ -4443,37 +4443,34 @@ 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) +#define INTEL_PCH_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) 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) + acs_flags &= ~(INTEL_PCH_ACS_FLAGS); + + return acs_flags ? 0 : 1; } /* - * 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); + acs_flags &= ~(PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); - return ret; + return acs_flags ? 0 : 1; } static int pci_quirk_al_acs(struct pci_dev *dev, u16 acs_flags) -- cgit From 7cf2cba43f15c74bac46dc5f0326805d25ef514d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 6 Sep 2019 18:36:06 -0500 Subject: PCI: Unify ACS quirk desired vs provided checking Most of the ACS quirks have a similar pattern of: acs_flags &= ~( ); return acs_flags ? 0 : 1; Pull this out into a helper function to simplify the quirks slightly. The helper function is also a convenient place for comments about what the list of ACS controls means. No functional change intended. Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe Reviewed-by: Alex Williamson --- drivers/pci/quirks.c | 67 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 22 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 59f73d084e1d..9a1051071a81 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4296,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 @@ -4339,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 @@ -4377,9 +4395,8 @@ static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags) * hardware implements and enables equivalent ACS functionality for * these flags. */ - 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 int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags) @@ -4389,9 +4406,8 @@ 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); } /* @@ -4443,17 +4459,16 @@ static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev) return false; } -#define INTEL_PCH_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) - static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags) { if (!pci_quirk_intel_pch_acs_match(dev)) return -ENOTTY; if (dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK) - acs_flags &= ~(INTEL_PCH_ACS_FLAGS); + return pci_acs_ctrl_enabled(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, 0); } /* @@ -4468,9 +4483,8 @@ static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags) */ static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags) { - 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 int pci_quirk_al_acs(struct pci_dev *dev, u16 acs_flags) @@ -4571,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) @@ -4585,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) @@ -4599,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 { @@ -4703,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; -- cgit