pcie_capability_read_word() and pcie_capability_read_dword() use the kernel config accessors which don't check block_cfg_access, so they can't be used for reads on behalf of userspace that should wait for a reset (or other pci_cfg_access_lock() holder) to finish. Add pcie_capability_user_read_word() and pcie_capability_user_read_dword() helpers, which provide the same function using the user config accessors. These are for use within the PCI core, so they are declared in drivers/pci/pci.h and not exported. Signed-off-by: Matthew Wood Tested-by: Nikita Vetoshkin Reviewed-by: Keith Busch --- drivers/pci/access.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 2 ++ 2 files changed, 52 insertions(+) diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 18a206bb2a94..ff5a16236758 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -490,6 +490,56 @@ int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val) } EXPORT_SYMBOL(pcie_capability_read_dword); +/* + * Same as pcie_capability_read_{word,dword}(), but using the user config + * accessors. Returns 0 on success, negative values indicate error. + */ +int pcie_capability_user_read_word(struct pci_dev *dev, int pos, u16 *val) +{ + int ret; + + *val = 0; + if (pos & 1) + return -EINVAL; + + if (pcie_capability_reg_implemented(dev, pos)) { + ret = pci_user_read_config_word(dev, pci_pcie_cap(dev) + pos, + val); + if (ret) + *val = 0; + return ret; + } + + if (pci_is_pcie(dev) && pcie_downstream_port(dev) && + pos == PCI_EXP_SLTSTA) + *val = PCI_EXP_SLTSTA_PDS; + + return 0; +} + +int pcie_capability_user_read_dword(struct pci_dev *dev, int pos, u32 *val) +{ + int ret; + + *val = 0; + if (pos & 3) + return -EINVAL; + + if (pcie_capability_reg_implemented(dev, pos)) { + ret = pci_user_read_config_dword(dev, pci_pcie_cap(dev) + pos, + val); + if (ret) + *val = 0; + return ret; + } + + if (pci_is_pcie(dev) && pcie_downstream_port(dev) && + pos == PCI_EXP_SLTSTA) + *val = PCI_EXP_SLTSTA_PDS; + + return 0; +} + int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val) { if (pos & 1) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 77efa4c5c960..7c5a2ebc5706 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -128,6 +128,8 @@ extern struct mutex pci_rescan_remove_lock; bool pcie_cap_has_lnkctl(const struct pci_dev *dev); bool pcie_cap_has_lnkctl2(const struct pci_dev *dev); bool pcie_cap_has_rtctl(const struct pci_dev *dev); +int pcie_capability_user_read_word(struct pci_dev *dev, int pos, u16 *val); +int pcie_capability_user_read_dword(struct pci_dev *dev, int pos, u32 *val); /* Standard Capability finder */ /** -- 2.53.0-Meta