Calculate the negotiated TPH requester type from device and root port capabilities once in pci_tph_init(). Add tph_ext_support 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 | 4 +++- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/pci/tph.c b/drivers/pci/tph.c index 489487158b99..4097787ea98a 100644 --- a/drivers/pci/tph.c +++ b/drivers/pci/tph.c @@ -383,7 +383,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) @@ -403,23 +402,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_support ? 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, ®); @@ -506,13 +490,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_support = !!(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 ce520523b152..a99eeea53c81 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -587,7 +587,9 @@ struct pci_dev { u8 reset_methods[PCI_NUM_RESET_METHODS]; /* In priority order */ #ifdef CONFIG_PCIE_TPH - u16 tph_cap:15; /* TPH capability offset */ + u16 tph_cap:14; /* TPH capability offset */ + u16 tph_ext_support:1; /* Indicate whether Extended TPH + * requester is supported */ u16 tph_enabled:1; /* Whether TPH is enabled */ u8 tph_mode; /* TPH mode */ u8 tph_req_type; /* TPH requester type */ -- 2.17.1