aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
authorBjorn Helgaas <bhelgaas@google.com>2026-06-23 17:32:16 -0500
committerBjorn Helgaas <bhelgaas@google.com>2026-06-23 17:32:16 -0500
commit7b900190125920e9e7e480a3075c9ee9c9de63bd (patch)
tree759563c1b99fc0d86957b2afdd2cfca03c0e9754 /drivers
parenta5c8e1ffe9d92f76b62c515506121c7870ec7fcf (diff)
parent843044971a5167087a9484f8f6eec81da30f2a71 (diff)
downloadath-7b900190125920e9e7e480a3075c9ee9c9de63bd.tar.gz
Merge branch 'pci/controller/mediatek'
- Use FIELD_PREP() to fix incorrect operator precedence in PCIE_FTS_NUM_L0 (Li RongQing) - Fix IRQ domain leak when port fails to enable (Manivannan Sadhasivam) - Use actual physical address for MSI message address instead of virt_to_phys() (Manivannan Sadhasivam) - Add EcoNet EN7528 to DT binding (Caleb James DeLisle) * pci/controller/mediatek: dt-bindings: PCI: mediatek: Add support for EcoNet EN7528 PCI: mediatek: Use actual physical address instead of virt_to_phys() PCI: mediatek: Fix IRQ domain leak when port fails to enable PCI: mediatek: Fix operator precedence in PCIE_FTS_NUM_L0 macro
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/controller/pcie-mediatek.c82
1 files changed, 55 insertions, 27 deletions
diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c
index 75722524fe744..1bb8839c3cb0f 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -7,6 +7,7 @@
* Honghui Zhang <honghui.zhang@mediatek.com>
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
@@ -61,7 +62,7 @@
/* MediaTek specific configuration registers */
#define PCIE_FTS_NUM 0x70c
#define PCIE_FTS_NUM_MASK GENMASK(15, 8)
-#define PCIE_FTS_NUM_L0(x) ((x) & 0xff << 8)
+#define PCIE_FTS_NUM_L0(x) FIELD_PREP(PCIE_FTS_NUM_MASK, x)
#define PCIE_FC_CREDIT 0x73c
#define PCIE_FC_CREDIT_MASK (GENMASK(31, 31) | GENMASK(28, 16))
@@ -175,6 +176,7 @@ struct mtk_pcie_soc {
/**
* struct mtk_pcie_port - PCIe port information
* @base: IO mapped register base
+ * @phys_base: Physical address of the I/O register base region
* @list: port list
* @pcie: pointer to PCIe host info
* @reset: pointer to port reset control
@@ -196,6 +198,7 @@ struct mtk_pcie_soc {
*/
struct mtk_pcie_port {
void __iomem *base;
+ phys_addr_t phys_base;
struct list_head list;
struct mtk_pcie *pcie;
struct reset_control *reset;
@@ -405,7 +408,7 @@ static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
phys_addr_t addr;
/* MT2712/MT7622 only support 32-bit MSI addresses */
- addr = virt_to_phys(port->base + PCIE_MSI_VECTOR);
+ addr = port->phys_base + PCIE_MSI_VECTOR;
msg->address_hi = 0;
msg->address_lo = lower_32_bits(addr);
@@ -520,7 +523,7 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
u32 val;
phys_addr_t msg_addr;
- msg_addr = virt_to_phys(port->base + PCIE_MSI_VECTOR);
+ msg_addr = port->phys_base + PCIE_MSI_VECTOR;
val = lower_32_bits(msg_addr);
writel(val, port->base + PCIE_IMSI_ADDR);
@@ -529,23 +532,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
writel(val, port->base + PCIE_INT_MASK);
}
-static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+static void mtk_pcie_irq_teardown_port(struct mtk_pcie_port *port)
{
- struct mtk_pcie_port *port, *tmp;
+ irq_set_chained_handler_and_data(port->irq, NULL, NULL);
- list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
- irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+ if (port->irq_domain)
+ irq_domain_remove(port->irq_domain);
- if (port->irq_domain)
- irq_domain_remove(port->irq_domain);
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+ if (port->inner_domain)
+ irq_domain_remove(port->inner_domain);
+ }
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- if (port->inner_domain)
- irq_domain_remove(port->inner_domain);
- }
+ irq_dispose_mapping(port->irq);
+}
- irq_dispose_mapping(port->irq);
- }
+static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+{
+ struct mtk_pcie_port *port, *tmp;
+
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list)
+ mtk_pcie_irq_teardown_port(port);
}
static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
@@ -865,7 +872,7 @@ static int mtk_pcie_startup_port_an7583(struct mtk_pcie_port *port)
return mtk_pcie_startup_port_v2(port);
}
-static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
+static int mtk_pcie_enable_port(struct mtk_pcie_port *port)
{
struct mtk_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
@@ -874,7 +881,7 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
err = clk_prepare_enable(port->sys_ck);
if (err) {
dev_err(dev, "failed to enable sys_ck%d clock\n", port->slot);
- goto err_sys_clk;
+ return err;
}
err = clk_prepare_enable(port->ahb_ck);
@@ -922,11 +929,15 @@ static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
goto err_phy_on;
}
- if (!pcie->soc->startup(port))
- return;
+ err = pcie->soc->startup(port);
+ if (err) {
+ dev_info(dev, "Port%d link down\n", port->slot);
+ goto err_soc_startup;
+ }
- dev_info(dev, "Port%d link down\n", port->slot);
+ return 0;
+err_soc_startup:
phy_power_off(port->phy);
err_phy_on:
phy_exit(port->phy);
@@ -942,8 +953,8 @@ err_aux_clk:
clk_disable_unprepare(port->ahb_ck);
err_ahb_clk:
clk_disable_unprepare(port->sys_ck);
-err_sys_clk:
- mtk_pcie_port_free(port);
+
+ return err;
}
static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
@@ -953,6 +964,7 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
struct mtk_pcie_port *port;
struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev);
+ struct resource *res;
char name[20];
int err;
@@ -961,7 +973,14 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
return -ENOMEM;
snprintf(name, sizeof(name), "port%d", slot);
- port->base = devm_platform_ioremap_resource_byname(pdev, name);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+ if (!res) {
+ dev_err(dev, "failed to get port%d base\n", slot);
+ return -EINVAL;
+ }
+
+ port->phys_base = res->start;
+ port->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(port->base)) {
dev_err(dev, "failed to map port%d base\n", slot);
return PTR_ERR(port->base);
@@ -1109,8 +1128,13 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
return err;
/* enable each port, and then check link status */
- list_for_each_entry_safe(port, tmp, &pcie->ports, list)
- mtk_pcie_enable_port(port);
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+ err = mtk_pcie_enable_port(port);
+ if (err) {
+ mtk_pcie_irq_teardown_port(port);
+ mtk_pcie_port_free(port);
+ }
+ }
/* power down PCIe subsys if slots are all empty (link down) */
if (list_empty(&pcie->ports))
@@ -1209,14 +1233,18 @@ static int mtk_pcie_resume_noirq(struct device *dev)
{
struct mtk_pcie *pcie = dev_get_drvdata(dev);
struct mtk_pcie_port *port, *tmp;
+ int err;
if (list_empty(&pcie->ports))
return 0;
clk_prepare_enable(pcie->free_ck);
- list_for_each_entry_safe(port, tmp, &pcie->ports, list)
- mtk_pcie_enable_port(port);
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+ err = mtk_pcie_enable_port(port);
+ if (err)
+ mtk_pcie_port_free(port);
+ }
/* In case of EP was removed while system suspend. */
if (list_empty(&pcie->ports))