From 17a0a1e5f6c4bd6df17834312ff577c1373d87b8 Mon Sep 17 00:00:00 2001 From: Gustavo A. R. Silva Date: Fri, 20 Jul 2018 10:01:58 -0500 Subject: PCI: mediatek: Fix unchecked return value Check return value of devm_pci_remap_iospace(). Addresses-Coverity-ID: 1471965 ("Unchecked return value") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Lorenzo Pieralisi Acked-by: Honghui Zhang --- drivers/pci/controller/pcie-mediatek.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller/pcie-mediatek.c') diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 861dda69f366..1477939ef38a 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -1109,7 +1109,9 @@ static int mtk_pcie_request_resources(struct mtk_pcie *pcie) if (err < 0) return err; - devm_pci_remap_iospace(dev, &pcie->pio, pcie->io.start); + err = devm_pci_remap_iospace(dev, &pcie->pio, pcie->io.start); + if (err) + return err; return 0; } -- cgit v1.2.3-55-g7522 From 074d6f32689ce05a084b6fa3db38445745bf11cc Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:52 +0800 Subject: PCI: mediatek: Fix mtk_pcie_find_port() endpoint/port matching logic The Mediatek's host controller has two slots, each with its own control registers. The host driver needs to identify what slot is connected to what port in order to access the device's configuration space. Current code retrieving slot connected to a given endpoint device. Assuming each slot is connected to one endpoint device as below: host bridge bus 0 --> __________|_______ | | | | slot 0 slot 1 bus 1 -->| bus 2 --> | | | EP 0 EP 1 During PCI enumeration, system software will scan all the PCI devices on every bus starting from devfn 0. Using PCI_SLOT(devfn) for matching an endpoint to its slot is erroneous in that the devfn does not contain the hierarchical bus numbering in it. In order to match an endpoint with its slot (and related port), the PCI tree must be walked up to the root bus (where the root ports are situated) and then the PCI_SLOT(devfn) matching logic can be correctly applied for matching. This patch fixes the mtk_pcie_find_port() slot matching logic by adding appropriate PCI tree walking code to retrieve the slot/port a given endpoint is connected to. Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: rewrote the commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee --- drivers/pci/controller/pcie-mediatek.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/pci/controller/pcie-mediatek.c') diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 1477939ef38a..0d100f56cb88 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -337,6 +337,17 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct pci_bus *bus, { struct mtk_pcie *pcie = bus->sysdata; struct mtk_pcie_port *port; + struct pci_dev *dev = NULL; + + /* + * Walk the bus hierarchy to get the devfn value + * of the port in the root bus. + */ + while (bus && bus->number) { + dev = bus->self; + bus = dev->bus; + devfn = dev->devfn; + } list_for_each_entry(port, &pcie->ports, list) if (port->slot == PCI_SLOT(devfn)) -- cgit v1.2.3-55-g7522 From a7f172ab6a8e755e60311f27512034b0441ef421 Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:53 +0800 Subject: PCI: mediatek: Fix class type for MT7622 to PCI_CLASS_BRIDGE_PCI commit 101c92dc80c8 ("PCI: mediatek: Set up vendor ID and class type for MT7622") erroneously set the class type for MT7622 to PCI_CLASS_BRIDGE_HOST. The PCIe controller of MT7622 integrates a Root Port that has type 1 configuration space header and related bridge windows. The HW default value of this bridge's class type is invalid. Fix its class type and set it to PCI_CLASS_BRIDGE_PCI to match the hardware implementation. Fixes: 101c92dc80c8 ("PCI: mediatek: Set up vendor ID and class type for MT7622") Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: reworked the commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee --- drivers/pci/controller/pcie-mediatek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller/pcie-mediatek.c') diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 0d100f56cb88..8d1364c31774 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -432,7 +432,7 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port) val = PCI_VENDOR_ID_MEDIATEK; writew(val, port->base + PCIE_CONF_VEND_ID); - val = PCI_CLASS_BRIDGE_HOST; + val = PCI_CLASS_BRIDGE_PCI; writew(val, port->base + PCIE_CONF_CLASS_ID); } -- cgit v1.2.3-55-g7522 From 88c0e230bb4a79680ee5f05ddba879d436f98f13 Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:54 +0800 Subject: PCI: mediatek: Remove the redundant dev->pm_domain check There is no need to check whether device have a PM domain attached before calling the PM runtime methods. Remove it. Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: commit log changes] Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee --- drivers/pci/controller/pcie-mediatek.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/pci/controller/pcie-mediatek.c') diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 8d1364c31774..547e4c76edbb 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -225,10 +225,8 @@ static void mtk_pcie_subsys_powerdown(struct mtk_pcie *pcie) clk_disable_unprepare(pcie->free_ck); - if (dev->pm_domain) { - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); - } + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); } static void mtk_pcie_port_free(struct mtk_pcie_port *port) @@ -998,10 +996,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie) pcie->free_ck = NULL; } - if (dev->pm_domain) { - pm_runtime_enable(dev); - pm_runtime_get_sync(dev); - } + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); /* enable top level clock */ err = clk_prepare_enable(pcie->free_ck); @@ -1013,10 +1009,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie) return 0; err_free_ck: - if (dev->pm_domain) { - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); - } + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); return err; } -- cgit v1.2.3-55-g7522 From 57cb3152b360eabf30d498515dcf9049f3c7b9df Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:55 +0800 Subject: PCI: mediatek: Convert to use pci_host_probe() Part of mtk_pcie_register_host() is an open-coded version of pci_host_probe(). So instead of duplicating this code, use pci_host_probe() directly and remove mtk_pcie_register_host(). Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: commit log changes] Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee --- drivers/pci/controller/pcie-mediatek.c | 37 ++++++++-------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) (limited to 'drivers/pci/controller/pcie-mediatek.c') diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 547e4c76edbb..6f0849049041 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -1121,34 +1121,6 @@ static int mtk_pcie_request_resources(struct mtk_pcie *pcie) return 0; } -static int mtk_pcie_register_host(struct pci_host_bridge *host) -{ - struct mtk_pcie *pcie = pci_host_bridge_priv(host); - struct pci_bus *child; - int err; - - host->busnr = pcie->busn.start; - host->dev.parent = pcie->dev; - host->ops = pcie->soc->ops; - host->map_irq = of_irq_parse_and_map_pci; - host->swizzle_irq = pci_common_swizzle; - host->sysdata = pcie; - - err = pci_scan_root_bus_bridge(host); - if (err < 0) - return err; - - pci_bus_size_bridges(host->bus); - pci_bus_assign_resources(host->bus); - - list_for_each_entry(child, &host->bus->children, node) - pcie_bus_configure_settings(child); - - pci_bus_add_devices(host->bus); - - return 0; -} - static int mtk_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1175,7 +1147,14 @@ static int mtk_pcie_probe(struct platform_device *pdev) if (err) goto put_resources; - err = mtk_pcie_register_host(host); + host->busnr = pcie->busn.start; + host->dev.parent = pcie->dev; + host->ops = pcie->soc->ops; + host->map_irq = of_irq_parse_and_map_pci; + host->swizzle_irq = pci_common_swizzle; + host->sysdata = pcie; + + err = pci_host_probe(host); if (err) goto put_resources; -- cgit v1.2.3-55-g7522 From 3828d60fd2ef99f97a677c1f95af2ab3e65e2576 Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:56 +0800 Subject: PCI: mediatek: Fixup MSI enablement logic by enabling MSI before clocks Commit 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622") added MSI support but enabled MSI in the wrong place, at a step in the probe sequence where clocks were not still enabled. Fix this issue by calling mtk_pcie_enable_msi() in mtk_pcie_startup_port_v2() since clocks are enabled when mtk_pcie_startup_port_v2() is called. To avoid forward declaration of mtk_pcie_enable_msi(), move the mtk_pcie_startup_port_v2() function definition in the file. Fixes: 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622") Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: squashed commit and adapted log] Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee --- drivers/pci/controller/pcie-mediatek.c | 143 +++++++++++++++++---------------- 1 file changed, 72 insertions(+), 71 deletions(-) (limited to 'drivers/pci/controller/pcie-mediatek.c') diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 6f0849049041..aa900b0f0a40 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -392,75 +392,6 @@ static struct pci_ops mtk_pcie_ops_v2 = { .write = mtk_pcie_config_write, }; -static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port) -{ - struct mtk_pcie *pcie = port->pcie; - struct resource *mem = &pcie->mem; - const struct mtk_pcie_soc *soc = port->pcie->soc; - u32 val; - size_t size; - int err; - - /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */ - if (pcie->base) { - val = readl(pcie->base + PCIE_SYS_CFG_V2); - val |= PCIE_CSR_LTSSM_EN(port->slot) | - PCIE_CSR_ASPM_L1_EN(port->slot); - writel(val, pcie->base + PCIE_SYS_CFG_V2); - } - - /* Assert all reset signals */ - writel(0, port->base + PCIE_RST_CTRL); - - /* - * Enable PCIe link down reset, if link status changed from link up to - * link down, this will reset MAC control registers and configuration - * space. - */ - writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL); - - /* De-assert PHY, PE, PIPE, MAC and configuration reset */ - val = readl(port->base + PCIE_RST_CTRL); - val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB | - PCIE_MAC_SRSTB | PCIE_CRSTB; - writel(val, port->base + PCIE_RST_CTRL); - - /* Set up vendor ID and class code */ - if (soc->need_fix_class_id) { - val = PCI_VENDOR_ID_MEDIATEK; - writew(val, port->base + PCIE_CONF_VEND_ID); - - val = PCI_CLASS_BRIDGE_PCI; - writew(val, port->base + PCIE_CONF_CLASS_ID); - } - - /* 100ms timeout value should be enough for Gen1/2 training */ - err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val, - !!(val & PCIE_PORT_LINKUP_V2), 20, - 100 * USEC_PER_MSEC); - if (err) - return -ETIMEDOUT; - - /* Set INTx mask */ - val = readl(port->base + PCIE_INT_MASK); - val &= ~INTX_MASK; - writel(val, port->base + PCIE_INT_MASK); - - /* Set AHB to PCIe translation windows */ - size = mem->end - mem->start; - val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size)); - writel(val, port->base + PCIE_AHB_TRANS_BASE0_L); - - val = upper_32_bits(mem->start); - writel(val, port->base + PCIE_AHB_TRANS_BASE0_H); - - /* Set PCIe to AXI translation memory space.*/ - val = fls(0xffffffff) | WIN_ENABLE; - writel(val, port->base + PCIE_AXI_WINDOW0); - - return 0; -} - static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) { struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); @@ -637,8 +568,6 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, ret = mtk_pcie_allocate_msi_domains(port); if (ret) return ret; - - mtk_pcie_enable_msi(port); } return 0; @@ -705,6 +634,78 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, return 0; } +static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port) +{ + struct mtk_pcie *pcie = port->pcie; + struct resource *mem = &pcie->mem; + const struct mtk_pcie_soc *soc = port->pcie->soc; + u32 val; + size_t size; + int err; + + /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */ + if (pcie->base) { + val = readl(pcie->base + PCIE_SYS_CFG_V2); + val |= PCIE_CSR_LTSSM_EN(port->slot) | + PCIE_CSR_ASPM_L1_EN(port->slot); + writel(val, pcie->base + PCIE_SYS_CFG_V2); + } + + /* Assert all reset signals */ + writel(0, port->base + PCIE_RST_CTRL); + + /* + * Enable PCIe link down reset, if link status changed from link up to + * link down, this will reset MAC control registers and configuration + * space. + */ + writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL); + + /* De-assert PHY, PE, PIPE, MAC and configuration reset */ + val = readl(port->base + PCIE_RST_CTRL); + val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB | + PCIE_MAC_SRSTB | PCIE_CRSTB; + writel(val, port->base + PCIE_RST_CTRL); + + /* Set up vendor ID and class code */ + if (soc->need_fix_class_id) { + val = PCI_VENDOR_ID_MEDIATEK; + writew(val, port->base + PCIE_CONF_VEND_ID); + + val = PCI_CLASS_BRIDGE_PCI; + writew(val, port->base + PCIE_CONF_CLASS_ID); + } + + /* 100ms timeout value should be enough for Gen1/2 training */ + err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val, + !!(val & PCIE_PORT_LINKUP_V2), 20, + 100 * USEC_PER_MSEC); + if (err) + return -ETIMEDOUT; + + /* Set INTx mask */ + val = readl(port->base + PCIE_INT_MASK); + val &= ~INTX_MASK; + writel(val, port->base + PCIE_INT_MASK); + + if (IS_ENABLED(CONFIG_PCI_MSI)) + mtk_pcie_enable_msi(port); + + /* Set AHB to PCIe translation windows */ + size = mem->end - mem->start; + val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size)); + writel(val, port->base + PCIE_AHB_TRANS_BASE0_L); + + val = upper_32_bits(mem->start); + writel(val, port->base + PCIE_AHB_TRANS_BASE0_H); + + /* Set PCIe to AXI translation memory space.*/ + val = fls(0xffffffff) | WIN_ENABLE; + writel(val, port->base + PCIE_AXI_WINDOW0); + + return 0; +} + static void __iomem *mtk_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, int where) { -- cgit v1.2.3-55-g7522 From 97d2932fee4b0607bad4f71a8d2c0938f596b1c3 Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:58 +0800 Subject: PCI: mediatek: Add system PM support for MT2712 and MT7622 In order to reduce the PCIe power consumption in system suspend, the PCI bus physical layer should be gated. On system resume, the PCIe link should be re-established and the related control register values should be restored. Define suspend_noirq & resume_noirq callback functions to implement PM system syspend hooks for the PCI host controller. Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee --- drivers/pci/controller/pcie-mediatek.c | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers/pci/controller/pcie-mediatek.c') diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index aa900b0f0a40..5f042316c3a8 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -1168,6 +1168,55 @@ put_resources: return err; } +static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev) +{ + struct mtk_pcie *pcie = dev_get_drvdata(dev); + struct mtk_pcie_port *port; + + if (list_empty(&pcie->ports)) + return 0; + + list_for_each_entry(port, &pcie->ports, list) { + clk_disable_unprepare(port->pipe_ck); + clk_disable_unprepare(port->obff_ck); + clk_disable_unprepare(port->axi_ck); + clk_disable_unprepare(port->aux_ck); + clk_disable_unprepare(port->ahb_ck); + clk_disable_unprepare(port->sys_ck); + phy_power_off(port->phy); + phy_exit(port->phy); + } + + clk_disable_unprepare(pcie->free_ck); + + return 0; +} + +static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev) +{ + struct mtk_pcie *pcie = dev_get_drvdata(dev); + struct mtk_pcie_port *port, *tmp; + + 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); + + /* In case of EP was removed while system suspend. */ + if (list_empty(&pcie->ports)) + clk_disable_unprepare(pcie->free_ck); + + return 0; +} + +static const struct dev_pm_ops mtk_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq, + mtk_pcie_resume_noirq) +}; + static const struct mtk_pcie_soc mtk_pcie_soc_v1 = { .ops = &mtk_pcie_ops, .startup = mtk_pcie_startup_port, @@ -1200,6 +1249,7 @@ static struct platform_driver mtk_pcie_driver = { .name = "mtk-pcie", .of_match_table = mtk_pcie_ids, .suppress_bind_attrs = true, + .pm = &mtk_pcie_pm_ops, }, }; builtin_platform_driver(mtk_pcie_driver); -- cgit v1.2.3-55-g7522 From 031337ace2d1c22a447da6390716fe92592cdd6e Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 15 Oct 2018 16:08:59 +0800 Subject: PCI: mediatek: Add loadable kernel module support Implement remove() callback function for the Mediatek PCIe controller driver to add loadable kernel module support. Save the PCIe's GIC IRQ at probe so that it can be retrieved to call dispose_irq() to tear down the IRQ upon module removal. Signed-off-by: Honghui Zhang [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Ryder Lee --- drivers/pci/controller/Kconfig | 2 +- drivers/pci/controller/pcie-mediatek.c | 60 +++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 5 deletions(-) (limited to 'drivers/pci/controller/pcie-mediatek.c') diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 028b287466fb..465790fc665a 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -231,7 +231,7 @@ config PCIE_ROCKCHIP_EP available to support GEN2 with 4 slots. config PCIE_MEDIATEK - bool "MediaTek PCIe controller" + tristate "MediaTek PCIe controller" depends on ARCH_MEDIATEK || COMPILE_TEST depends on OF depends on PCI_MSI_IRQ_DOMAIN diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 5f042316c3a8..d069a76cbb95 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -162,6 +163,7 @@ struct mtk_pcie_soc { * @phy: pointer to PHY control block * @lane: lane count * @slot: port slot + * @irq: GIC irq * @irq_domain: legacy INTx IRQ domain * @inner_domain: inner IRQ domain * @msi_domain: MSI IRQ domain @@ -182,6 +184,7 @@ struct mtk_pcie_port { struct phy *phy; u32 lane; u32 slot; + int irq; struct irq_domain *irq_domain; struct irq_domain *inner_domain; struct irq_domain *msi_domain; @@ -530,6 +533,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) +{ + struct mtk_pcie_port *port, *tmp; + + 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 (IS_ENABLED(CONFIG_PCI_MSI)) { + if (port->msi_domain) + irq_domain_remove(port->msi_domain); + if (port->inner_domain) + irq_domain_remove(port->inner_domain); + } + + irq_dispose_mapping(port->irq); + } +} + static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq, irq_hw_number_t hwirq) { @@ -620,7 +644,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, struct mtk_pcie *pcie = port->pcie; struct device *dev = pcie->dev; struct platform_device *pdev = to_platform_device(dev); - int err, irq; + int err; err = mtk_pcie_init_irq_domain(port, node); if (err) { @@ -628,8 +652,9 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, return err; } - irq = platform_get_irq(pdev, port->slot); - irq_set_chained_handler_and_data(irq, mtk_pcie_intr_handler, port); + port->irq = platform_get_irq(pdev, port->slot); + irq_set_chained_handler_and_data(port->irq, + mtk_pcie_intr_handler, port); return 0; } @@ -1168,6 +1193,31 @@ put_resources: return err; } + +static void mtk_pcie_free_resources(struct mtk_pcie *pcie) +{ + struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); + struct list_head *windows = &host->windows; + + pci_free_resource_list(windows); +} + +static int mtk_pcie_remove(struct platform_device *pdev) +{ + struct mtk_pcie *pcie = platform_get_drvdata(pdev); + struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); + + pci_stop_root_bus(host->bus); + pci_remove_root_bus(host->bus); + mtk_pcie_free_resources(pcie); + + mtk_pcie_irq_teardown(pcie); + + mtk_pcie_put_resources(pcie); + + return 0; +} + static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev) { struct mtk_pcie *pcie = dev_get_drvdata(dev); @@ -1245,6 +1295,7 @@ static const struct of_device_id mtk_pcie_ids[] = { static struct platform_driver mtk_pcie_driver = { .probe = mtk_pcie_probe, + .remove = mtk_pcie_remove, .driver = { .name = "mtk-pcie", .of_match_table = mtk_pcie_ids, @@ -1252,4 +1303,5 @@ static struct platform_driver mtk_pcie_driver = { .pm = &mtk_pcie_pm_ops, }, }; -builtin_platform_driver(mtk_pcie_driver); +module_platform_driver(mtk_pcie_driver); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-55-g7522