From fdc348121f2465897792f946715a5da7887e5f97 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Wed, 19 Mar 2025 10:29:00 +0100 Subject: irqdomain: pci: Switch to of_fwnode_handle() of_node_to_fwnode() is irqdomain's reimplementation of the "officially" defined of_fwnode_handle(). The former is in the process of being removed, so use the latter instead. Signed-off-by: Jiri Slaby (SUSE) Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250319092951.37667-8-jirislaby@kernel.org --- drivers/pci/controller/dwc/pcie-designware-host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index ecc33f6789e3..d1cd48efad43 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -227,7 +227,7 @@ static const struct irq_domain_ops dw_pcie_msi_domain_ops = { int dw_pcie_allocate_domains(struct dw_pcie_rp *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node); + struct fwnode_handle *fwnode = of_fwnode_handle(pci->dev->of_node); pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors, &dw_pcie_msi_domain_ops, pp); -- cgit v1.2.3 From b584ab12d59f646b9254b2b16ff197d612fd4935 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 28 Mar 2025 15:30:44 +0100 Subject: PCI: rcar-gen4: set ep BAR4 fixed size On rcar-gen4, the ep BAR4 has a fixed size of 256B. Document this constraint in the epc features of the platform. Fixes: e311b3834dfa ("PCI: rcar-gen4: Add endpoint mode support") Signed-off-by: Jerome Brunet Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250328-rcar-gen4-bar4-v1-1-10bb6ce9ee7f@baylibre.com --- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index fc872dd35029..02638ec442e7 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -403,6 +403,7 @@ static const struct pci_epc_features rcar_gen4_pcie_epc_features = { .msix_capable = false, .bar[BAR_1] = { .type = BAR_RESERVED, }, .bar[BAR_3] = { .type = BAR_RESERVED, }, + .bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256 }, .bar[BAR_5] = { .type = BAR_RESERVED, }, .align = SZ_1M, }; -- cgit v1.2.3 From f9eb654fb194e7c404d4984481a18edb9b1c1d7c Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Fri, 28 Mar 2025 15:58:31 +0530 Subject: PCI: dwc: Update pci->num_lanes to maximum supported link width If the num-lanes property is not present in the devicetree, update pci->num_lanes with the hardware supported maximum link width using the newly introduced dw_pcie_link_get_max_link_width() API. The API is used to get the Maximum Link Width (MLW) of the controller. Signed-off-by: Krishna Chaitanya Chundru [mani: reworded commit message a bit] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250328-preset_v6-v9-3-22cfa0490518@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-designware-host.c | 3 +++ drivers/pci/controller/dwc/pcie-designware.c | 8 ++++++++ drivers/pci/controller/dwc/pcie-designware.h | 1 + 3 files changed, 12 insertions(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index ecc33f6789e3..e8eccf6a1b2f 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -523,6 +523,9 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) dw_pcie_iatu_detect(pci); + if (pci->num_lanes < 1) + pci->num_lanes = dw_pcie_link_get_max_link_width(pci); + /* * Allocate the resource for MSG TLP before programming the iATU * outbound window in dw_pcie_setup_rc(). Since the allocation depends diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 97d76d3dc066..cafe91bd9c34 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -781,6 +781,14 @@ static void dw_pcie_link_set_max_speed(struct dw_pcie *pci) } +int dw_pcie_link_get_max_link_width(struct dw_pcie *pci) +{ + u8 cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + u32 lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP); + + return FIELD_GET(PCI_EXP_LNKCAP_MLW, lnkcap); +} + static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes) { u32 lnkcap, lwsc, plc; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 56aafdbcdaca..dda788e3bd24 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -540,6 +540,7 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val); int dw_pcie_link_up(struct dw_pcie *pci); void dw_pcie_upconfig_setup(struct dw_pcie *pci); int dw_pcie_wait_for_link(struct dw_pcie *pci); +int dw_pcie_link_get_max_link_width(struct dw_pcie *pci); int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, const struct dw_pcie_ob_atu_cfg *atu); int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type, -- cgit v1.2.3 From 09483959e34d2577142ad7c56491c82f50da540d Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Fri, 28 Mar 2025 15:58:33 +0530 Subject: PCI: dwc: Add support for configuring lane equalization presets PCIe equalization presets are predefined settings used to optimize signal integrity by compensating for signal loss and distortion in high-speed data transmission. Based upon the number of lanes and the data rate supported, write the preset data read from the device tree in to the lane equalization control registers. These preset values will be used by the controller during the LTSSM lane equalization procedure. Signed-off-by: Krishna Chaitanya Chundru [mani: reworded the commit message and comments in the driver] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250328-preset_v6-v9-5-22cfa0490518@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-designware-host.c | 76 +++++++++++++++++++++++ drivers/pci/controller/dwc/pcie-designware.h | 3 + 2 files changed, 79 insertions(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index e8eccf6a1b2f..b7faef26ed44 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -526,6 +526,10 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) if (pci->num_lanes < 1) pci->num_lanes = dw_pcie_link_get_max_link_width(pci); + ret = of_pci_get_equalization_presets(dev, &pp->presets, pci->num_lanes); + if (ret) + goto err_free_msi; + /* * Allocate the resource for MSG TLP before programming the iATU * outbound window in dw_pcie_setup_rc(). Since the allocation depends @@ -831,6 +835,77 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp) return 0; } +static void dw_pcie_program_presets(struct dw_pcie_rp *pp, enum pci_bus_speed speed) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + u8 lane_eq_offset, lane_reg_size, cap_id; + u8 *presets; + u32 cap; + int i; + + if (speed == PCIE_SPEED_8_0GT) { + presets = (u8 *)pp->presets.eq_presets_8gts; + lane_eq_offset = PCI_SECPCI_LE_CTRL; + cap_id = PCI_EXT_CAP_ID_SECPCI; + /* For data rate of 8 GT/S each lane equalization control is 16bits wide*/ + lane_reg_size = 0x2; + } else if (speed == PCIE_SPEED_16_0GT) { + presets = pp->presets.eq_presets_Ngts[EQ_PRESET_TYPE_16GTS - 1]; + lane_eq_offset = PCI_PL_16GT_LE_CTRL; + cap_id = PCI_EXT_CAP_ID_PL_16GT; + lane_reg_size = 0x1; + } else if (speed == PCIE_SPEED_32_0GT) { + presets = pp->presets.eq_presets_Ngts[EQ_PRESET_TYPE_32GTS - 1]; + lane_eq_offset = PCI_PL_32GT_LE_CTRL; + cap_id = PCI_EXT_CAP_ID_PL_32GT; + lane_reg_size = 0x1; + } else if (speed == PCIE_SPEED_64_0GT) { + presets = pp->presets.eq_presets_Ngts[EQ_PRESET_TYPE_64GTS - 1]; + lane_eq_offset = PCI_PL_64GT_LE_CTRL; + cap_id = PCI_EXT_CAP_ID_PL_64GT; + lane_reg_size = 0x1; + } else { + return; + } + + if (presets[0] == PCI_EQ_RESV) + return; + + cap = dw_pcie_find_ext_capability(pci, cap_id); + if (!cap) + return; + + /* + * Write preset values to the registers byte-by-byte for the given + * number of lanes and register size. + */ + for (i = 0; i < pci->num_lanes * lane_reg_size; i++) + dw_pcie_writeb_dbi(pci, cap + lane_eq_offset + i, presets[i]); +} + +static void dw_pcie_config_presets(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + enum pci_bus_speed speed = pcie_link_speed[pci->max_link_speed]; + + /* + * Lane equalization settings need to be applied for all data rates the + * controller supports and for all supported lanes. + */ + + if (speed >= PCIE_SPEED_8_0GT) + dw_pcie_program_presets(pp, PCIE_SPEED_8_0GT); + + if (speed >= PCIE_SPEED_16_0GT) + dw_pcie_program_presets(pp, PCIE_SPEED_16_0GT); + + if (speed >= PCIE_SPEED_32_0GT) + dw_pcie_program_presets(pp, PCIE_SPEED_32_0GT); + + if (speed >= PCIE_SPEED_64_0GT) + dw_pcie_program_presets(pp, PCIE_SPEED_64_0GT); +} + int dw_pcie_setup_rc(struct dw_pcie_rp *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -884,6 +959,7 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp) PCI_COMMAND_MASTER | PCI_COMMAND_SERR; dw_pcie_writel_dbi(pci, PCI_COMMAND, val); + dw_pcie_config_presets(pp); /* * If the platform provides its own child bus config accesses, it means * the platform uses its own address translation component rather than diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index dda788e3bd24..7add69f13759 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -25,6 +25,8 @@ #include #include +#include "../../pci.h" + /* DWC PCIe IP-core versions (native support since v4.70a) */ #define DW_PCIE_VER_365A 0x3336352a #define DW_PCIE_VER_460A 0x3436302a @@ -412,6 +414,7 @@ struct dw_pcie_rp { int msg_atu_index; struct resource *msg_res; bool use_linkup_irq; + struct pci_eq_presets presets; }; struct dw_pcie_ep_ops { -- cgit v1.2.3 From 3e5127469a8d41153fb30031a271788f52dd17ec Mon Sep 17 00:00:00 2001 From: Nitheesh Sekar Date: Wed, 26 Mar 2025 12:10:58 +0400 Subject: PCI: qcom: Add support for IPQ5018 Add IPQ5018 platform with is based on Qcom IP rev. 2.9.0 and Synopsys IP rev. 5.00a. The platform itself has two PCIe Gen2 controllers: one single-lane and one dual-lane. So add the IPQ5018 compatible and re-use 2_9_0 ops. Signed-off-by: Nitheesh Sekar Signed-off-by: Sricharan R Signed-off-by: George Moussalem Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250326-ipq5018-pcie-v7-4-e1828fef06c9@outlook.com --- drivers/pci/controller/dwc/pcie-qcom.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index dc98ae63362d..e91bbe218569 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1840,6 +1840,7 @@ static const struct of_device_id qcom_pcie_match[] = { { .compatible = "qcom,pcie-apq8064", .data = &cfg_2_1_0 }, { .compatible = "qcom,pcie-apq8084", .data = &cfg_1_0_0 }, { .compatible = "qcom,pcie-ipq4019", .data = &cfg_2_4_0 }, + { .compatible = "qcom,pcie-ipq5018", .data = &cfg_2_9_0 }, { .compatible = "qcom,pcie-ipq6018", .data = &cfg_2_9_0 }, { .compatible = "qcom,pcie-ipq8064", .data = &cfg_2_1_0 }, { .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 }, -- cgit v1.2.3 From 7d9b5d6115532cf90a789ed6afd3f4c70ebbd827 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 17 Apr 2025 08:35:09 +0800 Subject: PCI: dw-rockchip: Remove PCIE_L0S_ENTRY check from rockchip_pcie_link_up() rockchip_pcie_link_up() currently has two issues: 1. Value 0x11 of PCIE_L0S_ENTRY corresponds to L0 state, not L0S. So the naming is wrong from the very beginning. 2. Checking for value 0x11 treats other states like L0S and L1 as link down, which is wrong. Hence, remove the PCIE_L0S_ENTRY check and also its definition. This allows adding ASPM support in the successive commits. Fixes: 0e898eb8df4e ("PCI: rockchip-dwc: Add Rockchip RK356X host controller driver") Signed-off-by: Shawn Lin [mani: commit message rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Manivannan Sadhasivam Cc: stable@vger.kernel.org Link: https://patch.msgid.link/1744850111-236269-1-git-send-email-shawn.lin@rock-chips.com --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index c624b7ebd118..21dc99c9d95c 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -44,7 +44,6 @@ #define PCIE_LINKUP (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP) #define PCIE_RDLH_LINK_UP_CHGED BIT(1) #define PCIE_LINK_REQ_RST_NOT_INT BIT(2) -#define PCIE_L0S_ENTRY 0x11 #define PCIE_CLIENT_GENERAL_CONTROL 0x0 #define PCIE_CLIENT_INTR_STATUS_LEGACY 0x8 #define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c @@ -177,8 +176,7 @@ static int rockchip_pcie_link_up(struct dw_pcie *pci) struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); u32 val = rockchip_pcie_get_ltssm(rockchip); - if ((val & PCIE_LINKUP) == PCIE_LINKUP && - (val & PCIE_LTSSM_STATUS_MASK) == PCIE_L0S_ENTRY) + if ((val & PCIE_LINKUP) == PCIE_LINKUP) return 1; return 0; -- cgit v1.2.3 From 198e69cc4150aba1e7af740a2111ace6a267779e Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 17 Apr 2025 08:35:10 +0800 Subject: PCI: dw-rockchip: Enable ASPM L0s capability for both RC and EP modes L0s capability isn't enabled on all Rockchip SoCs by default, so enable it in order to make ASPM L0s work on Rockchip platforms. Testing the L0s for a long time revealed that the default N_FTS value of 210 in the hardware doesn't work stable and causes LTSSM to switch between L0s and Recovery states. This leads to long exit latency and also causes link down sometimes. So override the value to the max 255, which seems to work fine under both PHYs used on Rockchip platforms. Signed-off-by: Shawn Lin [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/1744850111-236269-2-git-send-email-shawn.lin@rock-chips.com --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index 21dc99c9d95c..e4519c020ea9 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -182,6 +182,21 @@ static int rockchip_pcie_link_up(struct dw_pcie *pci) return 0; } +static void rockchip_pcie_enable_l0s(struct dw_pcie *pci) +{ + u32 cap, lnkcap; + + /* Enable L0S capability for all SoCs */ + cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + if (cap) { + lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP); + lnkcap |= PCI_EXP_LNKCAP_ASPM_L0S; + dw_pcie_dbi_ro_wr_en(pci); + dw_pcie_writel_dbi(pci, cap + PCI_EXP_LNKCAP, lnkcap); + dw_pcie_dbi_ro_wr_dis(pci); + } +} + static int rockchip_pcie_start_link(struct dw_pcie *pci) { struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); @@ -231,6 +246,8 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp) irq_set_chained_handler_and_data(irq, rockchip_pcie_intx_handler, rockchip); + rockchip_pcie_enable_l0s(pci); + return 0; } @@ -271,6 +288,8 @@ static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); enum pci_barno bar; + rockchip_pcie_enable_l0s(pci); + for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) dw_pcie_ep_reset_bar(pci, bar); }; @@ -599,6 +618,10 @@ static int rockchip_pcie_probe(struct platform_device *pdev) rockchip->pci.ops = &dw_pcie_ops; rockchip->data = data; + /* Default N_FTS value (210) is broken, override it to 255 */ + rockchip->pci.n_fts[0] = 255; /* Gen1 */ + rockchip->pci.n_fts[1] = 255; /* Gen2+ */ + ret = rockchip_pcie_resource_get(pdev, rockchip); if (ret) return ret; -- cgit v1.2.3 From d4a5d7e6d91f6e53c8bf6ec72b7ee6c51f781695 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 14 Apr 2025 09:28:29 +0800 Subject: PCI: dw-rockchip: Move rockchip_pcie_ep_hide_broken_ats_cap_rk3588() to dw_pcie_ep_ops::init() In the case of PERST# deassert, non-sticky registers will get reset to their hardware default state and EXT_CAP registers are one among them. But since the broken ATS cap is hidden only in dw_pcie_ep_ops::pre_init() callback which is not gettting called during PERST# deassert, it results in the capability getting advertised again. So move it to dw_pcie_ep_ops::init() to fix it. Suggested-by: Niklas Cassel Signed-off-by: Shawn Lin [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Tested-by: Niklas Cassel Reviewed-by: Niklas Cassel Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/1744594109-209312-1-git-send-email-shawn.lin@rock-chips.com --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index e4519c020ea9..7790a9f33e48 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -278,17 +278,13 @@ static void rockchip_pcie_ep_hide_broken_ats_cap_rk3588(struct dw_pcie_ep *ep) dev_err(dev, "failed to hide ATS capability\n"); } -static void rockchip_pcie_ep_pre_init(struct dw_pcie_ep *ep) -{ - rockchip_pcie_ep_hide_broken_ats_cap_rk3588(ep); -} - static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); enum pci_barno bar; rockchip_pcie_enable_l0s(pci); + rockchip_pcie_ep_hide_broken_ats_cap_rk3588(ep); for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) dw_pcie_ep_reset_bar(pci, bar); @@ -359,7 +355,6 @@ rockchip_pcie_get_features(struct dw_pcie_ep *ep) static const struct dw_pcie_ep_ops rockchip_pcie_ep_ops = { .init = rockchip_pcie_ep_init, - .pre_init = rockchip_pcie_ep_pre_init, .raise_irq = rockchip_pcie_raise_irq, .get_features = rockchip_pcie_get_features, }; -- cgit v1.2.3 From 9c03e30e3ade32136fed5a4ab7872dcb205687d3 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:08 +0800 Subject: PCI: imx6: Skip link up workaround for newer platforms The current link setup procedure has one workaround to detect the devices behind PCIe switches on some i.MX6 platforms. But this workaround is not needed on recent i.MX7 platforms. So skip the workaround for platforms that do not set the flag and start LTSSM directly. Also, change the flag name from IMX_PCIE_FLAG_IMX_SPEED_CHANGE to IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND to match the usecase. Signed-off-by: Richard Zhu [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250416081314.3929794-2-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 5f267dd261b5..a4c0714c6468 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -91,7 +91,7 @@ enum imx_pcie_variants { }; #define IMX_PCIE_FLAG_IMX_PHY BIT(0) -#define IMX_PCIE_FLAG_IMX_SPEED_CHANGE BIT(1) +#define IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND BIT(1) #define IMX_PCIE_FLAG_SUPPORTS_SUSPEND BIT(2) #define IMX_PCIE_FLAG_HAS_PHYDRV BIT(3) #define IMX_PCIE_FLAG_HAS_APP_RESET BIT(4) @@ -860,6 +860,12 @@ static int imx_pcie_start_link(struct dw_pcie *pci) u32 tmp; int ret; + if (!(imx_pcie->drvdata->flags & + IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND)) { + imx_pcie_ltssm_enable(dev); + return 0; + } + /* * Force Gen1 operation when starting the link. In case the link is * started in Gen2 mode, there is a possibility the devices on the @@ -896,22 +902,10 @@ static int imx_pcie_start_link(struct dw_pcie *pci) dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp); dw_pcie_dbi_ro_wr_dis(pci); - if (imx_pcie->drvdata->flags & - IMX_PCIE_FLAG_IMX_SPEED_CHANGE) { - - /* - * On i.MX7, DIRECT_SPEED_CHANGE behaves differently - * from i.MX6 family when no link speed transition - * occurs and we go Gen1 -> yep, Gen1. The difference - * is that, in such case, it will not be cleared by HW - * which will cause the following code to report false - * failure. - */ - ret = imx_pcie_wait_for_speed_change(imx_pcie); - if (ret) { - dev_err(dev, "Failed to bring link up!\n"); - goto err_reset_phy; - } + ret = imx_pcie_wait_for_speed_change(imx_pcie); + if (ret) { + dev_err(dev, "Failed to bring link up!\n"); + goto err_reset_phy; } /* Make sure link training is finished as well! */ @@ -1649,7 +1643,7 @@ static const struct imx_pcie_drvdata drvdata[] = { [IMX6Q] = { .variant = IMX6Q, .flags = IMX_PCIE_FLAG_IMX_PHY | - IMX_PCIE_FLAG_IMX_SPEED_CHANGE | + IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND | IMX_PCIE_FLAG_BROKEN_SUSPEND | IMX_PCIE_FLAG_SUPPORTS_SUSPEND, .dbi_length = 0x200, @@ -1665,7 +1659,7 @@ static const struct imx_pcie_drvdata drvdata[] = { [IMX6SX] = { .variant = IMX6SX, .flags = IMX_PCIE_FLAG_IMX_PHY | - IMX_PCIE_FLAG_IMX_SPEED_CHANGE | + IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND | IMX_PCIE_FLAG_SUPPORTS_SUSPEND, .gpr = "fsl,imx6q-iomuxc-gpr", .ltssm_off = IOMUXC_GPR12, @@ -1680,7 +1674,7 @@ static const struct imx_pcie_drvdata drvdata[] = { [IMX6QP] = { .variant = IMX6QP, .flags = IMX_PCIE_FLAG_IMX_PHY | - IMX_PCIE_FLAG_IMX_SPEED_CHANGE | + IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND | IMX_PCIE_FLAG_SUPPORTS_SUSPEND, .dbi_length = 0x200, .gpr = "fsl,imx6q-iomuxc-gpr", -- cgit v1.2.3 From 4a4be0c088e3029a482ef8ac98bb2acb94af960e Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:09 +0800 Subject: PCI: imx6: Call dw_pcie_wait_for_link() from start_link() callback only when required Since the DWC driver is already calling dw_pcie_wait_for_link() after calling the start_link() callback, remove the redundant dw_pcie_wait_for_link() call from imx_pcie_start_link(). It is still required to call this function for controllers supporting Gen 2 and higher link speeds. Suggested-by: Manivannan Sadhasivam Signed-off-by: Richard Zhu [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Reviewed-by: Frank Li Link: https://patch.msgid.link/20250416081314.3929794-3-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index a4c0714c6468..c5871c3d4194 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -881,11 +881,11 @@ static int imx_pcie_start_link(struct dw_pcie *pci) /* Start LTSSM. */ imx_pcie_ltssm_enable(dev); - ret = dw_pcie_wait_for_link(pci); - if (ret) - goto err_reset_phy; - if (pci->max_link_speed > 1) { + ret = dw_pcie_wait_for_link(pci); + if (ret) + goto err_reset_phy; + /* Allow faster modes after the link is up */ dw_pcie_dbi_ro_wr_en(pci); tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); @@ -907,17 +907,10 @@ static int imx_pcie_start_link(struct dw_pcie *pci) dev_err(dev, "Failed to bring link up!\n"); goto err_reset_phy; } - - /* Make sure link training is finished as well! */ - ret = dw_pcie_wait_for_link(pci); - if (ret) - goto err_reset_phy; } else { dev_info(dev, "Link: Only Gen1 is enabled\n"); } - tmp = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA); - dev_info(dev, "Link up, Gen%i\n", tmp & PCI_EXP_LNKSTA_CLS); return 0; err_reset_phy: -- cgit v1.2.3 From 47f54a902dcd3b756e8e761f2c4c742af57dfff0 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:10 +0800 Subject: PCI: imx6: Toggle the core reset for i.MX95 PCIe Add toggling core reset for i.MX95 to align with PHY's power-up sequence. Note that the register is named as IMX95_PCIE_COLD_RST in hardware, though it is used to reset the PCIe core. Signed-off-by: Richard Zhu Signed-off-by: Manivannan Sadhasivam [mani: subject and description rewording] Reviewed-by: Manivannan Sadhasivam Reviewed-by: Frank Li Link: https://patch.msgid.link/20250416081314.3929794-4-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index c5871c3d4194..7c60b712480a 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -71,6 +71,9 @@ #define IMX95_SID_MASK GENMASK(5, 0) #define IMX95_MAX_LUT 32 +#define IMX95_PCIE_RST_CTRL 0x3010 +#define IMX95_PCIE_COLD_RST BIT(0) + #define to_imx_pcie(x) dev_get_drvdata((x)->dev) enum imx_pcie_variants { @@ -773,6 +776,43 @@ static int imx7d_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert) return 0; } +static int imx95_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert) +{ + u32 val; + + if (assert) { + /* + * From i.MX95 PCIe PHY perspective, the COLD reset toggle + * should be complete after power-up by the following sequence. + * > 10us(at power-up) + * > 10ns(warm reset) + * |<------------>| + * ______________ + * phy_reset ____/ \________________ + * ____________ + * ref_clk_en_______________________/ + * Toggle COLD reset aligned with this sequence for i.MX95 PCIe. + */ + regmap_set_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL, + IMX95_PCIE_COLD_RST); + /* + * Make sure the write to IMX95_PCIE_RST_CTRL is flushed to the + * hardware by doing a read. Otherwise, there is no guarantee + * that the write has reached the hardware before udelay(). + */ + regmap_read_bypassed(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL, + &val); + udelay(15); + regmap_clear_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL, + IMX95_PCIE_COLD_RST); + regmap_read_bypassed(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL, + &val); + udelay(10); + } + + return 0; +} + static void imx_pcie_assert_core_reset(struct imx_pcie *imx_pcie) { reset_control_assert(imx_pcie->pciephy_reset); @@ -1739,6 +1779,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .ltssm_mask = IMX95_PCIE_LTSSM_EN, .mode_off[0] = IMX95_PE0_GEN_CTRL_1, .mode_mask[0] = IMX95_PCIE_DEVICE_TYPE, + .core_reset = imx95_pcie_core_reset, .init_phy = imx95_pcie_init_phy, }, [IMX8MQ_EP] = { @@ -1792,6 +1833,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .mode_off[0] = IMX95_PE0_GEN_CTRL_1, .mode_mask[0] = IMX95_PCIE_DEVICE_TYPE, .init_phy = imx95_pcie_init_phy, + .core_reset = imx95_pcie_core_reset, .epc_features = &imx95_pcie_epc_features, .mode = DW_PCIE_EP_TYPE, }, -- cgit v1.2.3 From ce0c43e855c7f652b6351110aaaabf9b521debd7 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:11 +0800 Subject: PCI: imx6: Add workaround for errata ERR051624 ERR051624: The Controller Without Vaux Cannot Exit L23 Ready Through Beacon or PERST# De-assertion When the auxiliary power is not available, the controller cannot exit from L23 Ready with beacon or PERST# de-assertion when main power is not removed. So the workaround is to set SS_RW_REG_1[SYS_AUX_PWR_DET] to 1. This workaround is required irrespective of whether Vaux is supplied to the link partner or not. Signed-off-by: Richard Zhu [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250416081314.3929794-5-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 7c60b712480a..016b86add959 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -48,6 +48,8 @@ #define IMX95_PCIE_SS_RW_REG_0 0xf0 #define IMX95_PCIE_REF_CLKEN BIT(23) #define IMX95_PCIE_PHY_CR_PARA_SEL BIT(9) +#define IMX95_PCIE_SS_RW_REG_1 0xf4 +#define IMX95_PCIE_SYS_AUX_PWR_DET BIT(31) #define IMX95_PE0_GEN_CTRL_1 0x1050 #define IMX95_PCIE_DEVICE_TYPE GENMASK(3, 0) @@ -227,6 +229,19 @@ static unsigned int imx_pcie_grp_offset(const struct imx_pcie *imx_pcie) static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie) { + /* + * ERR051624: The Controller Without Vaux Cannot Exit L23 Ready + * Through Beacon or PERST# De-assertion + * + * When the auxiliary power is not available, the controller + * cannot exit from L23 Ready with beacon or PERST# de-assertion + * when main power is not removed. + * + * Workaround: Set SS_RW_REG_1[SYS_AUX_PWR_DET] to 1. + */ + regmap_set_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1, + IMX95_PCIE_SYS_AUX_PWR_DET); + regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0, IMX95_PCIE_PHY_CR_PARA_SEL, -- cgit v1.2.3 From 744a1c20ce933dcaca0f161fe7da115902a2f343 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:12 +0800 Subject: PCI: imx6: Add workaround for errata ERR051586 ERR051586: Compliance with 8GT/s Receiver Impedance ECN. The default value of GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL] is 1 which makes receiver non-compliant with the ZRX-DC parameter for 2.5 GT/s when operating at 8 GT/s or higher. It causes unnecessary timeout in L1. So the workaround is to set GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL] to 0. Add this workaround in the dw_pcie_host_ops::post_init() callback for i.MX95 platforms. Signed-off-by: Richard Zhu [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250416081314.3929794-6-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 016b86add959..7dcc9d88740d 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -110,6 +110,7 @@ enum imx_pcie_variants { */ #define IMX_PCIE_FLAG_BROKEN_SUSPEND BIT(9) #define IMX_PCIE_FLAG_HAS_LUT BIT(10) +#define IMX_PCIE_FLAG_8GT_ECN_ERR051586 BIT(11) #define imx_check_flag(pci, val) (pci->drvdata->flags & val) @@ -1256,6 +1257,32 @@ static void imx_pcie_host_exit(struct dw_pcie_rp *pp) regulator_disable(imx_pcie->vpcie); } +static void imx_pcie_host_post_init(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct imx_pcie *imx_pcie = to_imx_pcie(pci); + u32 val; + + if (imx_pcie->drvdata->flags & IMX_PCIE_FLAG_8GT_ECN_ERR051586) { + /* + * ERR051586: Compliance with 8GT/s Receiver Impedance ECN + * + * The default value of GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL] + * is 1 which makes receiver non-compliant with the ZRX-DC + * parameter for 2.5 GT/s when operating at 8 GT/s or higher. + * It causes unnecessary timeout in L1. + * + * Workaround: Program GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL] + * to 0. + */ + dw_pcie_dbi_ro_wr_en(pci); + val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); + val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; + dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); + dw_pcie_dbi_ro_wr_dis(pci); + } +} + /* * In old DWC implementations, PCIE_ATU_INHIBIT_PAYLOAD in iATU Ctrl2 * register is reserved, so the generic DWC implementation of sending the @@ -1281,6 +1308,7 @@ static const struct dw_pcie_host_ops imx_pcie_host_ops = { static const struct dw_pcie_host_ops imx_pcie_host_dw_pme_ops = { .init = imx_pcie_host_init, .deinit = imx_pcie_host_exit, + .post_init = imx_pcie_host_post_init, }; static const struct dw_pcie_ops dw_pcie_ops = { @@ -1392,6 +1420,7 @@ static int imx_add_pcie_ep(struct imx_pcie *imx_pcie, dev_err(dev, "failed to initialize endpoint\n"); return ret; } + imx_pcie_host_post_init(pp); ret = dw_pcie_ep_init_registers(ep); if (ret) { @@ -1789,6 +1818,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .variant = IMX95, .flags = IMX_PCIE_FLAG_HAS_SERDES | IMX_PCIE_FLAG_HAS_LUT | + IMX_PCIE_FLAG_8GT_ECN_ERR051586 | IMX_PCIE_FLAG_SUPPORTS_SUSPEND, .ltssm_off = IMX95_PE0_GEN_CTRL_3, .ltssm_mask = IMX95_PCIE_LTSSM_EN, @@ -1842,6 +1872,7 @@ static const struct imx_pcie_drvdata drvdata[] = { [IMX95_EP] = { .variant = IMX95_EP, .flags = IMX_PCIE_FLAG_HAS_SERDES | + IMX_PCIE_FLAG_8GT_ECN_ERR051586 | IMX_PCIE_FLAG_SUPPORT_64BIT, .ltssm_off = IMX95_PE0_GEN_CTRL_3, .ltssm_mask = IMX95_PCIE_LTSSM_EN, -- cgit v1.2.3 From 047e8b6b3bc3e6b25bfa12896a39d9fb82b591be Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:13 +0800 Subject: PCI: imx6: Add PLL lock check for i.MX95 SoC PLL lock is required to ensure that the PLL clock is stable before enabling the controller in i.MX95 SoC. Signed-off-by: Richard Zhu [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250416081314.3929794-7-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 7dcc9d88740d..4cff66794990 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -45,6 +45,9 @@ #define IMX95_PCIE_PHY_GEN_CTRL 0x0 #define IMX95_PCIE_REF_USE_PAD BIT(17) +#define IMX95_PCIE_PHY_MPLLA_CTRL 0x10 +#define IMX95_PCIE_PHY_MPLL_STATE BIT(30) + #define IMX95_PCIE_SS_RW_REG_0 0xf0 #define IMX95_PCIE_REF_CLKEN BIT(23) #define IMX95_PCIE_PHY_CR_PARA_SEL BIT(9) @@ -132,6 +135,7 @@ struct imx_pcie_drvdata { int (*init_phy)(struct imx_pcie *pcie); int (*enable_ref_clk)(struct imx_pcie *pcie, bool enable); int (*core_reset)(struct imx_pcie *pcie, bool assert); + int (*wait_pll_lock)(struct imx_pcie *pcie); const struct dw_pcie_host_ops *ops; }; @@ -479,6 +483,23 @@ static void imx7d_pcie_wait_for_phy_pll_lock(struct imx_pcie *imx_pcie) dev_err(dev, "PCIe PLL lock timeout\n"); } +static int imx95_pcie_wait_for_phy_pll_lock(struct imx_pcie *imx_pcie) +{ + u32 val; + struct device *dev = imx_pcie->pci->dev; + + if (regmap_read_poll_timeout(imx_pcie->iomuxc_gpr, + IMX95_PCIE_PHY_MPLLA_CTRL, val, + val & IMX95_PCIE_PHY_MPLL_STATE, + PHY_PLL_LOCK_WAIT_USLEEP_MAX, + PHY_PLL_LOCK_WAIT_TIMEOUT)) { + dev_err(dev, "PCIe PLL lock timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int imx_setup_phy_mpll(struct imx_pcie *imx_pcie) { unsigned long phy_rate = 0; @@ -1225,6 +1246,12 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp) goto err_phy_off; } + if (imx_pcie->drvdata->wait_pll_lock) { + ret = imx_pcie->drvdata->wait_pll_lock(imx_pcie); + if (ret < 0) + goto err_phy_off; + } + imx_setup_phy_mpll(imx_pcie); return 0; @@ -1826,6 +1853,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .mode_mask[0] = IMX95_PCIE_DEVICE_TYPE, .core_reset = imx95_pcie_core_reset, .init_phy = imx95_pcie_init_phy, + .wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock, }, [IMX8MQ_EP] = { .variant = IMX8MQ_EP, @@ -1880,6 +1908,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .mode_mask[0] = IMX95_PCIE_DEVICE_TYPE, .init_phy = imx95_pcie_init_phy, .core_reset = imx95_pcie_core_reset, + .wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock, .epc_features = &imx95_pcie_epc_features, .mode = DW_PCIE_EP_TYPE, }, -- cgit v1.2.3 From e4d66131caaf18d7c3c69914513f4be0519ddaaf Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:14 +0800 Subject: PCI: imx6: Save and restore the LUT setting during suspend/resume for i.MX95 SoC The look up table (LUT) setting would be lost during the PCIe suspend on i.MX95 SoC. So to ensure proper functionality after resume, save it during suspend and restore it while resuming. Fixes: 9d6b1bd6b3c8 ("PCI: imx6: Add i.MX8MQ, i.MX8Q and i.MX95 PM support") Signed-off-by: Richard Zhu [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250416081314.3929794-8-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 4cff66794990..5a38cfaf989b 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -139,6 +139,11 @@ struct imx_pcie_drvdata { const struct dw_pcie_host_ops *ops; }; +struct imx_lut_data { + u32 data1; + u32 data2; +}; + struct imx_pcie { struct dw_pcie *pci; struct gpio_desc *reset_gpiod; @@ -158,6 +163,8 @@ struct imx_pcie { struct regulator *vph; void __iomem *phy_base; + /* LUT data for pcie */ + struct imx_lut_data luts[IMX95_MAX_LUT]; /* power domain for pcie */ struct device *pd_pcie; /* power domain for pcie phy */ @@ -1484,6 +1491,42 @@ static void imx_pcie_msi_save_restore(struct imx_pcie *imx_pcie, bool save) } } +static void imx_pcie_lut_save(struct imx_pcie *imx_pcie) +{ + u32 data1, data2; + int i; + + for (i = 0; i < IMX95_MAX_LUT; i++) { + regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_ACSCTRL, + IMX95_PEO_LUT_RWA | i); + regmap_read(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA1, &data1); + regmap_read(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA2, &data2); + if (data1 & IMX95_PE0_LUT_VLD) { + imx_pcie->luts[i].data1 = data1; + imx_pcie->luts[i].data2 = data2; + } else { + imx_pcie->luts[i].data1 = 0; + imx_pcie->luts[i].data2 = 0; + } + } +} + +static void imx_pcie_lut_restore(struct imx_pcie *imx_pcie) +{ + int i; + + for (i = 0; i < IMX95_MAX_LUT; i++) { + if ((imx_pcie->luts[i].data1 & IMX95_PE0_LUT_VLD) == 0) + continue; + + regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA1, + imx_pcie->luts[i].data1); + regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA2, + imx_pcie->luts[i].data2); + regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_ACSCTRL, i); + } +} + static int imx_pcie_suspend_noirq(struct device *dev) { struct imx_pcie *imx_pcie = dev_get_drvdata(dev); @@ -1492,6 +1535,8 @@ static int imx_pcie_suspend_noirq(struct device *dev) return 0; imx_pcie_msi_save_restore(imx_pcie, true); + if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT)) + imx_pcie_lut_save(imx_pcie); if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_BROKEN_SUSPEND)) { /* * The minimum for a workaround would be to set PERST# and to @@ -1536,6 +1581,8 @@ static int imx_pcie_resume_noirq(struct device *dev) if (ret) return ret; } + if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT)) + imx_pcie_lut_restore(imx_pcie); imx_pcie_msi_save_restore(imx_pcie, false); return 0; -- cgit v1.2.3 From c2f61b8479b2abcd9e20f8bd4c46e54bb7f5286f Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Sun, 27 Apr 2025 20:53:14 +0800 Subject: PCI: dw-rockchip: Remove unused PCIE_CLIENT_GENERAL_DEBUG definition The PCIE_CLIENT_GENERAL_DEBUG register offset is defined but never used in the driver. It's presence adds noise to the register map. Remove this unused definition to keep the register list minimal and aligned with actual hardware usage. Signed-off-by: Hans Zhang <18255117159@163.com> Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250427125316.99627-2-18255117159@163.com --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index 7790a9f33e48..e7d33d545d5b 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -47,7 +47,6 @@ #define PCIE_CLIENT_GENERAL_CONTROL 0x0 #define PCIE_CLIENT_INTR_STATUS_LEGACY 0x8 #define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c -#define PCIE_CLIENT_GENERAL_DEBUG 0x104 #define PCIE_CLIENT_HOT_RESET_CTRL 0x180 #define PCIE_CLIENT_LTSSM_STATUS 0x300 #define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) -- cgit v1.2.3 From ae8ed2b091ee8bd92da365d3332eebf159de8e0f Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Sun, 27 Apr 2025 20:53:15 +0800 Subject: PCI: dw-rockchip: Reorganize register and bitfield definitions Register definitions were scattered with ambiguous names (e.g., PCIE_RDLH_LINK_UP_CHGED in PCIE_CLIENT_INTR_STATUS_MISC) and lacked hierarchical grouping. Group registers and their associated bitfields logically. This improves maintainability and aligns the code with hardware documentation. Signed-off-by: Hans Zhang <18255117159@163.com> Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250427125316.99627-3-18255117159@163.com --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 49 +++++++++++++++++---------- 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index e7d33d545d5b..a778f4f61595 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -33,24 +33,37 @@ #define to_rockchip_pcie(x) dev_get_drvdata((x)->dev) -#define PCIE_CLIENT_RC_MODE HIWORD_UPDATE_BIT(0x40) -#define PCIE_CLIENT_EP_MODE HIWORD_UPDATE(0xf0, 0x0) -#define PCIE_CLIENT_ENABLE_LTSSM HIWORD_UPDATE_BIT(0xc) -#define PCIE_CLIENT_DISABLE_LTSSM HIWORD_UPDATE(0x0c, 0x8) -#define PCIE_CLIENT_INTR_STATUS_MISC 0x10 -#define PCIE_CLIENT_INTR_MASK_MISC 0x24 -#define PCIE_SMLH_LINKUP BIT(16) -#define PCIE_RDLH_LINKUP BIT(17) -#define PCIE_LINKUP (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP) -#define PCIE_RDLH_LINK_UP_CHGED BIT(1) -#define PCIE_LINK_REQ_RST_NOT_INT BIT(2) -#define PCIE_CLIENT_GENERAL_CONTROL 0x0 +/* General Control Register */ +#define PCIE_CLIENT_GENERAL_CON 0x0 +#define PCIE_CLIENT_RC_MODE HIWORD_UPDATE_BIT(0x40) +#define PCIE_CLIENT_EP_MODE HIWORD_UPDATE(0xf0, 0x0) +#define PCIE_CLIENT_ENABLE_LTSSM HIWORD_UPDATE_BIT(0xc) +#define PCIE_CLIENT_DISABLE_LTSSM HIWORD_UPDATE(0x0c, 0x8) + +/* Interrupt Status Register Related to Legacy Interrupt */ #define PCIE_CLIENT_INTR_STATUS_LEGACY 0x8 + +/* Interrupt Status Register Related to Miscellaneous Operation */ +#define PCIE_CLIENT_INTR_STATUS_MISC 0x10 +#define PCIE_RDLH_LINK_UP_CHGED BIT(1) +#define PCIE_LINK_REQ_RST_NOT_INT BIT(2) + +/* Interrupt Mask Register Related to Legacy Interrupt */ #define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c + +/* Interrupt Mask Register Related to Miscellaneous Operation */ +#define PCIE_CLIENT_INTR_MASK_MISC 0x24 + +/* Hot Reset Control Register */ #define PCIE_CLIENT_HOT_RESET_CTRL 0x180 +#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) + +/* LTSSM Status Register */ #define PCIE_CLIENT_LTSSM_STATUS 0x300 -#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) -#define PCIE_LTSSM_STATUS_MASK GENMASK(5, 0) +#define PCIE_SMLH_LINKUP BIT(16) +#define PCIE_RDLH_LINKUP BIT(17) +#define PCIE_LINKUP (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP) +#define PCIE_LTSSM_STATUS_MASK GENMASK(5, 0) struct rockchip_pcie { struct dw_pcie pci; @@ -161,13 +174,13 @@ static u32 rockchip_pcie_get_ltssm(struct rockchip_pcie *rockchip) static void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip) { rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_ENABLE_LTSSM, - PCIE_CLIENT_GENERAL_CONTROL); + PCIE_CLIENT_GENERAL_CON); } static void rockchip_pcie_disable_ltssm(struct rockchip_pcie *rockchip) { rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_DISABLE_LTSSM, - PCIE_CLIENT_GENERAL_CONTROL); + PCIE_CLIENT_GENERAL_CON); } static int rockchip_pcie_link_up(struct dw_pcie *pci) @@ -516,7 +529,7 @@ static int rockchip_pcie_configure_rc(struct platform_device *pdev, rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_RC_MODE, - PCIE_CLIENT_GENERAL_CONTROL); + PCIE_CLIENT_GENERAL_CON); pp = &rockchip->pci.pp; pp->ops = &rockchip_pcie_host_ops; @@ -562,7 +575,7 @@ static int rockchip_pcie_configure_ep(struct platform_device *pdev, rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_EP_MODE, - PCIE_CLIENT_GENERAL_CONTROL); + PCIE_CLIENT_GENERAL_CON); rockchip->pci.ep.ops = &rockchip_pcie_ep_ops; rockchip->pci.ep.page_size = SZ_64K; -- cgit v1.2.3 From 5e5a3bf48eed8d90bc5c5b710466f24663231f0a Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Sun, 27 Apr 2025 20:53:16 +0800 Subject: PCI: dw-rockchip: Use rockchip_pcie_link_up() to check link up instead of open coding Some of the callers of rockchip_pcie_link_up() are open coding the rockchip_pcie_link_up() function, leading to code duplication. So switch them to use rockchip_pcie_link_up() function. Also, use the FIELD_GET() macro to simplify the link up check in rockchip_pcie_link_up(). Signed-off-by: Hans Zhang <18255117159@163.com> [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250427125316.99627-4-18255117159@163.com --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index a778f4f61595..bfc47dab32e5 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -8,6 +8,7 @@ * Author: Simon Xue */ +#include #include #include #include @@ -60,9 +61,8 @@ /* LTSSM Status Register */ #define PCIE_CLIENT_LTSSM_STATUS 0x300 -#define PCIE_SMLH_LINKUP BIT(16) -#define PCIE_RDLH_LINKUP BIT(17) -#define PCIE_LINKUP (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP) +#define PCIE_LINKUP 0x3 +#define PCIE_LINKUP_MASK GENMASK(17, 16) #define PCIE_LTSSM_STATUS_MASK GENMASK(5, 0) struct rockchip_pcie { @@ -188,10 +188,7 @@ static int rockchip_pcie_link_up(struct dw_pcie *pci) struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); u32 val = rockchip_pcie_get_ltssm(rockchip); - if ((val & PCIE_LINKUP) == PCIE_LINKUP) - return 1; - - return 0; + return FIELD_GET(PCIE_LINKUP_MASK, val) == PCIE_LINKUP; } static void rockchip_pcie_enable_l0s(struct dw_pcie *pci) @@ -450,7 +447,7 @@ static irqreturn_t rockchip_pcie_rc_sys_irq_thread(int irq, void *arg) struct dw_pcie *pci = &rockchip->pci; struct dw_pcie_rp *pp = &pci->pp; struct device *dev = pci->dev; - u32 reg, val; + u32 reg; reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); @@ -459,8 +456,7 @@ static irqreturn_t rockchip_pcie_rc_sys_irq_thread(int irq, void *arg) dev_dbg(dev, "LTSSM_STATUS: %#x\n", rockchip_pcie_get_ltssm(rockchip)); if (reg & PCIE_RDLH_LINK_UP_CHGED) { - val = rockchip_pcie_get_ltssm(rockchip); - if ((val & PCIE_LINKUP) == PCIE_LINKUP) { + if (rockchip_pcie_link_up(pci)) { dev_dbg(dev, "Received Link up event. Starting enumeration!\n"); /* Rescan the bus to enumerate endpoint devices */ pci_lock_rescan_remove(); @@ -477,7 +473,7 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) struct rockchip_pcie *rockchip = arg; struct dw_pcie *pci = &rockchip->pci; struct device *dev = pci->dev; - u32 reg, val; + u32 reg; reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); @@ -491,8 +487,7 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) } if (reg & PCIE_RDLH_LINK_UP_CHGED) { - val = rockchip_pcie_get_ltssm(rockchip); - if ((val & PCIE_LINKUP) == PCIE_LINKUP) { + if (rockchip_pcie_link_up(pci)) { dev_dbg(dev, "link up\n"); dw_pcie_ep_linkup(&pci->ep); } -- cgit v1.2.3 From 286ed198b899739862456f451eda884558526a9d Mon Sep 17 00:00:00 2001 From: Diederik de Haas Date: Thu, 17 Apr 2025 16:21:18 +0200 Subject: PCI: dw-rockchip: Fix PHY function call sequence in rockchip_pcie_phy_deinit() The documentation for the phy_power_off() function explicitly says that it must be called before phy_exit(). Hence, follow the same rule in rockchip_pcie_phy_deinit(). Fixes: 0e898eb8df4e ("PCI: rockchip-dwc: Add Rockchip RK356X host controller driver") Signed-off-by: Diederik de Haas [mani: commit message change] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Dragan Simic Acked-by: Shawn Lin Cc: stable@vger.kernel.org # v5.15+ Link: https://patch.msgid.link/20250417142138.1377451-1-didi.debian@cknow.org --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index bfc47dab32e5..3c6ab71c996e 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -431,8 +431,8 @@ static int rockchip_pcie_phy_init(struct rockchip_pcie *rockchip) static void rockchip_pcie_phy_deinit(struct rockchip_pcie *rockchip) { - phy_exit(rockchip->phy); phy_power_off(rockchip->phy); + phy_exit(rockchip->phy); } static const struct dw_pcie_ops dw_pcie_ops = { -- cgit v1.2.3 From af3c6eacce0c464f28fe0e3d365b3860aba07931 Mon Sep 17 00:00:00 2001 From: Wenbin Yao Date: Tue, 22 Apr 2025 18:36:23 +0800 Subject: PCI: dwc: Make link training more robust by setting PORT_LOGIC_LINK_WIDTH to one lane As per DWC PCIe registers description 4.30a, section 1.13.43, NUM_OF_LANES named as PORT_LOGIC_LINK_WIDTH in PCIe DWC driver, is referred to as the "Predetermined Number of Lanes" in PCIe r6.0, sec 4.2.7.2.1, which explains the conditions required to enter Polling.Configuration: Next state is Polling.Configuration after at least 1024 TS1 Ordered Sets were transmitted, and all Lanes that detected a Receiver during Detect receive eight consecutive training sequences ... Otherwise, after a 24 ms timeout the next state is: Polling.Configuration if, (i) Any Lane, which detected a Receiver during Detect, received eight consecutive training sequences ... and a minimum of 1024 TS1 Ordered Sets are transmitted after receiving one TS1 or TS2 Ordered Set. And (ii) At least a predetermined set of Lanes that detected a Receiver during Detect have detected an exit from Electrical Idle at least once since entering Polling.Active. Note: This may prevent one or more bad Receivers or Transmitters from holding up a valid Link from being configured, and allow for additional training in Polling.Configuration. The exact set of predetermined Lanes is implementation specific. Note: Any Lane that receives eight consecutive TS1 or TS2 Ordered Sets should have detected an exit from Electrical Idle at least once since entering Polling.Active. In a PCIe link supporting multiple lanes, if PORT_LOGIC_LINK_WIDTH is set to lane width the hardware supports, all lanes that detect a receiver during the Detect phase must receive eight consecutive training sequences. Otherwise, LTSSM will not enter Polling.Configuration and link training will fail. Therefore, always set PORT_LOGIC_LINK_WIDTH to 1, regardless of the number of lanes the port actually supports, to make link up more robust. This setting will not affect the intended link width if all lanes are functional. Additionally, the link can still be established with at least one lane if other lanes are faulty. Co-developed-by: Qiang Yu Signed-off-by: Qiang Yu Signed-off-by: Wenbin Yao [mani: subject change] Signed-off-by: Manivannan Sadhasivam [bhelgaas: update PCIe spec citation, format quote] Signed-off-by: Bjorn Helgaas Tested-by: Niklas Cassel Link: https://patch.msgid.link/20250422103623.462277-1-quic_wenbyao@quicinc.com --- drivers/pci/controller/dwc/pcie-designware.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 97d76d3dc066..be348b341e3c 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -797,22 +797,19 @@ static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes) /* Set link width speed control register */ lwsc = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); lwsc &= ~PORT_LOGIC_LINK_WIDTH_MASK; + lwsc |= PORT_LOGIC_LINK_WIDTH_1_LANES; switch (num_lanes) { case 1: plc |= PORT_LINK_MODE_1_LANES; - lwsc |= PORT_LOGIC_LINK_WIDTH_1_LANES; break; case 2: plc |= PORT_LINK_MODE_2_LANES; - lwsc |= PORT_LOGIC_LINK_WIDTH_2_LANES; break; case 4: plc |= PORT_LINK_MODE_4_LANES; - lwsc |= PORT_LOGIC_LINK_WIDTH_4_LANES; break; case 8: plc |= PORT_LINK_MODE_8_LANES; - lwsc |= PORT_LOGIC_LINK_WIDTH_8_LANES; break; default: dev_err(pci->dev, "num-lanes %u: invalid value\n", num_lanes); -- cgit v1.2.3 From ed798ff1c52f6fe232ce2e24e68fb63f5470ab97 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Mon, 7 Apr 2025 20:43:31 +0800 Subject: PCI: tegra194: Create debugfs directory only when CONFIG_PCIEASPM is enabled Previously, the debugfs directory was unconditionally created in tegra_pcie_config_rp() regardless of the CONFIG_PCIEASPM setting. This led to unnecessary directory creation when ASPM support was disabled since only ASPM state count was exposed through debugfs. Hence, move the debugfs directory creation into init_debugfs() which is conditionally compiled based on CONFIG_PCIEASPM. This ensures that both the directory and 'aspm_state_cnt' entry are only created when ASPM is enabled and avoids cluttering debugfs with empty directories when ASPM is disabled. Signed-off-by: Hans Zhang <18255117159@163.com> [mani: subject and description change] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Christophe JAILLET Link: https://patch.msgid.link/20250407124331.69459-1-18255117159@163.com --- drivers/pci/controller/dwc/pcie-tegra194.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 5103995cd6c7..bc419688527a 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -713,7 +713,16 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie) static void init_debugfs(struct tegra_pcie_dw *pcie) { - debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt", pcie->debugfs, + struct device *dev = pcie->dev; + char *name; + + name = devm_kasprintf(dev, GFP_KERNEL, "%pOFP", dev->of_node); + if (!name) + return; + + pcie->debugfs = debugfs_create_dir(name, NULL); + + debugfs_create_devm_seqfile(dev, "aspm_state_cnt", pcie->debugfs, aspm_state_cnt); } #else @@ -1634,7 +1643,6 @@ static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) { struct device *dev = pcie->dev; - char *name; int ret; pm_runtime_enable(dev); @@ -1664,13 +1672,6 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) goto fail_host_init; } - name = devm_kasprintf(dev, GFP_KERNEL, "%pOFP", dev->of_node); - if (!name) { - ret = -ENOMEM; - goto fail_host_init; - } - - pcie->debugfs = debugfs_create_dir(name, NULL); init_debugfs(pcie); return ret; -- cgit v1.2.3 From 2612378d442aad23448053c47f34eb17f6209e67 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Mon, 28 Apr 2025 20:42:30 +0800 Subject: PCI: dwc: ep: Use FIELD_GET() where applicable Use FIELD_GET() to simplify the code extracting the register values. No functional change intended. Signed-off-by: Hans Zhang <18255117159@163.com> [mani: commit message fixup] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Link: https://patch.msgid.link/20250428124230.112648-1-18255117159@163.com --- drivers/pci/controller/dwc/pcie-designware-ep.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 1a0bf9341542..f3daf46b5e63 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -256,11 +256,11 @@ static unsigned int dw_pcie_ep_get_rebar_offset(struct dw_pcie *pci, return offset; reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); - nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >> PCI_REBAR_CTRL_NBAR_SHIFT; + nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, reg); for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) { reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); - bar_index = reg & PCI_REBAR_CTRL_BAR_IDX; + bar_index = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, reg); if (bar_index == bar) return offset; } @@ -875,8 +875,7 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) if (offset) { reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); - nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >> - PCI_REBAR_CTRL_NBAR_SHIFT; + nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, reg); /* * PCIe r6.0, sec 7.8.6.2 require us to support at least one @@ -897,7 +896,7 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) * is why RESBAR_CAP_REG is written here. */ val = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); - bar = val & PCI_REBAR_CTRL_BAR_IDX; + bar = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, val); if (ep->epf_bar[bar]) pci_epc_bar_size_to_rebar_cap(ep->epf_bar[bar]->size, &val); else -- cgit v1.2.3 From f46bfb1d3c6a601caad90eb3c11a1e1e17cccb1a Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Sun, 11 May 2025 00:07:08 +0800 Subject: PCI: dwc: Return bool from link up check PCIe link status check is supposed to return a boolean to indicate whether the link is up or not. So, modify the link_up callbacks and dw_pcie_link_up() function to return bool instead of int. Signed-off-by: Hans Zhang <18255117159@163.com> [mani: commit message reword] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Link: https://patch.msgid.link/20250510160710.392122-2-18255117159@163.com --- drivers/pci/controller/dwc/pci-dra7xx.c | 4 ++-- drivers/pci/controller/dwc/pci-exynos.c | 4 ++-- drivers/pci/controller/dwc/pci-keystone.c | 5 ++--- drivers/pci/controller/dwc/pci-meson.c | 6 +++--- drivers/pci/controller/dwc/pcie-armada8k.c | 6 +++--- drivers/pci/controller/dwc/pcie-designware.c | 2 +- drivers/pci/controller/dwc/pcie-designware.h | 4 ++-- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 2 +- drivers/pci/controller/dwc/pcie-histb.c | 9 +++------ drivers/pci/controller/dwc/pcie-keembay.c | 2 +- drivers/pci/controller/dwc/pcie-kirin.c | 7 ++----- drivers/pci/controller/dwc/pcie-qcom-ep.c | 2 +- drivers/pci/controller/dwc/pcie-qcom.c | 4 ++-- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 +- drivers/pci/controller/dwc/pcie-spear13xx.c | 7 ++----- drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++-- drivers/pci/controller/dwc/pcie-uniphier.c | 2 +- drivers/pci/controller/dwc/pcie-visconti.c | 4 ++-- 18 files changed, 33 insertions(+), 43 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 33d6bf460ffe..58f7d04ff37f 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -118,12 +118,12 @@ static u64 dra7xx_pcie_cpu_addr_fixup(struct dw_pcie *pci, u64 cpu_addr) return cpu_addr & DRA7XX_CPU_TO_BUS_ADDR; } -static int dra7xx_pcie_link_up(struct dw_pcie *pci) +static bool dra7xx_pcie_link_up(struct dw_pcie *pci) { struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); u32 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS); - return !!(reg & LINK_UP); + return reg & LINK_UP; } static void dra7xx_pcie_stop_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index ace736b025b1..1f0e98d07109 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -209,12 +209,12 @@ static struct pci_ops exynos_pci_ops = { .write = exynos_pcie_wr_own_conf, }; -static int exynos_pcie_link_up(struct dw_pcie *pci) +static bool exynos_pcie_link_up(struct dw_pcie *pci) { struct exynos_pcie *ep = to_exynos_pcie(pci); u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_RDLH_LINKUP); - return (val & PCIE_ELBI_XMLH_LINKUP); + return val & PCIE_ELBI_XMLH_LINKUP; } static int exynos_pcie_host_init(struct dw_pcie_rp *pp) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 76a37368ae4f..968464530e3d 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -492,13 +492,12 @@ static struct pci_ops ks_pcie_ops = { * @pci: A pointer to the dw_pcie structure which holds the DesignWare PCIe host * controller driver information. */ -static int ks_pcie_link_up(struct dw_pcie *pci) +static bool ks_pcie_link_up(struct dw_pcie *pci) { u32 val; val = dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0); - val &= PORT_LOGIC_LTSSM_STATE_MASK; - return (val == PORT_LOGIC_LTSSM_STATE_L0); + return (val & PORT_LOGIC_LTSSM_STATE_MASK) == PORT_LOGIC_LTSSM_STATE_L0; } static void ks_pcie_stop_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index db9482a113e9..787469d1b396 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -335,7 +335,7 @@ static struct pci_ops meson_pci_ops = { .write = pci_generic_config_write, }; -static int meson_pcie_link_up(struct dw_pcie *pci) +static bool meson_pcie_link_up(struct dw_pcie *pci) { struct meson_pcie *mp = to_meson_pcie(pci); struct device *dev = pci->dev; @@ -363,7 +363,7 @@ static int meson_pcie_link_up(struct dw_pcie *pci) dev_dbg(dev, "speed_okay\n"); if (smlh_up && rdlh_up && ltssm_up && speed_okay) - return 1; + return true; cnt++; @@ -371,7 +371,7 @@ static int meson_pcie_link_up(struct dw_pcie *pci) } while (cnt < WAIT_LINKUP_TIMEOUT); dev_err(dev, "error: wait linkup timeout\n"); - return 0; + return false; } static int meson_pcie_host_init(struct dw_pcie_rp *pp) diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c index b5c599ccaacf..c2650fd0d458 100644 --- a/drivers/pci/controller/dwc/pcie-armada8k.c +++ b/drivers/pci/controller/dwc/pcie-armada8k.c @@ -139,7 +139,7 @@ static int armada8k_pcie_setup_phys(struct armada8k_pcie *pcie) return ret; } -static int armada8k_pcie_link_up(struct dw_pcie *pci) +static bool armada8k_pcie_link_up(struct dw_pcie *pci) { u32 reg; u32 mask = PCIE_GLB_STS_RDLH_LINK_UP | PCIE_GLB_STS_PHY_LINK_UP; @@ -147,10 +147,10 @@ static int armada8k_pcie_link_up(struct dw_pcie *pci) reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_STATUS_REG); if ((reg & mask) == mask) - return 1; + return true; dev_dbg(pci->dev, "No link detected (Global-Status: 0x%08x).\n", reg); - return 0; + return false; } static int armada8k_pcie_start_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 97d76d3dc066..b3615d125942 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -711,7 +711,7 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci) } EXPORT_SYMBOL_GPL(dw_pcie_wait_for_link); -int dw_pcie_link_up(struct dw_pcie *pci) +bool dw_pcie_link_up(struct dw_pcie *pci) { u32 val; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 56aafdbcdaca..4dd16aa4b39e 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -462,7 +462,7 @@ struct dw_pcie_ops { size_t size, u32 val); void (*write_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg, size_t size, u32 val); - int (*link_up)(struct dw_pcie *pcie); + bool (*link_up)(struct dw_pcie *pcie); enum dw_pcie_ltssm (*get_ltssm)(struct dw_pcie *pcie); int (*start_link)(struct dw_pcie *pcie); void (*stop_link)(struct dw_pcie *pcie); @@ -537,7 +537,7 @@ int dw_pcie_write(void __iomem *addr, int size, u32 val); u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size); void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val); void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val); -int dw_pcie_link_up(struct dw_pcie *pci); +bool dw_pcie_link_up(struct dw_pcie *pci); void dw_pcie_upconfig_setup(struct dw_pcie *pci); int dw_pcie_wait_for_link(struct dw_pcie *pci); int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index 3c6ab71c996e..ae171a545df6 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -183,7 +183,7 @@ static void rockchip_pcie_disable_ltssm(struct rockchip_pcie *rockchip) PCIE_CLIENT_GENERAL_CON); } -static int rockchip_pcie_link_up(struct dw_pcie *pci) +static bool rockchip_pcie_link_up(struct dw_pcie *pci) { struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); u32 val = rockchip_pcie_get_ltssm(rockchip); diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index 1f2f4c28a949..a52071589377 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c @@ -151,7 +151,7 @@ static struct pci_ops histb_pci_ops = { .write = histb_pcie_wr_own_conf, }; -static int histb_pcie_link_up(struct dw_pcie *pci) +static bool histb_pcie_link_up(struct dw_pcie *pci) { struct histb_pcie *hipcie = to_histb_pcie(pci); u32 regval; @@ -160,11 +160,8 @@ static int histb_pcie_link_up(struct dw_pcie *pci) regval = histb_pcie_readl(hipcie, PCIE_SYS_STAT0); status = histb_pcie_readl(hipcie, PCIE_SYS_STAT4); status &= PCIE_LTSSM_STATE_MASK; - if ((regval & PCIE_XMLH_LINK_UP) && (regval & PCIE_RDLH_LINK_UP) && - (status == PCIE_LTSSM_STATE_ACTIVE)) - return 1; - - return 0; + return ((regval & PCIE_XMLH_LINK_UP) && (regval & PCIE_RDLH_LINK_UP) && + (status == PCIE_LTSSM_STATE_ACTIVE)); } static int histb_pcie_start_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pcie-keembay.c b/drivers/pci/controller/dwc/pcie-keembay.c index 278205db60a2..67dd3337b447 100644 --- a/drivers/pci/controller/dwc/pcie-keembay.c +++ b/drivers/pci/controller/dwc/pcie-keembay.c @@ -101,7 +101,7 @@ static void keembay_pcie_ltssm_set(struct keembay_pcie *pcie, bool enable) writel(val, pcie->apb_base + PCIE_REGS_PCIE_APP_CNTRL); } -static int keembay_pcie_link_up(struct dw_pcie *pci) +static bool keembay_pcie_link_up(struct dw_pcie *pci) { struct keembay_pcie *pcie = dev_get_drvdata(pci->dev); u32 val; diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index d0e6a3811b00..91559c8b1866 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -586,16 +586,13 @@ static void kirin_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, kirin_pcie_sideband_dbi_w_mode(kirin_pcie, false); } -static int kirin_pcie_link_up(struct dw_pcie *pci) +static bool kirin_pcie_link_up(struct dw_pcie *pci) { struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci); u32 val; regmap_read(kirin_pcie->apb, PCIE_APB_PHY_STATUS0, &val); - if ((val & PCIE_LINKUP_ENABLE) == PCIE_LINKUP_ENABLE) - return 1; - - return 0; + return (val & PCIE_LINKUP_ENABLE) == PCIE_LINKUP_ENABLE; } static int kirin_pcie_start_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 46b1c6d19974..b3f7f42fa852 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -261,7 +261,7 @@ static void qcom_pcie_ep_configure_tcsr(struct qcom_pcie_ep *pcie_ep) } } -static int qcom_pcie_dw_link_up(struct dw_pcie *pci) +static bool qcom_pcie_dw_link_up(struct dw_pcie *pci) { struct qcom_pcie_ep *pcie_ep = to_pcie_ep(pci); u32 reg; diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index dc98ae63362d..ba0dd1717a58 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1221,12 +1221,12 @@ static int qcom_pcie_post_init_2_9_0(struct qcom_pcie *pcie) return 0; } -static int qcom_pcie_link_up(struct dw_pcie *pci) +static bool qcom_pcie_link_up(struct dw_pcie *pci) { u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); u16 val = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA); - return !!(val & PCI_EXP_LNKSTA_DLLLA); + return val & PCI_EXP_LNKSTA_DLLLA; } static int qcom_pcie_host_init(struct dw_pcie_rp *pp) diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index fc872dd35029..ccb94f4a215f 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -87,7 +87,7 @@ struct rcar_gen4_pcie { #define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw) /* Common */ -static int rcar_gen4_pcie_link_up(struct dw_pcie *dw) +static bool rcar_gen4_pcie_link_up(struct dw_pcie *dw) { struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw); u32 val, mask; diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index ff986ced56b2..01794a9d3ad2 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c @@ -110,15 +110,12 @@ static void spear13xx_pcie_enable_interrupts(struct spear13xx_pcie *spear13xx_pc MSI_CTRL_INT, &app_reg->int_mask); } -static int spear13xx_pcie_link_up(struct dw_pcie *pci) +static bool spear13xx_pcie_link_up(struct dw_pcie *pci) { struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci); struct pcie_app_reg __iomem *app_reg = spear13xx_pcie->app_base; - if (readl(&app_reg->app_status_1) & XMLH_LINK_UP) - return 1; - - return 0; + return readl(&app_reg->app_status_1) & XMLH_LINK_UP; } static int spear13xx_pcie_host_init(struct dw_pcie_rp *pp) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 5103995cd6c7..55c47318e65a 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1027,12 +1027,12 @@ retry_link: return 0; } -static int tegra_pcie_dw_link_up(struct dw_pcie *pci) +static bool tegra_pcie_dw_link_up(struct dw_pcie *pci) { struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); u32 val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA); - return !!(val & PCI_EXP_LNKSTA_DLLLA); + return val & PCI_EXP_LNKSTA_DLLLA; } static void tegra_pcie_dw_stop_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c index 5757ca3803c9..9d05b3a0579e 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier.c +++ b/drivers/pci/controller/dwc/pcie-uniphier.c @@ -135,7 +135,7 @@ static int uniphier_pcie_wait_rc(struct uniphier_pcie *pcie) return 0; } -static int uniphier_pcie_link_up(struct dw_pcie *pci) +static bool uniphier_pcie_link_up(struct dw_pcie *pci) { struct uniphier_pcie *pcie = to_uniphier_pcie(pci); u32 val, mask; diff --git a/drivers/pci/controller/dwc/pcie-visconti.c b/drivers/pci/controller/dwc/pcie-visconti.c index 318c278e65c8..cdeac6177143 100644 --- a/drivers/pci/controller/dwc/pcie-visconti.c +++ b/drivers/pci/controller/dwc/pcie-visconti.c @@ -121,13 +121,13 @@ static u32 visconti_mpu_readl(struct visconti_pcie *pcie, u32 reg) return readl_relaxed(pcie->mpu_base + reg); } -static int visconti_pcie_link_up(struct dw_pcie *pci) +static bool visconti_pcie_link_up(struct dw_pcie *pci) { struct visconti_pcie *pcie = dev_get_drvdata(pci->dev); void __iomem *addr = pcie->ulreg_base; u32 val = readl_relaxed(addr + PCIE_UL_REG_V_PHY_ST_02); - return !!(val & PCIE_UL_S_L0); + return val & PCIE_UL_S_L0; } static int visconti_pcie_start_link(struct dw_pcie *pci) -- cgit v1.2.3 From 87a9d0cd6748b658a0c8f8c957c3260ed901f094 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 5 May 2025 19:54:40 +0530 Subject: PCI: dwc: Pass DWC PCIe mode to dwc_pcie_debugfs_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upcoming PTM debugfs interface relies on the DWC PCIe mode to expose the relevant debugfs attributes to userspace. So pass the mode to dwc_pcie_debugfs_init() API from host and ep drivers and save it in 'struct dw_pcie::mode'. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Link: https://patch.msgid.link/20250505-pcie-ptm-v4-2-02d26d51400b@linaro.org --- drivers/pci/controller/dwc/pcie-designware-debugfs.c | 4 +++- drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +- drivers/pci/controller/dwc/pcie-designware-host.c | 2 +- drivers/pci/controller/dwc/pcie-designware.h | 6 ++++-- 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-designware-debugfs.c b/drivers/pci/controller/dwc/pcie-designware-debugfs.c index 9e6f4d00f262..896c387450ca 100644 --- a/drivers/pci/controller/dwc/pcie-designware-debugfs.c +++ b/drivers/pci/controller/dwc/pcie-designware-debugfs.c @@ -651,7 +651,7 @@ void dwc_pcie_debugfs_deinit(struct dw_pcie *pci) debugfs_remove_recursive(pci->debugfs->debug_dir); } -void dwc_pcie_debugfs_init(struct dw_pcie *pci) +void dwc_pcie_debugfs_init(struct dw_pcie *pci, enum dw_pcie_device_mode mode) { char dirname[DWC_DEBUGFS_BUF_MAX]; struct device *dev = pci->dev; @@ -674,4 +674,6 @@ void dwc_pcie_debugfs_init(struct dw_pcie *pci) err); dwc_pcie_ltssm_debugfs_init(pci, dir); + + pci->mode = mode; } diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 1a0bf9341542..6ee14694372c 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -1013,7 +1013,7 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep) dw_pcie_ep_init_non_sticky_registers(pci); - dwc_pcie_debugfs_init(pci); + dwc_pcie_debugfs_init(pci, DW_PCIE_EP_TYPE); return 0; diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index ecc33f6789e3..17c78a334651 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -567,7 +567,7 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) if (pp->ops->post_init) pp->ops->post_init(pp); - dwc_pcie_debugfs_init(pci); + dwc_pcie_debugfs_init(pci, DW_PCIE_RC_TYPE); return 0; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 56aafdbcdaca..7f58c94b5b1e 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -503,6 +503,7 @@ struct dw_pcie { struct gpio_desc *pe_rst; bool suspended; struct debugfs_info *debugfs; + enum dw_pcie_device_mode mode; /* * If iATU input addresses are offset from CPU physical addresses, @@ -871,10 +872,11 @@ dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) #endif #ifdef CONFIG_PCIE_DW_DEBUGFS -void dwc_pcie_debugfs_init(struct dw_pcie *pci); +void dwc_pcie_debugfs_init(struct dw_pcie *pci, enum dw_pcie_device_mode mode); void dwc_pcie_debugfs_deinit(struct dw_pcie *pci); #else -static inline void dwc_pcie_debugfs_init(struct dw_pcie *pci) +static inline void dwc_pcie_debugfs_init(struct dw_pcie *pci, + enum dw_pcie_device_mode mode) { } static inline void dwc_pcie_debugfs_deinit(struct dw_pcie *pci) -- cgit v1.2.3 From 852a1fdd34a82d719bd67a55111f13a72891a868 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 5 May 2025 19:54:41 +0530 Subject: PCI: dwc: Add debugfs support for PTM context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Synopsys Designware PCIe IPs support PTM capability as defined in the PCIe spec r6.0, sec 6.21. The PTM context information is exposed through Vendor Specific Extended Capability (VSEC) registers on supported controller implementation. Hence, add support for exposing these context information to userspace through the debugfs interface for the DWC controllers (both RC and EP). Currently, only Qcom controllers are supported. For adding support for other DWC vendor controllers, dwc_pcie_ptm_vsec_ids[] needs to be extended. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Link: https://patch.msgid.link/20250505-pcie-ptm-v4-3-02d26d51400b@linaro.org --- .../pci/controller/dwc/pcie-designware-debugfs.c | 248 +++++++++++++++++++++ drivers/pci/controller/dwc/pcie-designware.c | 14 ++ drivers/pci/controller/dwc/pcie-designware.h | 18 ++ 3 files changed, 280 insertions(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-designware-debugfs.c b/drivers/pci/controller/dwc/pcie-designware-debugfs.c index 896c387450ca..c67601096c48 100644 --- a/drivers/pci/controller/dwc/pcie-designware-debugfs.c +++ b/drivers/pci/controller/dwc/pcie-designware-debugfs.c @@ -642,11 +642,257 @@ static void dwc_pcie_ltssm_debugfs_init(struct dw_pcie *pci, struct dentry *dir) &dwc_pcie_ltssm_status_ops); } +static int dw_pcie_ptm_check_capability(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + pci->ptm_vsec_offset = dw_pcie_find_ptm_capability(pci); + + return pci->ptm_vsec_offset; +} + +static int dw_pcie_ptm_context_update_write(void *drvdata, u8 mode) +{ + struct dw_pcie *pci = drvdata; + u32 val; + + if (mode == PCIE_PTM_CONTEXT_UPDATE_AUTO) { + val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL); + val |= PTM_REQ_AUTO_UPDATE_ENABLED; + dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val); + } else if (mode == PCIE_PTM_CONTEXT_UPDATE_MANUAL) { + val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL); + val &= ~PTM_REQ_AUTO_UPDATE_ENABLED; + val |= PTM_REQ_START_UPDATE; + dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val); + } else { + return -EINVAL; + } + + return 0; +} + +static int dw_pcie_ptm_context_update_read(void *drvdata, u8 *mode) +{ + struct dw_pcie *pci = drvdata; + u32 val; + + val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL); + if (FIELD_GET(PTM_REQ_AUTO_UPDATE_ENABLED, val)) + *mode = PCIE_PTM_CONTEXT_UPDATE_AUTO; + else + /* + * PTM_REQ_START_UPDATE is a self clearing register bit. So if + * PTM_REQ_AUTO_UPDATE_ENABLED is not set, then it implies that + * manual update is used. + */ + *mode = PCIE_PTM_CONTEXT_UPDATE_MANUAL; + + return 0; +} + +static int dw_pcie_ptm_context_valid_write(void *drvdata, bool valid) +{ + struct dw_pcie *pci = drvdata; + u32 val; + + if (valid) { + val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL); + val |= PTM_RES_CCONTEXT_VALID; + dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val); + } else { + val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL); + val &= ~PTM_RES_CCONTEXT_VALID; + dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val); + } + + return 0; +} + +static int dw_pcie_ptm_context_valid_read(void *drvdata, bool *valid) +{ + struct dw_pcie *pci = drvdata; + u32 val; + + val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL); + *valid = !!FIELD_GET(PTM_RES_CCONTEXT_VALID, val); + + return 0; +} + +static int dw_pcie_ptm_local_clock_read(void *drvdata, u64 *clock) +{ + struct dw_pcie *pci = drvdata; + u32 msb, lsb; + + do { + msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_LOCAL_MSB); + lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_LOCAL_LSB); + } while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_LOCAL_MSB)); + + *clock = ((u64) msb) << 32 | lsb; + + return 0; +} + +static int dw_pcie_ptm_master_clock_read(void *drvdata, u64 *clock) +{ + struct dw_pcie *pci = drvdata; + u32 msb, lsb; + + do { + msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_MASTER_MSB); + lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_MASTER_LSB); + } while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_MASTER_MSB)); + + *clock = ((u64) msb) << 32 | lsb; + + return 0; +} + +static int dw_pcie_ptm_t1_read(void *drvdata, u64 *clock) +{ + struct dw_pcie *pci = drvdata; + u32 msb, lsb; + + do { + msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_MSB); + lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_LSB); + } while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_MSB)); + + *clock = ((u64) msb) << 32 | lsb; + + return 0; +} + +static int dw_pcie_ptm_t2_read(void *drvdata, u64 *clock) +{ + struct dw_pcie *pci = drvdata; + u32 msb, lsb; + + do { + msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_MSB); + lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_LSB); + } while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_MSB)); + + *clock = ((u64) msb) << 32 | lsb; + + return 0; +} + +static int dw_pcie_ptm_t3_read(void *drvdata, u64 *clock) +{ + struct dw_pcie *pci = drvdata; + u32 msb, lsb; + + do { + msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_MSB); + lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_LSB); + } while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_MSB)); + + *clock = ((u64) msb) << 32 | lsb; + + return 0; +} + +static int dw_pcie_ptm_t4_read(void *drvdata, u64 *clock) +{ + struct dw_pcie *pci = drvdata; + u32 msb, lsb; + + do { + msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_MSB); + lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_LSB); + } while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_MSB)); + + *clock = ((u64) msb) << 32 | lsb; + + return 0; +} + +static bool dw_pcie_ptm_context_update_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_EP_TYPE) ? true : false; +} + +static bool dw_pcie_ptm_context_valid_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_RC_TYPE) ? true : false; +} + +static bool dw_pcie_ptm_local_clock_visible(void *drvdata) +{ + /* PTM local clock is always visible */ + return true; +} + +static bool dw_pcie_ptm_master_clock_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_EP_TYPE) ? true : false; +} + +static bool dw_pcie_ptm_t1_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_EP_TYPE) ? true : false; +} + +static bool dw_pcie_ptm_t2_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_RC_TYPE) ? true : false; +} + +static bool dw_pcie_ptm_t3_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_RC_TYPE) ? true : false; +} + +static bool dw_pcie_ptm_t4_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_EP_TYPE) ? true : false; +} + +const struct pcie_ptm_ops dw_pcie_ptm_ops = { + .check_capability = dw_pcie_ptm_check_capability, + .context_update_write = dw_pcie_ptm_context_update_write, + .context_update_read = dw_pcie_ptm_context_update_read, + .context_valid_write = dw_pcie_ptm_context_valid_write, + .context_valid_read = dw_pcie_ptm_context_valid_read, + .local_clock_read = dw_pcie_ptm_local_clock_read, + .master_clock_read = dw_pcie_ptm_master_clock_read, + .t1_read = dw_pcie_ptm_t1_read, + .t2_read = dw_pcie_ptm_t2_read, + .t3_read = dw_pcie_ptm_t3_read, + .t4_read = dw_pcie_ptm_t4_read, + .context_update_visible = dw_pcie_ptm_context_update_visible, + .context_valid_visible = dw_pcie_ptm_context_valid_visible, + .local_clock_visible = dw_pcie_ptm_local_clock_visible, + .master_clock_visible = dw_pcie_ptm_master_clock_visible, + .t1_visible = dw_pcie_ptm_t1_visible, + .t2_visible = dw_pcie_ptm_t2_visible, + .t3_visible = dw_pcie_ptm_t3_visible, + .t4_visible = dw_pcie_ptm_t4_visible, +}; + void dwc_pcie_debugfs_deinit(struct dw_pcie *pci) { if (!pci->debugfs) return; + pcie_ptm_destroy_debugfs(pci->ptm_debugfs); dwc_pcie_rasdes_debugfs_deinit(pci); debugfs_remove_recursive(pci->debugfs->debug_dir); } @@ -676,4 +922,6 @@ void dwc_pcie_debugfs_init(struct dw_pcie *pci, enum dw_pcie_device_mode mode) dwc_pcie_ltssm_debugfs_init(pci, dir); pci->mode = mode; + pci->ptm_debugfs = pcie_ptm_create_debugfs(pci->dev, pci, + &dw_pcie_ptm_ops); } diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 97d76d3dc066..4a9b1ebda679 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -54,6 +54,14 @@ static const char * const dw_pcie_core_rsts[DW_PCIE_NUM_CORE_RSTS] = { [DW_PCIE_PWR_RST] = "pwr", }; +static const struct dwc_pcie_vsec_id dwc_pcie_ptm_vsec_ids[] = { + { .vendor_id = PCI_VENDOR_ID_QCOM, /* EP */ + .vsec_id = 0x03, .vsec_rev = 0x1 }, + { .vendor_id = PCI_VENDOR_ID_QCOM, /* RC */ + .vsec_id = 0x04, .vsec_rev = 0x1 }, + { } +}; + static int dw_pcie_get_clocks(struct dw_pcie *pci) { int i, ret; @@ -330,6 +338,12 @@ u16 dw_pcie_find_rasdes_capability(struct dw_pcie *pci) } EXPORT_SYMBOL_GPL(dw_pcie_find_rasdes_capability); +u16 dw_pcie_find_ptm_capability(struct dw_pcie *pci) +{ + return dw_pcie_find_vsec_capability(pci, dwc_pcie_ptm_vsec_ids); +} +EXPORT_SYMBOL_GPL(dw_pcie_find_ptm_capability); + int dw_pcie_read(void __iomem *addr, int size, u32 *val) { if (!IS_ALIGNED((uintptr_t)addr, size)) { diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 7f58c94b5b1e..4d41274a6937 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -260,6 +260,21 @@ #define PCIE_RAS_DES_EVENT_COUNTER_DATA 0xc +/* PTM register definitions */ +#define PTM_RES_REQ_CTRL 0x8 +#define PTM_RES_CCONTEXT_VALID BIT(0) +#define PTM_REQ_AUTO_UPDATE_ENABLED BIT(0) +#define PTM_REQ_START_UPDATE BIT(1) + +#define PTM_LOCAL_LSB 0x10 +#define PTM_LOCAL_MSB 0x14 +#define PTM_T1_T2_LSB 0x18 +#define PTM_T1_T2_MSB 0x1c +#define PTM_T3_T4_LSB 0x28 +#define PTM_T3_T4_MSB 0x2c +#define PTM_MASTER_LSB 0x38 +#define PTM_MASTER_MSB 0x3c + /* * The default address offset between dbi_base and atu_base. Root controller * drivers are not required to initialize atu_base if the offset matches this @@ -504,6 +519,8 @@ struct dw_pcie { bool suspended; struct debugfs_info *debugfs; enum dw_pcie_device_mode mode; + u16 ptm_vsec_offset; + struct pci_ptm_debugfs *ptm_debugfs; /* * If iATU input addresses are offset from CPU physical addresses, @@ -531,6 +548,7 @@ void dw_pcie_version_detect(struct dw_pcie *pci); u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap); u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap); u16 dw_pcie_find_rasdes_capability(struct dw_pcie *pci); +u16 dw_pcie_find_ptm_capability(struct dw_pcie *pci); int dw_pcie_read(void __iomem *addr, int size, u32 *val); int dw_pcie_write(void __iomem *addr, int size, u32 val); -- cgit v1.2.3 From 5fbfae69e78d242c5efb2a4b62eeea883af145ee Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 5 May 2025 19:54:42 +0530 Subject: PCI: qcom-ep: Mask PTM_UPDATING interrupt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When PTM is enabled, PTM_UPDATING interrupt will be fired for each PTM context update, which will be once every 10ms in the case of auto context update. Since the interrupt is not strictly needed for making use of PTM, mask it to avoid the overhead of processing it. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Link: https://patch.msgid.link/20250505-pcie-ptm-v4-4-02d26d51400b@linaro.org --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 46b1c6d19974..9270429501ae 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -60,6 +60,7 @@ #define PARF_DEVICE_TYPE 0x1000 #define PARF_BDF_TO_SID_CFG 0x2c00 #define PARF_INT_ALL_5_MASK 0x2dcc +#define PARF_INT_ALL_3_MASK 0x2e18 /* PARF_INT_ALL_{STATUS/CLEAR/MASK} register fields */ #define PARF_INT_ALL_LINK_DOWN BIT(1) @@ -132,6 +133,9 @@ /* PARF_INT_ALL_5_MASK fields */ #define PARF_INT_ALL_5_MHI_RAM_DATA_PARITY_ERR BIT(0) +/* PARF_INT_ALL_3_MASK fields */ +#define PARF_INT_ALL_3_PTM_UPDATING BIT(4) + /* ELBI registers */ #define ELBI_SYS_STTS 0x08 #define ELBI_CS2_ENABLE 0xa4 @@ -497,6 +501,10 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) writel_relaxed(val, pcie_ep->parf + PARF_INT_ALL_5_MASK); } + val = readl_relaxed(pcie_ep->parf + PARF_INT_ALL_3_MASK); + val &= ~PARF_INT_ALL_3_PTM_UPDATING; + writel_relaxed(val, pcie_ep->parf + PARF_INT_ALL_3_MASK); + ret = dw_pcie_ep_init_registers(&pcie_ep->pci.ep); if (ret) { dev_err(dev, "Failed to complete initialization: %d\n", ret); -- cgit v1.2.3 From 4b5e1d97154df4e0e2dabfc3e6bef68b87265a55 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Wed, 19 Mar 2025 10:29:22 +0100 Subject: PCI: Switch to irq_domain_create_linear() irq_domain_add_linear() is going away as being obsolete now. Switch to the preferred irq_domain_create_linear(). That differs in the first parameter: It takes more generic struct fwnode_handle instead of struct device_node. Therefore, of_fwnode_handle() is added around the parameter. Note some of the users can likely use dev->fwnode directly instead of indirect of_fwnode_handle(dev->of_node). But dev->fwnode is not guaranteed to be set for all, so this has to be investigated on case to case basis (by people who can actually test with the HW). [ tglx: Fix up subject prefix and convert the new instance in dwc/pcie-amd-mdb.c ] Signed-off-by: Jiri Slaby (SUSE) Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/20250319092951.37667-30-jirislaby@kernel.org --- drivers/pci/controller/dwc/pci-dra7xx.c | 4 ++-- drivers/pci/controller/dwc/pci-keystone.c | 2 +- drivers/pci/controller/dwc/pcie-amd-mdb.c | 8 ++++---- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 4 ++-- drivers/pci/controller/dwc/pcie-uniphier.c | 2 +- drivers/pci/controller/mobiveil/pcie-mobiveil-host.c | 9 ++++----- drivers/pci/controller/pci-aardvark.c | 14 +++++--------- drivers/pci/controller/pci-ftpci100.c | 4 ++-- drivers/pci/controller/pci-mvebu.c | 6 +++--- drivers/pci/controller/pcie-altera-msi.c | 2 +- drivers/pci/controller/pcie-altera.c | 2 +- drivers/pci/controller/pcie-brcmstb.c | 2 +- drivers/pci/controller/pcie-iproc-msi.c | 4 ++-- drivers/pci/controller/pcie-mediatek-gen3.c | 9 +++++---- drivers/pci/controller/pcie-mediatek.c | 4 ++-- drivers/pci/controller/pcie-rockchip-host.c | 4 ++-- drivers/pci/controller/pcie-xilinx-cpm.c | 10 ++++------ drivers/pci/controller/pcie-xilinx-dma-pl.c | 12 ++++++------ drivers/pci/controller/pcie-xilinx-nwl.c | 9 +++------ drivers/pci/controller/pcie-xilinx.c | 5 ++--- drivers/pci/controller/plda/pcie-plda-host.c | 14 ++++++-------- 21 files changed, 59 insertions(+), 71 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 33d6bf460ffe..3219704aba0e 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -359,8 +359,8 @@ static int dra7xx_pcie_init_irq_domain(struct dw_pcie_rp *pp) irq_set_chained_handler_and_data(pp->irq, dra7xx_pcie_msi_irq_handler, pp); - dra7xx->irq_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, - &intx_domain_ops, pp); + dra7xx->irq_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), + PCI_NUM_INTX, &intx_domain_ops, pp); of_node_put(pcie_intc_node); if (!dra7xx->irq_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 76a37368ae4f..1385d9db7b32 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -761,7 +761,7 @@ static int ks_pcie_config_intx_irq(struct keystone_pcie *ks_pcie) ks_pcie); } - intx_irq_domain = irq_domain_add_linear(intc_np, PCI_NUM_INTX, + intx_irq_domain = irq_domain_create_linear(of_fwnode_handle(intc_np), PCI_NUM_INTX, &ks_pcie_intx_irq_domain_ops, NULL); if (!intx_irq_domain) { dev_err(dev, "Failed to add irq domain for INTX irqs\n"); diff --git a/drivers/pci/controller/dwc/pcie-amd-mdb.c b/drivers/pci/controller/dwc/pcie-amd-mdb.c index 4eb2a4e8189d..9f7251a16d32 100644 --- a/drivers/pci/controller/dwc/pcie-amd-mdb.c +++ b/drivers/pci/controller/dwc/pcie-amd-mdb.c @@ -290,8 +290,8 @@ static int amd_mdb_pcie_init_irq_domains(struct amd_mdb_pcie *pcie, return -ENODEV; } - pcie->mdb_domain = irq_domain_add_linear(pcie_intc_node, 32, - &event_domain_ops, pcie); + pcie->mdb_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), 32, + &event_domain_ops, pcie); if (!pcie->mdb_domain) { err = -ENOMEM; dev_err(dev, "Failed to add MDB domain\n"); @@ -300,8 +300,8 @@ static int amd_mdb_pcie_init_irq_domains(struct amd_mdb_pcie *pcie, irq_domain_update_bus_token(pcie->mdb_domain, DOMAIN_BUS_NEXUS); - pcie->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, - &amd_intx_domain_ops, pcie); + pcie->intx_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), + PCI_NUM_INTX, &amd_intx_domain_ops, pcie); if (!pcie->intx_domain) { err = -ENOMEM; dev_err(dev, "Failed to add INTx domain\n"); diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index c624b7ebd118..678d510a261d 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -144,8 +144,8 @@ static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip) return -EINVAL; } - rockchip->irq_domain = irq_domain_add_linear(intc, PCI_NUM_INTX, - &intx_domain_ops, rockchip); + rockchip->irq_domain = irq_domain_create_linear(of_fwnode_handle(intc), PCI_NUM_INTX, + &intx_domain_ops, rockchip); of_node_put(intc); if (!rockchip->irq_domain) { dev_err(dev, "failed to get a INTx IRQ domain\n"); diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c index 5757ca3803c9..43b28f826edd 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier.c +++ b/drivers/pci/controller/dwc/pcie-uniphier.c @@ -279,7 +279,7 @@ static int uniphier_pcie_config_intx_irq(struct dw_pcie_rp *pp) goto out_put_node; } - pcie->intx_irq_domain = irq_domain_add_linear(np_intc, PCI_NUM_INTX, + pcie->intx_irq_domain = irq_domain_create_linear(of_fwnode_handle(np_intc), PCI_NUM_INTX, &uniphier_intx_domain_ops, pp); if (!pcie->intx_irq_domain) { dev_err(pci->dev, "Failed to get INTx domain\n"); diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c index 6628eed9d26e..a600f46ee3c3 100644 --- a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c @@ -439,8 +439,8 @@ static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie) struct mobiveil_msi *msi = &pcie->rp.msi; mutex_init(&msi->lock); - msi->dev_domain = irq_domain_add_linear(NULL, msi->num_of_vectors, - &msi_domain_ops, pcie); + msi->dev_domain = irq_domain_create_linear(NULL, msi->num_of_vectors, + &msi_domain_ops, pcie); if (!msi->dev_domain) { dev_err(dev, "failed to create IRQ domain\n"); return -ENOMEM; @@ -461,12 +461,11 @@ static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie) static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie) { struct device *dev = &pcie->pdev->dev; - struct device_node *node = dev->of_node; struct mobiveil_root_port *rp = &pcie->rp; /* setup INTx */ - rp->intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX, - &intx_domain_ops, pcie); + rp->intx_domain = irq_domain_create_linear(of_fwnode_handle(dev->of_node), PCI_NUM_INTX, + &intx_domain_ops, pcie); if (!rp->intx_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index a29796cce420..7bac64533b14 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -1456,9 +1456,8 @@ static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie) raw_spin_lock_init(&pcie->msi_irq_lock); mutex_init(&pcie->msi_used_lock); - pcie->msi_inner_domain = - irq_domain_add_linear(NULL, MSI_IRQ_NUM, - &advk_msi_domain_ops, pcie); + pcie->msi_inner_domain = irq_domain_create_linear(NULL, MSI_IRQ_NUM, + &advk_msi_domain_ops, pcie); if (!pcie->msi_inner_domain) return -ENOMEM; @@ -1508,9 +1507,8 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) irq_chip->irq_mask = advk_pcie_irq_mask; irq_chip->irq_unmask = advk_pcie_irq_unmask; - pcie->irq_domain = - irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, - &advk_pcie_irq_domain_ops, pcie); + pcie->irq_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), PCI_NUM_INTX, + &advk_pcie_irq_domain_ops, pcie); if (!pcie->irq_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); ret = -ENOMEM; @@ -1549,9 +1547,7 @@ static const struct irq_domain_ops advk_pcie_rp_irq_domain_ops = { static int advk_pcie_init_rp_irq_domain(struct advk_pcie *pcie) { - pcie->rp_irq_domain = irq_domain_add_linear(NULL, 1, - &advk_pcie_rp_irq_domain_ops, - pcie); + pcie->rp_irq_domain = irq_domain_create_linear(NULL, 1, &advk_pcie_rp_irq_domain_ops, pcie); if (!pcie->rp_irq_domain) { dev_err(&pcie->pdev->dev, "Failed to add Root Port IRQ domain\n"); return -ENOMEM; diff --git a/drivers/pci/controller/pci-ftpci100.c b/drivers/pci/controller/pci-ftpci100.c index ffdeed25e961..28e43831c0f1 100644 --- a/drivers/pci/controller/pci-ftpci100.c +++ b/drivers/pci/controller/pci-ftpci100.c @@ -345,8 +345,8 @@ static int faraday_pci_setup_cascaded_irq(struct faraday_pci *p) return irq ?: -EINVAL; } - p->irqdomain = irq_domain_add_linear(intc, PCI_NUM_INTX, - &faraday_pci_irqdomain_ops, p); + p->irqdomain = irq_domain_create_linear(of_fwnode_handle(intc), PCI_NUM_INTX, + &faraday_pci_irqdomain_ops, p); of_node_put(intc); if (!p->irqdomain) { dev_err(p->dev, "failed to create Gemini PCI IRQ domain\n"); diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index b0e3bce10aa4..60da24ba0a19 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -1078,9 +1078,9 @@ static int mvebu_pcie_init_irq_domain(struct mvebu_pcie_port *port) return -ENODEV; } - port->intx_irq_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, - &mvebu_pcie_intx_irq_domain_ops, - port); + port->intx_irq_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), + PCI_NUM_INTX, + &mvebu_pcie_intx_irq_domain_ops, port); of_node_put(pcie_intc_node); if (!port->intx_irq_domain) { dev_err(dev, "Failed to get INTx IRQ domain for %s\n", port->name); diff --git a/drivers/pci/controller/pcie-altera-msi.c b/drivers/pci/controller/pcie-altera-msi.c index 5fb3a2e0017e..a43f21eb8fbb 100644 --- a/drivers/pci/controller/pcie-altera-msi.c +++ b/drivers/pci/controller/pcie-altera-msi.c @@ -166,7 +166,7 @@ static int altera_allocate_domains(struct altera_msi *msi) { struct fwnode_handle *fwnode = of_fwnode_handle(msi->pdev->dev.of_node); - msi->inner_domain = irq_domain_add_linear(NULL, msi->num_of_vectors, + msi->inner_domain = irq_domain_create_linear(NULL, msi->num_of_vectors, &msi_domain_ops, msi); if (!msi->inner_domain) { dev_err(&msi->pdev->dev, "failed to create IRQ domain\n"); diff --git a/drivers/pci/controller/pcie-altera.c b/drivers/pci/controller/pcie-altera.c index 70409e71a18f..0fc77176a52e 100644 --- a/drivers/pci/controller/pcie-altera.c +++ b/drivers/pci/controller/pcie-altera.c @@ -855,7 +855,7 @@ static int altera_pcie_init_irq_domain(struct altera_pcie *pcie) struct device_node *node = dev->of_node; /* Setup INTx */ - pcie->irq_domain = irq_domain_add_linear(node, PCI_NUM_INTX, + pcie->irq_domain = irq_domain_create_linear(of_fwnode_handle(node), PCI_NUM_INTX, &intx_domain_ops, pcie); if (!pcie->irq_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 924a81e073c0..92887b394eb4 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -584,7 +584,7 @@ static int brcm_allocate_domains(struct brcm_msi *msi) struct fwnode_handle *fwnode = of_fwnode_handle(msi->np); struct device *dev = msi->dev; - msi->inner_domain = irq_domain_add_linear(NULL, msi->nr, &msi_domain_ops, msi); + msi->inner_domain = irq_domain_create_linear(NULL, msi->nr, &msi_domain_ops, msi); if (!msi->inner_domain) { dev_err(dev, "failed to create IRQ domain\n"); return -ENOMEM; diff --git a/drivers/pci/controller/pcie-iproc-msi.c b/drivers/pci/controller/pcie-iproc-msi.c index 804b3a5787c5..d2cb4c4f821a 100644 --- a/drivers/pci/controller/pcie-iproc-msi.c +++ b/drivers/pci/controller/pcie-iproc-msi.c @@ -446,8 +446,8 @@ static void iproc_msi_disable(struct iproc_msi *msi) static int iproc_msi_alloc_domains(struct device_node *node, struct iproc_msi *msi) { - msi->inner_domain = irq_domain_add_linear(NULL, msi->nr_msi_vecs, - &msi_domain_ops, msi); + msi->inner_domain = irq_domain_create_linear(NULL, msi->nr_msi_vecs, + &msi_domain_ops, msi); if (!msi->inner_domain) return -ENOMEM; diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c index 9d52504acae4..b55f5973414c 100644 --- a/drivers/pci/controller/pcie-mediatek-gen3.c +++ b/drivers/pci/controller/pcie-mediatek-gen3.c @@ -745,8 +745,8 @@ static int mtk_pcie_init_irq_domains(struct mtk_gen3_pcie *pcie) return -ENODEV; } - pcie->intx_domain = irq_domain_add_linear(intc_node, PCI_NUM_INTX, - &intx_domain_ops, pcie); + pcie->intx_domain = irq_domain_create_linear(of_fwnode_handle(intc_node), PCI_NUM_INTX, + &intx_domain_ops, pcie); if (!pcie->intx_domain) { dev_err(dev, "failed to create INTx IRQ domain\n"); ret = -ENODEV; @@ -756,8 +756,9 @@ static int mtk_pcie_init_irq_domains(struct mtk_gen3_pcie *pcie) /* Setup MSI */ mutex_init(&pcie->lock); - pcie->msi_bottom_domain = irq_domain_add_linear(node, PCIE_MSI_IRQS_NUM, - &mtk_msi_bottom_domain_ops, pcie); + pcie->msi_bottom_domain = irq_domain_create_linear(of_fwnode_handle(node), + PCIE_MSI_IRQS_NUM, + &mtk_msi_bottom_domain_ops, pcie); if (!pcie->msi_bottom_domain) { dev_err(dev, "failed to create MSI bottom domain\n"); ret = -ENODEV; diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index efcc4a7c17be..e1934aa06c8d 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -569,8 +569,8 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, return -ENODEV; } - port->irq_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, - &intx_domain_ops, port); + port->irq_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), PCI_NUM_INTX, + &intx_domain_ops, port); of_node_put(pcie_intc_node); if (!port->irq_domain) { dev_err(dev, "failed to get INTx IRQ domain\n"); diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c index 6a46be17aa91..b9e7a8710cf0 100644 --- a/drivers/pci/controller/pcie-rockchip-host.c +++ b/drivers/pci/controller/pcie-rockchip-host.c @@ -693,8 +693,8 @@ static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip) return -EINVAL; } - rockchip->irq_domain = irq_domain_add_linear(intc, PCI_NUM_INTX, - &intx_domain_ops, rockchip); + rockchip->irq_domain = irq_domain_create_linear(of_fwnode_handle(intc), PCI_NUM_INTX, + &intx_domain_ops, rockchip); of_node_put(intc); if (!rockchip->irq_domain) { dev_err(dev, "failed to get a INTx IRQ domain\n"); diff --git a/drivers/pci/controller/pcie-xilinx-cpm.c b/drivers/pci/controller/pcie-xilinx-cpm.c index 13ca493d22bd..d38f27e20761 100644 --- a/drivers/pci/controller/pcie-xilinx-cpm.c +++ b/drivers/pci/controller/pcie-xilinx-cpm.c @@ -395,17 +395,15 @@ static int xilinx_cpm_pcie_init_irq_domain(struct xilinx_cpm_pcie *port) return -EINVAL; } - port->cpm_domain = irq_domain_add_linear(pcie_intc_node, 32, - &event_domain_ops, - port); + port->cpm_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), 32, + &event_domain_ops, port); if (!port->cpm_domain) goto out; irq_domain_update_bus_token(port->cpm_domain, DOMAIN_BUS_NEXUS); - port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, - &intx_domain_ops, - port); + port->intx_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), PCI_NUM_INTX, + &intx_domain_ops, port); if (!port->intx_domain) goto out; diff --git a/drivers/pci/controller/pcie-xilinx-dma-pl.c b/drivers/pci/controller/pcie-xilinx-dma-pl.c index 71cf13ae51c7..dc9690a535e1 100644 --- a/drivers/pci/controller/pcie-xilinx-dma-pl.c +++ b/drivers/pci/controller/pcie-xilinx-dma-pl.c @@ -472,8 +472,8 @@ static int xilinx_pl_dma_pcie_init_msi_irq_domain(struct pl_dma_pcie *port) int size = BITS_TO_LONGS(XILINX_NUM_MSI_IRQS) * sizeof(long); struct fwnode_handle *fwnode = of_fwnode_handle(port->dev->of_node); - msi->dev_domain = irq_domain_add_linear(NULL, XILINX_NUM_MSI_IRQS, - &dev_msi_domain_ops, port); + msi->dev_domain = irq_domain_create_linear(NULL, XILINX_NUM_MSI_IRQS, + &dev_msi_domain_ops, port); if (!msi->dev_domain) goto out; @@ -585,15 +585,15 @@ static int xilinx_pl_dma_pcie_init_irq_domain(struct pl_dma_pcie *port) return -EINVAL; } - port->pldma_domain = irq_domain_add_linear(pcie_intc_node, 32, - &event_domain_ops, port); + port->pldma_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), 32, + &event_domain_ops, port); if (!port->pldma_domain) return -ENOMEM; irq_domain_update_bus_token(port->pldma_domain, DOMAIN_BUS_NEXUS); - port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, - &intx_domain_ops, port); + port->intx_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), PCI_NUM_INTX, + &intx_domain_ops, port); if (!port->intx_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); return -ENOMEM; diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c index 9cf8a96f7bc4..c8b05477b719 100644 --- a/drivers/pci/controller/pcie-xilinx-nwl.c +++ b/drivers/pci/controller/pcie-xilinx-nwl.c @@ -498,8 +498,7 @@ static int nwl_pcie_init_msi_irq_domain(struct nwl_pcie *pcie) struct fwnode_handle *fwnode = of_fwnode_handle(dev->of_node); struct nwl_msi *msi = &pcie->msi; - msi->dev_domain = irq_domain_add_linear(NULL, INT_PCI_MSI_NR, - &dev_msi_domain_ops, pcie); + msi->dev_domain = irq_domain_create_linear(NULL, INT_PCI_MSI_NR, &dev_msi_domain_ops, pcie); if (!msi->dev_domain) { dev_err(dev, "failed to create dev IRQ domain\n"); return -ENOMEM; @@ -582,10 +581,8 @@ static int nwl_pcie_init_irq_domain(struct nwl_pcie *pcie) return -EINVAL; } - pcie->intx_irq_domain = irq_domain_add_linear(intc_node, - PCI_NUM_INTX, - &intx_domain_ops, - pcie); + pcie->intx_irq_domain = irq_domain_create_linear(of_fwnode_handle(intc_node), PCI_NUM_INTX, + &intx_domain_ops, pcie); of_node_put(intc_node); if (!pcie->intx_irq_domain) { dev_err(dev, "failed to create IRQ domain\n"); diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c index 0b534f73a942..e36aa874bae9 100644 --- a/drivers/pci/controller/pcie-xilinx.c +++ b/drivers/pci/controller/pcie-xilinx.c @@ -461,9 +461,8 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie *pcie) return -ENODEV; } - pcie->leg_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, - &intx_domain_ops, - pcie); + pcie->leg_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), PCI_NUM_INTX, + &intx_domain_ops, pcie); of_node_put(pcie_intc_node); if (!pcie->leg_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c index 4c7a9fa311e3..3abedf723215 100644 --- a/drivers/pci/controller/plda/pcie-plda-host.c +++ b/drivers/pci/controller/plda/pcie-plda-host.c @@ -155,8 +155,7 @@ static int plda_allocate_msi_domains(struct plda_pcie_rp *port) mutex_init(&port->msi.lock); - msi->dev_domain = irq_domain_add_linear(NULL, msi->num_vectors, - &msi_domain_ops, port); + msi->dev_domain = irq_domain_create_linear(NULL, msi->num_vectors, &msi_domain_ops, port); if (!msi->dev_domain) { dev_err(dev, "failed to create IRQ domain\n"); return -ENOMEM; @@ -393,10 +392,9 @@ static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port) return -EINVAL; } - port->event_domain = irq_domain_add_linear(pcie_intc_node, - port->num_events, - &plda_event_domain_ops, - port); + port->event_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), + port->num_events, &plda_event_domain_ops, + port); if (!port->event_domain) { dev_err(dev, "failed to get event domain\n"); of_node_put(pcie_intc_node); @@ -405,8 +403,8 @@ static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port) irq_domain_update_bus_token(port->event_domain, DOMAIN_BUS_NEXUS); - port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, - &intx_domain_ops, port); + port->intx_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), PCI_NUM_INTX, + &intx_domain_ops, port); if (!port->intx_domain) { dev_err(dev, "failed to get an INTx IRQ domain\n"); of_node_put(pcie_intc_node); -- cgit v1.2.3 From 1d79596e86613727006161439f3781e74bdb9fac Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 6 May 2025 11:51:39 +0200 Subject: PCI: dwc: ep: Fix errno typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix errno typo in kernel-doc comments. Fixes: 7cbebc86c72a ("PCI: dwc: ep: Add Kernel-doc comments for APIs") Signed-off-by: Niklas Cassel Signed-off-by: Krzysztof Wilczyński Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20250506095138.482485-2-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-designware-ep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index f3daf46b5e63..845862f1a1cb 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -671,7 +671,7 @@ static const struct pci_epc_ops epc_ops = { * @ep: DWC EP device * @func_no: Function number of the endpoint * - * Return: 0 if success, errono otherwise. + * Return: 0 if success, errno otherwise. */ int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no) { @@ -690,7 +690,7 @@ EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_intx_irq); * @func_no: Function number of the endpoint * @interrupt_num: Interrupt number to be raised * - * Return: 0 if success, errono otherwise. + * Return: 0 if success, errno otherwise. */ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num) -- cgit v1.2.3 From 810276362bad172d063d1f6be1cc2cb425b90103 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 14 May 2025 09:43:14 +0200 Subject: PCI: dwc: ep: Correct PBA offset in .set_msix() callback While dw_pcie_ep_set_msix() writes the Table Size field correctly (N-1), the calculation of the PBA offset is wrong because it calculates space for (N-1) entries instead of N. This results in the following QEMU error when using PCI passthrough on a device which relies on the PCI endpoint subsystem: failed to add PCI capability 0x11[0x50]@0xb0: table & pba overlap, or they don't fit in BARs, or don't align Fix the calculation of PBA offset in the MSI-X capability. [bhelgaas: more specific subject and commit log] Fixes: 83153d9f36e2 ("PCI: endpoint: Fix ->set_msix() to take BIR and offset as arguments") Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Wilfred Mallawa Reviewed-by: Damien Le Moal Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250514074313.283156-9-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-designware-ep.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 1a0bf9341542..24026f3f3413 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -585,6 +585,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie_ep_func *ep_func; u32 val, reg; + u16 actual_interrupts = interrupts + 1; ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); if (!ep_func || !ep_func->msix_cap) @@ -595,7 +596,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, reg = ep_func->msix_cap + PCI_MSIX_FLAGS; val = dw_pcie_ep_readw_dbi(ep, func_no, reg); val &= ~PCI_MSIX_FLAGS_QSIZE; - val |= interrupts; + val |= interrupts; /* 0's based value */ dw_pcie_writew_dbi(pci, reg, val); reg = ep_func->msix_cap + PCI_MSIX_TABLE; @@ -603,7 +604,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, dw_pcie_ep_writel_dbi(ep, func_no, reg, val); reg = ep_func->msix_cap + PCI_MSIX_PBA; - val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; + val = (offset + (actual_interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; dw_pcie_ep_writel_dbi(ep, func_no, reg, val); dw_pcie_dbi_ro_wr_dis(pci); -- cgit v1.2.3 From f7f15fc53245385e39ef0aab4310d1682fd3c079 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 14 May 2025 09:43:16 +0200 Subject: PCI: endpoint: Align pci_epc_get_msi(), pci_epc_ops::get_msi() return value encoding The kdoc for API pci_epc_get_msi() says: "Invoke to get the number of MSI interrupts allocated by the RC" The kdoc for the callback pci_epc_ops::get_msi() says: "ops to get the number of MSI interrupts allocated by the RC from the MSI capability register" pci_epc_ops::get_msi() does however return the number of interrupts in the encoding as defined by the Multiple Message Enable (MME) field of the MSI Capability structure. Nowhere in the kdoc does it say that the returned number of interrupts is in MME encoding. It is very confusing that the API pci_epc_get_msi() and the callback function pci_epc_ops::get_msi() don't return the same value. Clean up the API and the callback function to have the same semantics, i.e. return the number of interrupts, regardless of the internal encoding of that value. [bhelgaas: more specific subject] Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Damien Le Moal Cc: stable+noautosel@kernel.org # this is simply a cleanup Link: https://patch.msgid.link/20250514074313.283156-11-cassel@kernel.org --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 2 +- drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +- drivers/pci/controller/pcie-rcar-ep.c | 2 +- drivers/pci/controller/pcie-rockchip-ep.c | 4 ++-- drivers/pci/endpoint/pci-epc-core.c | 2 -- 5 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 112ae200b393..78b4d009cd04 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -262,7 +262,7 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn) */ mme = FIELD_GET(PCI_MSI_FLAGS_QSIZE, flags); - return mme; + return 1 << mme; } static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 24026f3f3413..03597551f4cd 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -532,7 +532,7 @@ static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no) val = FIELD_GET(PCI_MSI_FLAGS_QSIZE, val); - return val; + return 1 << val; } static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c index c5e0d025bc43..9da39a4617b6 100644 --- a/drivers/pci/controller/pcie-rcar-ep.c +++ b/drivers/pci/controller/pcie-rcar-ep.c @@ -280,7 +280,7 @@ static int rcar_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn) if (!(flags & MSICAP0_MSIE)) return -EINVAL; - return ((flags & MSICAP0_MMESE_MASK) >> MSICAP0_MMESE_OFFSET); + return 1 << ((flags & MSICAP0_MMESE_MASK) >> MSICAP0_MMESE_OFFSET); } static int rcar_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn, diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index 85ea36df2f59..85ca7d9b4c77 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -340,8 +340,8 @@ static int rockchip_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn) if (!(flags & ROCKCHIP_PCIE_EP_MSI_CTRL_ME)) return -EINVAL; - return ((flags & ROCKCHIP_PCIE_EP_MSI_CTRL_MME_MASK) >> - ROCKCHIP_PCIE_EP_MSI_CTRL_MME_OFFSET); + return 1 << ((flags & ROCKCHIP_PCIE_EP_MSI_CTRL_MME_MASK) >> + ROCKCHIP_PCIE_EP_MSI_CTRL_MME_OFFSET); } static void rockchip_pcie_ep_assert_intx(struct rockchip_pcie_ep *ep, u8 fn, diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index beabea00af91..cc1456bd188e 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -293,8 +293,6 @@ int pci_epc_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no) if (interrupt < 0) return 0; - interrupt = 1 << interrupt; - return interrupt; } EXPORT_SYMBOL_GPL(pci_epc_get_msi); -- cgit v1.2.3 From 0917ed8f16b646c5e3cc481ccfa4709286b76691 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 14 May 2025 09:43:17 +0200 Subject: PCI: endpoint: Align pci_epc_get_msix(), pci_epc_ops::get_msix() return value encoding The kdoc for pci_epc_get_msix() says: "Invoke to get the number of MSI-X interrupts allocated by the RC" The kdoc for the callback pci_epc_ops->get_msix() says: "ops to get the number of MSI-X interrupts allocated by the RC from the MSI-X capability register" pci_epc_ops::get_msix() does however return the number of interrupts in the encoding as defined by the Table Size field. Nowhere in the kdoc does it say that the returned number of interrupts is in Table Size encoding. It is very confusing that the API pci_epc_get_msix() and the callback function pci_epc_ops::get_msix() don't return the same value. Clean up the API and the callback function to have the same semantics, i.e. return the number of interrupts, regardless of the internal encoding of that value. [bhelgaas: more specific subject] Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Damien Le Moal Cc: stable+noautosel@kernel.org # this is simply a cleanup Link: https://patch.msgid.link/20250514074313.283156-12-cassel@kernel.org --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 2 +- drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +- drivers/pci/endpoint/pci-epc-core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 78b4d009cd04..569cb7481d45 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -281,7 +281,7 @@ static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) val &= PCI_MSIX_FLAGS_QSIZE; - return val; + return val + 1; } static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 03597551f4cd..307c862588a4 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -575,7 +575,7 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) val &= PCI_MSIX_FLAGS_QSIZE; - return val; + return val + 1; } static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index cc1456bd188e..092b14918b46 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -355,7 +355,7 @@ int pci_epc_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) if (interrupt < 0) return 0; - return interrupt + 1; + return interrupt; } EXPORT_SYMBOL_GPL(pci_epc_get_msix); -- cgit v1.2.3 From f62da6e7270c2db5aef8a8b14f465896961a9372 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 14 May 2025 09:43:18 +0200 Subject: PCI: endpoint: Align pci_epc_set_msi(), pci_epc_ops::set_msi() nr_irqs encoding The kdoc for pci_epc_set_msi() says: "Invoke to set the required number of MSI interrupts." The kdoc for the callback pci_epc_ops::set_msi() says: "ops to set the requested number of MSI interrupts in the MSI capability register" pci_epc_ops::set_msi() does however expect the parameter 'interrupts' to be in the encoding as defined by the Multiple Message Capable (MMC) field of the MSI capability structure. Nowhere in the kdoc does it say that the number of interrupts should be in MMC encoding. It is very confusing that the API pci_epc_set_msi() and the callback function pci_epc_ops::set_msi() both take a parameter named 'interrupts', but they expect completely different encodings. Clean up the API and the callback function to have the same semantics, i.e. the parameter represents the number of interrupts, regardless of the internal encoding of that value. Also rename the parameter 'interrupts' to 'nr_irqs', in both the wrapper function and the callback function, such that the name is unambiguous. [bhelgaas: more specific subject] Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Cc: stable+noautosel@kernel.org # this is simply a cleanup Link: https://patch.msgid.link/20250514074313.283156-13-cassel@kernel.org --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 3 ++- drivers/pci/controller/dwc/pcie-designware-ep.c | 5 +++-- drivers/pci/controller/pcie-rcar-ep.c | 6 +++--- drivers/pci/controller/pcie-rockchip-ep.c | 5 +++-- drivers/pci/endpoint/pci-epc-core.c | 11 ++++------- include/linux/pci-epc.h | 5 ++--- 6 files changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 569cb7481d45..f09f29ed27ed 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -220,10 +220,11 @@ static void cdns_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn, clear_bit(r, &ep->ob_region_map); } -static int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 mmc) +static int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 nr_irqs) { struct cdns_pcie_ep *ep = epc_get_drvdata(epc); struct cdns_pcie *pcie = &ep->pcie; + u8 mmc = order_base_2(nr_irqs); u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; u16 flags; diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 307c862588a4..230e82674591 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -536,11 +536,12 @@ static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no) } static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u8 interrupts) + u8 nr_irqs) { struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie_ep_func *ep_func; + u8 mmc = order_base_2(nr_irqs); u32 val, reg; ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); @@ -550,7 +551,7 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, reg = ep_func->msi_cap + PCI_MSI_FLAGS; val = dw_pcie_ep_readw_dbi(ep, func_no, reg); val &= ~PCI_MSI_FLAGS_QMASK; - val |= FIELD_PREP(PCI_MSI_FLAGS_QMASK, interrupts); + val |= FIELD_PREP(PCI_MSI_FLAGS_QMASK, mmc); dw_pcie_dbi_ro_wr_en(pci); dw_pcie_ep_writew_dbi(ep, func_no, reg, val); dw_pcie_dbi_ro_wr_dis(pci); diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c index 9da39a4617b6..a8a966844cf3 100644 --- a/drivers/pci/controller/pcie-rcar-ep.c +++ b/drivers/pci/controller/pcie-rcar-ep.c @@ -256,15 +256,15 @@ static void rcar_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn, u8 vfn, clear_bit(atu_index + 1, ep->ib_window_map); } -static int rcar_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, - u8 interrupts) +static int rcar_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 nr_irqs) { struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); struct rcar_pcie *pcie = &ep->pcie; + u8 mmc = order_base_2(nr_irqs); u32 flags; flags = rcar_pci_read_reg(pcie, MSICAP(fn)); - flags |= interrupts << MSICAP0_MMESCAP_OFFSET; + flags |= mmc << MSICAP0_MMESCAP_OFFSET; rcar_pci_write_reg(pcie, flags, MSICAP(fn)); return 0; diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index 85ca7d9b4c77..a0a85080c31d 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -308,10 +308,11 @@ static void rockchip_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn, } static int rockchip_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, - u8 multi_msg_cap) + u8 nr_irqs) { struct rockchip_pcie_ep *ep = epc_get_drvdata(epc); struct rockchip_pcie *rockchip = &ep->rockchip; + u8 mmc = order_base_2(nr_irqs); u32 flags; flags = rockchip_pcie_read(rockchip, @@ -319,7 +320,7 @@ static int rockchip_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, ROCKCHIP_PCIE_EP_MSI_CTRL_REG); flags &= ~ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_MASK; flags |= - (multi_msg_cap << ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_OFFSET) | + (mmc << ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_OFFSET) | (PCI_MSI_FLAGS_64BIT << ROCKCHIP_PCIE_EP_MSI_FLAGS_OFFSET); flags &= ~ROCKCHIP_PCIE_EP_MSI_CTRL_MASK_MSI_CAP; rockchip_pcie_write(rockchip, flags, diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index 092b14918b46..ea698551f9d8 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -302,28 +302,25 @@ EXPORT_SYMBOL_GPL(pci_epc_get_msi); * @epc: the EPC device on which MSI has to be configured * @func_no: the physical endpoint function number in the EPC device * @vfunc_no: the virtual endpoint function number in the physical function - * @interrupts: number of MSI interrupts required by the EPF + * @nr_irqs: number of MSI interrupts required by the EPF * * Invoke to set the required number of MSI interrupts. */ -int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u8 interrupts) +int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u8 nr_irqs) { int ret; - u8 encode_int; if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return -EINVAL; - if (interrupts < 1 || interrupts > 32) + if (nr_irqs < 1 || nr_irqs > 32) return -EINVAL; if (!epc->ops->set_msi) return 0; - encode_int = order_base_2(interrupts); - mutex_lock(&epc->lock); - ret = epc->ops->set_msi(epc, func_no, vfunc_no, encode_int); + ret = epc->ops->set_msi(epc, func_no, vfunc_no, nr_irqs); mutex_unlock(&epc->lock); return ret; diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index 82837008b56f..15d10c07c9f1 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -100,7 +100,7 @@ struct pci_epc_ops { void (*unmap_addr)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t addr); int (*set_msi)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u8 interrupts); + u8 nr_irqs); int (*get_msi)(struct pci_epc *epc, u8 func_no, u8 vfunc_no); int (*set_msix)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u16 interrupts, enum pci_barno, u32 offset); @@ -286,8 +286,7 @@ int pci_epc_map_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u64 pci_addr, size_t size); void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t phys_addr); -int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u8 interrupts); +int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u8 nr_irqs); int pci_epc_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no); int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u16 interrupts, enum pci_barno, u32 offset); -- cgit v1.2.3 From de0321bcc5fdd83631f0c2a6fdebfe0ad4e23449 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 14 May 2025 09:43:19 +0200 Subject: PCI: endpoint: Align pci_epc_set_msix(), pci_epc_ops::set_msix() nr_irqs encoding The kdoc for pci_epc_set_msix() says: "Invoke to set the required number of MSI-X interrupts." The kdoc for the callback pci_epc_ops->set_msix() says: "ops to set the requested number of MSI-X interrupts in the MSI-X capability register" pci_epc_ops::set_msix() does however expect the parameter 'interrupts' to be in the encoding as defined by the Table Size field. Nowhere in the kdoc does it say that the number of interrupts should be in Table Size encoding. It is very confusing that the API pci_epc_set_msix() and the callback function pci_epc_ops::set_msix() both take a parameter named 'interrupts', but they expect completely different encodings. Clean up the API and the callback function to have the same semantics, i.e. the parameter represents the number of interrupts, regardless of the internal encoding of that value. Also rename the parameter 'interrupts' to 'nr_irqs', in both the wrapper function and the callback function, such that the name is unambiguous. [bhelgaas: more specific subject] Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Cc: stable+noautosel@kernel.org # this is simply a cleanup Link: https://patch.msgid.link/20250514074313.283156-14-cassel@kernel.org --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 8 +++----- drivers/pci/controller/dwc/pcie-designware-ep.c | 7 +++---- drivers/pci/endpoint/pci-epc-core.c | 11 +++++------ include/linux/pci-epc.h | 6 +++--- 4 files changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index f09f29ed27ed..0e9ebe956e7a 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -286,21 +286,19 @@ static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) } static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, - u16 interrupts, enum pci_barno bir, - u32 offset) + u16 nr_irqs, enum pci_barno bir, u32 offset) { struct cdns_pcie_ep *ep = epc_get_drvdata(epc); struct cdns_pcie *pcie = &ep->pcie; u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET; u32 val, reg; - u16 actual_interrupts = interrupts + 1; fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn); reg = cap + PCI_MSIX_FLAGS; val = cdns_pcie_ep_fn_readw(pcie, fn, reg); val &= ~PCI_MSIX_FLAGS_QSIZE; - val |= interrupts; /* 0's based value */ + val |= nr_irqs - 1; /* encoded as N-1 */ cdns_pcie_ep_fn_writew(pcie, fn, reg, val); /* Set MSI-X BAR and offset */ @@ -310,7 +308,7 @@ static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, /* Set PBA BAR and offset. BAR must match MSI-X BAR */ reg = cap + PCI_MSIX_PBA; - val = (offset + (actual_interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; + val = (offset + (nr_irqs * PCI_MSIX_ENTRY_SIZE)) | bir; cdns_pcie_ep_fn_writel(pcie, fn, reg, val); return 0; diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 230e82674591..6770318c0636 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -580,13 +580,12 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) } static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u16 interrupts, enum pci_barno bir, u32 offset) + u16 nr_irqs, enum pci_barno bir, u32 offset) { struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie_ep_func *ep_func; u32 val, reg; - u16 actual_interrupts = interrupts + 1; ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); if (!ep_func || !ep_func->msix_cap) @@ -597,7 +596,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, reg = ep_func->msix_cap + PCI_MSIX_FLAGS; val = dw_pcie_ep_readw_dbi(ep, func_no, reg); val &= ~PCI_MSIX_FLAGS_QSIZE; - val |= interrupts; /* 0's based value */ + val |= nr_irqs - 1; /* encoded as N-1 */ dw_pcie_writew_dbi(pci, reg, val); reg = ep_func->msix_cap + PCI_MSIX_TABLE; @@ -605,7 +604,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, dw_pcie_ep_writel_dbi(ep, func_no, reg, val); reg = ep_func->msix_cap + PCI_MSIX_PBA; - val = (offset + (actual_interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; + val = (offset + (nr_irqs * PCI_MSIX_ENTRY_SIZE)) | bir; dw_pcie_ep_writel_dbi(ep, func_no, reg, val); dw_pcie_dbi_ro_wr_dis(pci); diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index ea698551f9d8..ca7f19cc973a 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -361,29 +361,28 @@ EXPORT_SYMBOL_GPL(pci_epc_get_msix); * @epc: the EPC device on which MSI-X has to be configured * @func_no: the physical endpoint function number in the EPC device * @vfunc_no: the virtual endpoint function number in the physical function - * @interrupts: number of MSI-X interrupts required by the EPF + * @nr_irqs: number of MSI-X interrupts required by the EPF * @bir: BAR where the MSI-X table resides * @offset: Offset pointing to the start of MSI-X table * * Invoke to set the required number of MSI-X interrupts. */ -int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u16 interrupts, enum pci_barno bir, u32 offset) +int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u16 nr_irqs, + enum pci_barno bir, u32 offset) { int ret; if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return -EINVAL; - if (interrupts < 1 || interrupts > 2048) + if (nr_irqs < 1 || nr_irqs > 2048) return -EINVAL; if (!epc->ops->set_msix) return 0; mutex_lock(&epc->lock); - ret = epc->ops->set_msix(epc, func_no, vfunc_no, interrupts - 1, bir, - offset); + ret = epc->ops->set_msix(epc, func_no, vfunc_no, nr_irqs, bir, offset); mutex_unlock(&epc->lock); return ret; diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index 15d10c07c9f1..4286bfdbfdfa 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -103,7 +103,7 @@ struct pci_epc_ops { u8 nr_irqs); int (*get_msi)(struct pci_epc *epc, u8 func_no, u8 vfunc_no); int (*set_msix)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u16 interrupts, enum pci_barno, u32 offset); + u16 nr_irqs, enum pci_barno, u32 offset); int (*get_msix)(struct pci_epc *epc, u8 func_no, u8 vfunc_no); int (*raise_irq)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, unsigned int type, u16 interrupt_num); @@ -288,8 +288,8 @@ void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t phys_addr); int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u8 nr_irqs); int pci_epc_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no); -int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u16 interrupts, enum pci_barno, u32 offset); +int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u16 nr_irqs, + enum pci_barno, u32 offset); int pci_epc_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no); int pci_epc_map_msi_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t phys_addr, u8 interrupt_num, -- cgit v1.2.3 From d1c696dba120624256ab335ab8247f535b872309 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 8 May 2025 12:40:32 +0530 Subject: PCI: host-common: Convert to library for host controller drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This common library will be used as a placeholder for helper functions shared by the host controller drivers. This avoids placing the host controller drivers specific helpers in drivers/pci/*.c, to avoid enlarging the kernel image on platforms that do not use host controller drivers at all (like x86/ACPI platforms). Suggested-by: Lukas Wunner Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250508-pcie-reset-slot-v4-3-7050093e2b50@linaro.org --- drivers/pci/controller/Kconfig | 8 ++++---- drivers/pci/controller/dwc/pcie-hisi.c | 1 + drivers/pci/controller/pci-host-common.c | 6 ++++-- drivers/pci/controller/pci-host-common.h | 16 ++++++++++++++++ drivers/pci/controller/pci-host-generic.c | 2 ++ drivers/pci/controller/pci-thunder-ecam.c | 2 ++ drivers/pci/controller/pci-thunder-pem.c | 1 + drivers/pci/controller/pcie-apple.c | 2 ++ drivers/pci/controller/plda/pcie-microchip-host.c | 1 + include/linux/pci-ecam.h | 6 ------ 10 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 drivers/pci/controller/pci-host-common.h (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 9800b7681054..9bb8bf669a80 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -3,6 +3,10 @@ menu "PCI controller drivers" depends on PCI +config PCI_HOST_COMMON + tristate + select PCI_ECAM + config PCI_AARDVARK tristate "Aardvark PCIe controller" depends on (ARCH_MVEBU && ARM64) || COMPILE_TEST @@ -119,10 +123,6 @@ config PCI_FTPCI100 depends on OF default ARCH_GEMINI -config PCI_HOST_COMMON - tristate - select PCI_ECAM - config PCI_HOST_GENERIC tristate "Generic PCI host controller" depends on OF diff --git a/drivers/pci/controller/dwc/pcie-hisi.c b/drivers/pci/controller/dwc/pcie-hisi.c index 8904b5b85ee5..3c17897e56fc 100644 --- a/drivers/pci/controller/dwc/pcie-hisi.c +++ b/drivers/pci/controller/dwc/pcie-hisi.c @@ -15,6 +15,7 @@ #include #include #include "../../pci.h" +#include "../pci-host-common.h" #if defined(CONFIG_PCI_HISI) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c index f441bfd6f96a..f93bc7034e69 100644 --- a/drivers/pci/controller/pci-host-common.c +++ b/drivers/pci/controller/pci-host-common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Generic PCI host driver common code + * Common library for PCI host controller drivers * * Copyright (C) 2014 ARM Limited * @@ -15,6 +15,8 @@ #include #include +#include "pci-host-common.h" + static void gen_pci_unmap_cfg(void *ptr) { pci_ecam_free((struct pci_config_window *)ptr); @@ -94,5 +96,5 @@ void pci_host_common_remove(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(pci_host_common_remove); -MODULE_DESCRIPTION("Generic PCI host common driver"); +MODULE_DESCRIPTION("Common library for PCI host controller drivers"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pci/controller/pci-host-common.h b/drivers/pci/controller/pci-host-common.h new file mode 100644 index 000000000000..d8be024ca68d --- /dev/null +++ b/drivers/pci/controller/pci-host-common.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Common library for PCI host controller drivers + * + * Copyright (C) 2014 ARM Limited + * + * Author: Will Deacon + */ + +#ifndef _PCI_HOST_COMMON_H +#define _PCI_HOST_COMMON_H + +int pci_host_common_probe(struct platform_device *pdev); +void pci_host_common_remove(struct platform_device *pdev); + +#endif diff --git a/drivers/pci/controller/pci-host-generic.c b/drivers/pci/controller/pci-host-generic.c index 4051b9b61dac..c1bc0d34348f 100644 --- a/drivers/pci/controller/pci-host-generic.c +++ b/drivers/pci/controller/pci-host-generic.c @@ -14,6 +14,8 @@ #include #include +#include "pci-host-common.h" + static const struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = { .bus_shift = 16, .pci_ops = { diff --git a/drivers/pci/controller/pci-thunder-ecam.c b/drivers/pci/controller/pci-thunder-ecam.c index 08161065a89c..b5b4a958e6a2 100644 --- a/drivers/pci/controller/pci-thunder-ecam.c +++ b/drivers/pci/controller/pci-thunder-ecam.c @@ -11,6 +11,8 @@ #include #include +#include "pci-host-common.h" + #if defined(CONFIG_PCI_HOST_THUNDER_ECAM) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) static void set_val(u32 v, int where, int size, u32 *val) diff --git a/drivers/pci/controller/pci-thunder-pem.c b/drivers/pci/controller/pci-thunder-pem.c index f1bd5de67997..5fa037fb61dc 100644 --- a/drivers/pci/controller/pci-thunder-pem.c +++ b/drivers/pci/controller/pci-thunder-pem.c @@ -14,6 +14,7 @@ #include #include #include "../pci.h" +#include "pci-host-common.h" #if defined(CONFIG_PCI_HOST_THUNDER_PEM) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index 18e11b9a7f46..edd4c8c683c6 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -29,6 +29,8 @@ #include #include +#include "pci-host-common.h" + #define CORE_RC_PHYIF_CTL 0x00024 #define CORE_RC_PHYIF_CTL_RUN BIT(0) #define CORE_RC_PHYIF_STAT 0x00028 diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c index 3fdfffdf0270..24bbf93b8051 100644 --- a/drivers/pci/controller/plda/pcie-microchip-host.c +++ b/drivers/pci/controller/plda/pcie-microchip-host.c @@ -23,6 +23,7 @@ #include #include "../../pci.h" +#include "../pci-host-common.h" #include "pcie-plda.h" #define MC_MAX_NUM_INBOUND_WINDOWS 8 diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index 3a10f8cfc3ad..d930651473b4 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -93,10 +93,4 @@ extern const struct pci_ecam_ops al_pcie_ops; /* Amazon Annapurna Labs PCIe */ extern const struct pci_ecam_ops tegra194_pcie_ops; /* Tegra194 PCIe */ extern const struct pci_ecam_ops loongson_pci_ecam_ops; /* Loongson PCIe */ #endif - -#if IS_ENABLED(CONFIG_PCI_HOST_COMMON) -/* for DT-based PCI controllers that support ECAM */ -int pci_host_common_probe(struct platform_device *pdev); -void pci_host_common_remove(struct platform_device *pdev); -#endif #endif -- cgit v1.2.3 From d34719d0e81f5bf1750931562a36a6f3fa6512bc Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 6 May 2025 09:39:38 +0200 Subject: PCI: dw-rockchip: Replace PERST# sleep time with proper macro Replace the PERST# sleep time with the proper macro (PCIE_T_PVPERL_MS). No functional change. Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Tested-by: Laszlo Fiat Reviewed-by: Hans Zhang <18255117159@163.com> Reviewed-by: Wilfred Mallawa Link: https://patch.msgid.link/20250506073934.433176-9-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index ae171a545df6..6089a6a9f252 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -22,6 +22,7 @@ #include #include +#include "../../pci.h" #include "pcie-designware.h" /* @@ -224,7 +225,7 @@ static int rockchip_pcie_start_link(struct dw_pcie *pci) * We need more extra time as before, rather than setting just * 100us as we don't know how long should the device need to reset. */ - msleep(100); + msleep(PCIE_T_PVPERL_MS); gpiod_set_value_cansleep(rockchip->rst_gpio, 1); return 0; -- cgit v1.2.3 From ec49e253322bf29e721c6153d9e7be95eef33b33 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 6 May 2025 09:39:39 +0200 Subject: PCI: qcom: Replace PERST# sleep time with proper macro Replace the PERST# sleep time with the proper macro (PCIE_T_PVPERL_MS). No functional change. Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Wilfred Mallawa Reviewed-by: Hans Zhang <18255117159@163.com> Reviewed-by: Krishna Chaitanya Chundru Link: https://patch.msgid.link/20250506073934.433176-10-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index ba0dd1717a58..a623ed0fbc2f 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -289,7 +289,7 @@ static void qcom_ep_reset_assert(struct qcom_pcie *pcie) static void qcom_ep_reset_deassert(struct qcom_pcie *pcie) { /* Ensure that PERST has been asserted for at least 100 ms */ - msleep(100); + msleep(PCIE_T_PVPERL_MS); gpiod_set_value_cansleep(pcie->reset, 0); usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); } -- cgit v1.2.3