From 51c6b14092761588a87d24330a3e37700e4be1b7 Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Sat, 18 Apr 2020 12:51:03 +0800 Subject: [PATCH] ramips: mt7621: backport more pcie driver fixes Signed-off-by: Chuanhong Guo --- target/linux/ramips/dts/mt7621.dtsi | 9 +- ...ci-properly-power-off-dual-ported-pc.patch | 65 ++++++++ ...t7621-pci-fix-PCIe-interrupt-mapping.patch | 157 ++++++++++++++++++ 3 files changed, 226 insertions(+), 5 deletions(-) create mode 100644 target/linux/ramips/patches-5.4/0120-staging-mt7621-pci-properly-power-off-dual-ported-pc.patch create mode 100644 target/linux/ramips/patches-5.4/0121-staging-mt7621-pci-fix-PCIe-interrupt-mapping.patch diff --git a/target/linux/ramips/dts/mt7621.dtsi b/target/linux/ramips/dts/mt7621.dtsi index 63befa1fdc..78979dc420 100644 --- a/target/linux/ramips/dts/mt7621.dtsi +++ b/target/linux/ramips/dts/mt7621.dtsi @@ -568,11 +568,10 @@ 0x01000000 0 0x00000000 0x1e160000 0 0x00010000 /* io space */ >; - #interrupt-cells = <1>; - interrupt-map-mask = <0xF0000 0 0 1>; - interrupt-map = <0x10000 0 0 1 &gic GIC_SHARED 4 IRQ_TYPE_LEVEL_HIGH>, - <0x20000 0 0 1 &gic GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH>, - <0x30000 0 0 1 &gic GIC_SHARED 25 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gic>; + interrupts = ; status = "disabled"; diff --git a/target/linux/ramips/patches-5.4/0120-staging-mt7621-pci-properly-power-off-dual-ported-pc.patch b/target/linux/ramips/patches-5.4/0120-staging-mt7621-pci-properly-power-off-dual-ported-pc.patch new file mode 100644 index 0000000000..9efcb8011a --- /dev/null +++ b/target/linux/ramips/patches-5.4/0120-staging-mt7621-pci-properly-power-off-dual-ported-pc.patch @@ -0,0 +1,65 @@ +From 5fcded5e857cf66c9592e4be28c4dab4520c9177 Mon Sep 17 00:00:00 2001 +From: Sergio Paracuellos +Date: Thu, 9 Apr 2020 13:16:52 +0200 +Subject: [PATCH] staging: mt7621-pci: properly power off dual-ported pcie phy + +Pcie phy for pcie0 and pcie1 is shared using a dual ported +one. Current code was assuming that if nothing is connected +in pcie0 it won't be also nothing connected in pcie1. This +assumtion is wrong for some devices such us 'Mikrotik rbm33g' +and 'ZyXEL LTE3301-PLUS' where only connecting a card to the +second bus on the phy is possible. For such devices kernel +hangs in the same point because of the wrong poweroff of the +phy getting the following trace: + +mt7621-pci-phy 1e149000.pcie-phy: PHY for 0xbe149000 (dual port = 1) +mt7621-pci-phy 1e14a000.pcie-phy: PHY for 0xbe14a000 (dual port = 0) +mt7621-pci-phy 1e149000.pcie-phy: Xtal is 40MHz +mt7621-pci-phy 1e14a000.pcie-phy: Xtal is 40MHz +mt7621-pci 1e140000.pcie: pcie0 no card, disable it (RST & CLK) +[hangs] + +The wrong assumption is located in the 'mt7621_pcie_init_ports' +function where we are just making a power off of the phy for +slots 0 and 2 if nothing is connected in them. Hence, only +poweroff the phy if nothing is connected in both slot 0 and +slot 1 avoiding the kernel to hang. + +Fixes: 5737cfe87a9c ("staging: mt7621-pci: avoid to poweroff the phy for slot one") +Signed-off-by: Sergio Paracuellos +Link: https://lore.kernel.org/r/20200409111652.30964-1-sergio.paracuellos@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/mt7621-pci/pci-mt7621.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/staging/mt7621-pci/pci-mt7621.c ++++ b/drivers/staging/mt7621-pci/pci-mt7621.c +@@ -502,17 +502,25 @@ static void mt7621_pcie_init_ports(struc + + mt7621_pcie_reset_ep_deassert(pcie); + ++ tmp = NULL; + list_for_each_entry(port, &pcie->ports, list) { + u32 slot = port->slot; + + if (!mt7621_pcie_port_is_linkup(port)) { + dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n", + slot); +- if (slot != 1) +- phy_power_off(port->phy); + mt7621_control_assert(port); + mt7621_pcie_port_clk_disable(port); + port->enabled = false; ++ ++ if (slot == 0) { ++ tmp = port; ++ continue; ++ } ++ ++ if (slot == 1 && tmp && !tmp->enabled) ++ phy_power_off(tmp->phy); ++ + } + } + } diff --git a/target/linux/ramips/patches-5.4/0121-staging-mt7621-pci-fix-PCIe-interrupt-mapping.patch b/target/linux/ramips/patches-5.4/0121-staging-mt7621-pci-fix-PCIe-interrupt-mapping.patch new file mode 100644 index 0000000000..68de6df2db --- /dev/null +++ b/target/linux/ramips/patches-5.4/0121-staging-mt7621-pci-fix-PCIe-interrupt-mapping.patch @@ -0,0 +1,157 @@ +From fab6710e4c51f4eb622f95a08322ab5fdbe3f295 Mon Sep 17 00:00:00 2001 +From: Sergio Paracuellos +Date: Mon, 13 Apr 2020 07:59:42 +0200 +Subject: [PATCH] staging: mt7621-pci: fix PCIe interrupt mapping + +MT7621 has three assigned interrupts for the pcie. This +interrupts should properly being mapped taking into account +which devices are finally connected in which bus according +to link status. So the irq mappings should be as follows +according to link status (three bits indicating which devices +are link up): + +* For PCIe Bus 1 slot 0: + - status = 0x2 || status = 0x6 => IRQ = pcie1_irq (24). + - status = 0x4 => IRQ = pcie2_irq (25). + - default => IRQ = pcie0_irq (23). +* For PCIe Bus 2 slot 0: + - status = 0x5 || status = 0x6 => IRQ = pcie2_irq (25). + - default => IRQ = pcie1_irq (24). +* For PCIe Bus 2 slot 1: + - status = 0x5 || status = 0x6 => IRQ = pcie2_irq (25). + - default => IRQ = pcie1_irq (24). +* For PCIe Bus 3 any slot: + - default => IRQ = pcie2_irq (25). + +Because of this, the function 'of_irq_parse_and_map_pci' cannot +be used and we need to change device tree information from using +the 'interrupt-map' and 'interrupt-map-mask' properties into an +'interrupts' property to be able to get irq information from the +ports using the 'platform_get_irq' and storing an 'irq-map' into +the pcie driver data node to properly map correct irq using a +new 'mt7621_map_irq' function where this map will be read and the +correct irq returned. + +Fixes: 46d093124df4 ("staging: mt7621-pci: improve interrupt mapping") +Signed-off-by: Sergio Paracuellos +Link: https://lore.kernel.org/r/20200413055942.2714-1-sergio.paracuellos@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/mt7621-dts/mt7621.dtsi | 9 +++---- + drivers/staging/mt7621-pci/pci-mt7621.c | 36 +++++++++++++++++++++++-- + 2 files changed, 38 insertions(+), 7 deletions(-) + +--- a/drivers/staging/mt7621-pci/pci-mt7621.c ++++ b/drivers/staging/mt7621-pci/pci-mt7621.c +@@ -97,6 +97,7 @@ + * @pcie_rst: pointer to port reset control + * @gpio_rst: gpio reset + * @slot: port slot ++ * @irq: GIC irq + * @enabled: indicates if port is enabled + */ + struct mt7621_pcie_port { +@@ -107,6 +108,7 @@ struct mt7621_pcie_port { + struct reset_control *pcie_rst; + struct gpio_desc *gpio_rst; + u32 slot; ++ int irq; + bool enabled; + }; + +@@ -120,6 +122,7 @@ struct mt7621_pcie_port { + * @dev: Pointer to PCIe device + * @io_map_base: virtual memory base address for io + * @ports: pointer to PCIe port information ++ * @irq_map: irq mapping info according pcie link status + * @resets_inverted: depends on chip revision + * reset lines are inverted. + */ +@@ -135,6 +138,7 @@ struct mt7621_pcie { + } offset; + unsigned long io_map_base; + struct list_head ports; ++ int irq_map[PCIE_P2P_MAX]; + bool resets_inverted; + }; + +@@ -279,6 +283,16 @@ static void setup_cm_memory_region(struc + } + } + ++static int mt7621_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) ++{ ++ struct mt7621_pcie *pcie = pdev->bus->sysdata; ++ struct device *dev = pcie->dev; ++ int irq = pcie->irq_map[slot]; ++ ++ dev_info(dev, "bus=%d slot=%d irq=%d\n", pdev->bus->number, slot, irq); ++ return irq; ++} ++ + static int mt7621_pci_parse_request_of_pci_ranges(struct mt7621_pcie *pcie) + { + struct device *dev = pcie->dev; +@@ -330,6 +344,7 @@ static int mt7621_pcie_parse_port(struct + { + struct mt7621_pcie_port *port; + struct device *dev = pcie->dev; ++ struct platform_device *pdev = to_platform_device(dev); + struct device_node *pnode = dev->of_node; + struct resource regs; + char name[10]; +@@ -371,6 +386,12 @@ static int mt7621_pcie_parse_port(struct + port->slot = slot; + port->pcie = pcie; + ++ port->irq = platform_get_irq(pdev, slot); ++ if (port->irq < 0) { ++ dev_err(dev, "Failed to get IRQ for PCIe%d\n", slot); ++ return -ENXIO; ++ } ++ + INIT_LIST_HEAD(&port->list); + list_add_tail(&port->list, &pcie->ports); + +@@ -585,13 +606,15 @@ static int mt7621_pcie_init_virtual_brid + { + u32 pcie_link_status = 0; + u32 n; +- int i; ++ int i = 0; + u32 p2p_br_devnum[PCIE_P2P_MAX]; ++ int irqs[PCIE_P2P_MAX]; + struct mt7621_pcie_port *port; + + list_for_each_entry(port, &pcie->ports, list) { + u32 slot = port->slot; + ++ irqs[i++] = port->irq; + if (port->enabled) + pcie_link_status |= BIT(slot); + } +@@ -614,6 +637,15 @@ static int mt7621_pcie_init_virtual_brid + (p2p_br_devnum[1] << PCIE_P2P_BR_DEVNUM1_SHIFT) | + (p2p_br_devnum[2] << PCIE_P2P_BR_DEVNUM2_SHIFT)); + ++ /* Assign IRQs */ ++ n = 0; ++ for (i = 0; i < PCIE_P2P_MAX; i++) ++ if (pcie_link_status & BIT(i)) ++ pcie->irq_map[n++] = irqs[i]; ++ ++ for (i = n; i < PCIE_P2P_MAX; i++) ++ pcie->irq_map[i] = -1; ++ + return 0; + } + +@@ -638,7 +670,7 @@ static int mt7621_pcie_register_host(str + host->busnr = pcie->busn.start; + host->dev.parent = pcie->dev; + host->ops = &mt7621_pci_ops; +- host->map_irq = of_irq_parse_and_map_pci; ++ host->map_irq = mt7621_map_irq; + host->swizzle_irq = pci_common_swizzle; + host->sysdata = pcie; +