Calculate the negotiated TPH requester type from device and root port capabilities once in pci_tph_init(). Add tph_ext_requester flag to cache whether the device is allowed to issue Extended TPH requests after topology negotiation. If the final requester type is disabled, clear TPH capability to prevent usage. Simplify pcie_enable_tph() by using the cached requester capability instead of recalculating every time. Signed-off-by: Chengwen Feng --- drivers/pci/tph.c | 43 +++++++++++++++++++++++++------------------ include/linux/pci.h | 1 + 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/drivers/pci/tph.c b/drivers/pci/tph.c index bef3a55539c4..b4ecc510033a 100644 --- a/drivers/pci/tph.c +++ b/drivers/pci/tph.c @@ -384,7 +384,6 @@ int pcie_enable_tph(struct pci_dev *pdev, int mode) { u32 reg; u8 dev_modes; - u8 rp_req_type; /* Honor "notph" kernel parameter */ if (pci_tph_disabled) @@ -404,23 +403,8 @@ int pcie_enable_tph(struct pci_dev *pdev, int mode) pdev->tph_mode = mode; - /* Get req_type supported by device and its Root Port */ - pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CAP, ®); - if (FIELD_GET(PCI_TPH_CAP_EXT_TPH, reg)) - pdev->tph_req_type = PCI_TPH_REQ_EXT_TPH; - else - pdev->tph_req_type = PCI_TPH_REQ_TPH_ONLY; - - /* Check if the device is behind a Root Port */ - if (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END) { - rp_req_type = get_rp_completer_type(pdev); - - /* Final req_type is the smallest value of two */ - pdev->tph_req_type = min(pdev->tph_req_type, rp_req_type); - } - - if (pdev->tph_req_type == PCI_TPH_REQ_DISABLE) - return -EINVAL; + pdev->tph_req_type = pdev->tph_ext_requester ? PCI_TPH_REQ_EXT_TPH : + PCI_TPH_REQ_TPH_ONLY; /* Write them into TPH control register */ pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, ®); @@ -510,13 +494,36 @@ void pci_no_tph(void) void pci_tph_init(struct pci_dev *pdev) { + u8 tph_req_type, rp_req_type; int num_entries; u32 save_size; + u32 reg = 0; pdev->tph_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_TPH); if (!pdev->tph_cap) return; + /* Get req_type supported by device and its Root Port */ + pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CAP, ®); + if (FIELD_GET(PCI_TPH_CAP_EXT_TPH, reg)) + tph_req_type = PCI_TPH_REQ_EXT_TPH; + else + tph_req_type = PCI_TPH_REQ_TPH_ONLY; + + /* Check if the device is behind a Root Port */ + if (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END) { + rp_req_type = get_rp_completer_type(pdev); + /* Final req_type is the smallest value of two */ + tph_req_type = min(tph_req_type, rp_req_type); + } + + if (tph_req_type == PCI_TPH_REQ_DISABLE) { + pdev->tph_cap = 0; + return; + } + + pdev->tph_ext_requester = !!(tph_req_type == PCI_TPH_REQ_EXT_TPH); + num_entries = pcie_tph_get_st_table_size(pdev); save_size = sizeof(u32) + num_entries * sizeof(u16); pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_TPH, save_size); diff --git a/include/linux/pci.h b/include/linux/pci.h index 2c4454583c11..0f4361aca794 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -509,6 +509,7 @@ struct pci_dev { unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ unsigned int non_mappable_bars:1; /* BARs can't be mapped to user-space */ + unsigned int tph_ext_requester:1; /* Can issue Extended TPH requests */ pci_dev_flags_t dev_flags; atomic_t enable_cnt; /* pci_enable_device has been called */ -- 2.17.1