It is based on Chuanhong Guo work.

PCI interrupt controller is not part of PCI. It is a part of reset controller
with 0x18060018, 0x1806001c control registers.

This should fix a bug with one IRQ for all PCI devices and also handle the 
PCI_CORE interrupt.

I am not sure that this kind of cascading is good for performance, but this way 
we are more flexible when cofiguring IRQs.

Run tested on DIR-825 B1.
---
 target/linux/ath79/dts/ar7100.dtsi                 |  22 ++-
 ...turn-pci-ar71xx-driver-into-a-pure-OF-dri.patch | 168 ++++++++---------
 .../0036-MIPS-ath79-add-pci-intc.patch             | 205 +++++++++++++++++++++
 3 files changed, 306 insertions(+), 89 deletions(-)
 create mode 100644 
target/linux/ath79/patches-4.14/0036-MIPS-ath79-add-pci-intc.patch

diff --git a/target/linux/ath79/dts/ar7100.dtsi 
b/target/linux/ath79/dts/ar7100.dtsi
index 8994a7d..6dc1751 100644
--- a/target/linux/ath79/dts/ar7100.dtsi
+++ b/target/linux/ath79/dts/ar7100.dtsi
@@ -96,6 +96,16 @@
                                #reset-cells = <1>;
                        };
 
+                       pci_intc: interrupt-controller@18060018 {
+                               compatible = "qca,ar7100-pci-intc";
+                               reg = <0x18060018 0x4>;
+                               interrupt-parent = <&cpuintc>;
+                               interrupts = <2>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                       };
+
+
                        pcie0: pcie-controller@180c0000 {
                                compatible = "qca,ar7100-pci";
                                #address-cells = <3>;
@@ -105,14 +115,16 @@
                                reg-names = "cfg_base";
                                ranges = <0x2000000 0 0x10000000 0x10000000 0 
0x07000000        /* pci memory */
                                          0x1000000 0 0x00000000 0x0000000 0 
0x000001>;         /* io space */
-                               interrupt-parent = <&cpuintc>;
-                               interrupts = <2>;
+                               interrupt-parent = <&pci_intc>;
+                               interrupts = <4>;
 
-                               interrupt-controller;
                                #interrupt-cells = <1>;
 
-                               interrupt-map-mask = <0 0 0 1>;
-                               interrupt-map = <0 0 0 0 &pcie0 0>;
+                               interrupt-map-mask = <0xf800 0 0 0>;
+                               interrupt-map = <0x8800 0 0 0 &pci_intc 1
+                                                0x9000 0 0 0 &pci_intc 2
+                                                0x9800 0 0 0 &pci_intc 3>;
+
                                status = "disabled";
                        };
                };
diff --git 
a/target/linux/ath79/patches-4.14/0020-MIPS-ath79-turn-pci-ar71xx-driver-into-a-pure-OF-dri.patch
 
b/target/linux/ath79/patches-4.14/0020-MIPS-ath79-turn-pci-ar71xx-driver-into-a-pure-OF-dri.patch
index ea3514a..95ca6d1 100644
--- 
a/target/linux/ath79/patches-4.14/0020-MIPS-ath79-turn-pci-ar71xx-driver-into-a-pure-OF-dri.patch
+++ 
b/target/linux/ath79/patches-4.14/0020-MIPS-ath79-turn-pci-ar71xx-driver-into-a-pure-OF-dri.patch
@@ -9,8 +9,10 @@ Signed-off-by: John Crispin <[email protected]>
  arch/mips/pci/pci-ar71xx.c | 81 +++++++++++++++++++++++-----------------------
  1 file changed, 40 insertions(+), 41 deletions(-)
 
---- a/arch/mips/pci/pci-ar71xx.c
-+++ b/arch/mips/pci/pci-ar71xx.c
+Index: linux-4.14.65/arch/mips/pci/pci-ar71xx.c
+===================================================================
+--- linux-4.14.65.orig/arch/mips/pci/pci-ar71xx.c
++++ linux-4.14.65/arch/mips/pci/pci-ar71xx.c
 @@ -18,8 +18,11 @@
  #include <linux/pci.h>
  #include <linux/pci_regs.h>
@@ -38,89 +40,86 @@ Signed-off-by: John Crispin <[email protected]>
  };
  
  /* Byte lane enable bits */
-@@ -228,29 +232,30 @@ static struct pci_ops ar71xx_pci_ops = {
+@@ -226,96 +230,6 @@ static struct pci_ops ar71xx_pci_ops = {
+       .write  = ar71xx_pci_write_config,
+ };
  
- static void ar71xx_pci_irq_handler(struct irq_desc *desc)
- {
+-static void ar71xx_pci_irq_handler(struct irq_desc *desc)
+-{
 -      struct ar71xx_pci_controller *apc;
-       void __iomem *base = ath79_reset_base;
-+      struct irq_chip *chip = irq_desc_get_chip(desc);
-+      struct ar71xx_pci_controller *apc = irq_desc_get_handler_data(desc);
-       u32 pending;
- 
+-      void __iomem *base = ath79_reset_base;
+-      u32 pending;
+-
 -      apc = irq_desc_get_handler_data(desc);
 -
-+      chained_irq_enter(chip, desc);
-       pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) &
-                 __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
- 
-       if (pending & AR71XX_PCI_INT_DEV0)
+-      pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) &
+-                __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-
+-      if (pending & AR71XX_PCI_INT_DEV0)
 -              generic_handle_irq(apc->irq_base + 0);
-+              generic_handle_irq(irq_linear_revmap(apc->domain, 1));
- 
-       else if (pending & AR71XX_PCI_INT_DEV1)
+-
+-      else if (pending & AR71XX_PCI_INT_DEV1)
 -              generic_handle_irq(apc->irq_base + 1);
-+              generic_handle_irq(irq_linear_revmap(apc->domain, 2));
- 
-       else if (pending & AR71XX_PCI_INT_DEV2)
+-
+-      else if (pending & AR71XX_PCI_INT_DEV2)
 -              generic_handle_irq(apc->irq_base + 2);
-+              generic_handle_irq(irq_linear_revmap(apc->domain, 3));
- 
-       else if (pending & AR71XX_PCI_INT_CORE)
+-
+-      else if (pending & AR71XX_PCI_INT_CORE)
 -              generic_handle_irq(apc->irq_base + 4);
-+              generic_handle_irq(irq_linear_revmap(apc->domain, 4));
- 
-       else
-               spurious_interrupt();
-+      chained_irq_exit(chip, desc);
- }
- 
- static void ar71xx_pci_irq_unmask(struct irq_data *d)
-@@ -261,7 +266,7 @@ static void ar71xx_pci_irq_unmask(struct
-       u32 t;
- 
-       apc = irq_data_get_irq_chip_data(d);
+-
+-      else
+-              spurious_interrupt();
+-}
+-
+-static void ar71xx_pci_irq_unmask(struct irq_data *d)
+-{
+-      struct ar71xx_pci_controller *apc;
+-      unsigned int irq;
+-      void __iomem *base = ath79_reset_base;
+-      u32 t;
+-
+-      apc = irq_data_get_irq_chip_data(d);
 -      irq = d->irq - apc->irq_base;
-+      irq = irq_linear_revmap(apc->domain, d->irq);
- 
-       t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
-       __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
-@@ -278,7 +283,7 @@ static void ar71xx_pci_irq_mask(struct i
-       u32 t;
- 
-       apc = irq_data_get_irq_chip_data(d);
+-
+-      t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-      __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-
+-      /* flush write */
+-      __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-}
+-
+-static void ar71xx_pci_irq_mask(struct irq_data *d)
+-{
+-      struct ar71xx_pci_controller *apc;
+-      unsigned int irq;
+-      void __iomem *base = ath79_reset_base;
+-      u32 t;
+-
+-      apc = irq_data_get_irq_chip_data(d);
 -      irq = d->irq - apc->irq_base;
-+      irq = irq_linear_revmap(apc->domain, d->irq);
- 
-       t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
-       __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
-@@ -294,24 +299,30 @@ static struct irq_chip ar71xx_pci_irq_ch
-       .irq_mask_ack   = ar71xx_pci_irq_mask,
- };
- 
-+static int ar71xx_pci_irq_map(struct irq_domain *d, unsigned int irq, 
irq_hw_number_t hw)
-+{
-+      struct ar71xx_pci_controller *apc = d->host_data;
-+
-+      irq_set_chip_and_handler(irq, &ar71xx_pci_irq_chip, handle_level_irq);
-+      irq_set_chip_data(irq, apc);
-+
-+      return 0;
-+}
-+
-+static const struct irq_domain_ops ar71xx_pci_domain_ops = {
-+      .xlate = irq_domain_xlate_onecell,
-+      .map = ar71xx_pci_irq_map,
-+};
-+
- static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc)
- {
-       void __iomem *base = ath79_reset_base;
+-
+-      t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-      __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-
+-      /* flush write */
+-      __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-}
+-
+-static struct irq_chip ar71xx_pci_irq_chip = {
+-      .name           = "AR71XX PCI",
+-      .irq_mask       = ar71xx_pci_irq_mask,
+-      .irq_unmask     = ar71xx_pci_irq_unmask,
+-      .irq_mask_ack   = ar71xx_pci_irq_mask,
+-};
+-
+-static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc)
+-{
+-      void __iomem *base = ath79_reset_base;
 -      int i;
- 
-       __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE);
-       __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS);
- 
+-
+-      __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-      __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS);
+-
 -      BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR71XX_PCI_IRQ_COUNT);
 -
 -      apc->irq_base = ATH79_PCI_IRQ_BASE;
@@ -131,12 +130,14 @@ Signed-off-by: John Crispin <[email protected]>
 -              irq_set_chip_data(i, apc);
 -      }
 -
-+      apc->domain = irq_domain_add_linear(apc->np, AR71XX_PCI_IRQ_COUNT,
-+                                          &ar71xx_pci_domain_ops, apc);
-       irq_set_chained_handler_and_data(apc->irq, ar71xx_pci_irq_handler,
-                                        apc);
- }
-@@ -328,6 +339,11 @@ static void ar71xx_pci_reset(void)
+-      irq_set_chained_handler_and_data(apc->irq, ar71xx_pci_irq_handler,
+-                                       apc);
+-}
+-
+ static void ar71xx_pci_reset(void)
+ {
+       ath79_device_reset_set(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE);
+@@ -328,6 +242,11 @@ static void ar71xx_pci_reset(void)
        mdelay(100);
  }
  
@@ -148,7 +149,7 @@ Signed-off-by: John Crispin <[email protected]>
  static int ar71xx_pci_probe(struct platform_device *pdev)
  {
        struct ar71xx_pci_controller *apc;
-@@ -348,26 +364,6 @@ static int ar71xx_pci_probe(struct platf
+@@ -348,26 +267,6 @@ static int ar71xx_pci_probe(struct platf
        if (apc->irq < 0)
                return -EINVAL;
  
@@ -175,7 +176,7 @@ Signed-off-by: John Crispin <[email protected]>
        ar71xx_pci_reset();
  
        /* setup COMMAND register */
-@@ -378,11 +374,13 @@ static int ar71xx_pci_probe(struct platf
+@@ -378,11 +277,12 @@ static int ar71xx_pci_probe(struct platf
        /* clear bus errors */
        ar71xx_pci_check_error(apc, 1);
  
@@ -187,11 +188,10 @@ Signed-off-by: John Crispin <[email protected]>
        apc->pci_ctrl.io_resource = &apc->io_res;
 +      pci_load_of_ranges(&apc->pci_ctrl, pdev->dev.of_node);
 +
-+      ar71xx_pci_irq_init(apc);
  
        register_pci_controller(&apc->pci_ctrl);
  
-@@ -393,6 +391,7 @@ static struct platform_driver ar71xx_pci
+@@ -393,6 +293,7 @@ static struct platform_driver ar71xx_pci
        .probe = ar71xx_pci_probe,
        .driver = {
                .name = "ar71xx-pci",
diff --git a/target/linux/ath79/patches-4.14/0036-MIPS-ath79-add-pci-intc.patch 
b/target/linux/ath79/patches-4.14/0036-MIPS-ath79-add-pci-intc.patch
new file mode 100644
index 0000000..23d6a55
--- /dev/null
+++ b/target/linux/ath79/patches-4.14/0036-MIPS-ath79-add-pci-intc.patch
@@ -0,0 +1,205 @@
+Index: linux-4.14.65/drivers/irqchip/Makefile
+===================================================================
+--- linux-4.14.65.orig/drivers/irqchip/Makefile
++++ linux-4.14.65/drivers/irqchip/Makefile
+@@ -5,6 +5,7 @@ obj-$(CONFIG_ALPINE_MSI)               += irq-alpine-
+ obj-$(CONFIG_ATH79)                   += irq-ath79-cpu.o
+ obj-$(CONFIG_ATH79)                   += irq-ath79-intc.o
+ obj-$(CONFIG_ATH79)                   += irq-ath79-misc.o
++obj-$(CONFIG_ATH79)                     += irq-ath79-pci.o
+ obj-$(CONFIG_ARCH_BCM2835)            += irq-bcm2835.o
+ obj-$(CONFIG_ARCH_BCM2835)            += irq-bcm2836.o
+ obj-$(CONFIG_ARCH_EXYNOS)             += exynos-combiner.o
+Index: linux-4.14.65/drivers/irqchip/irq-ath79-pci.c
+===================================================================
+--- /dev/null
++++ linux-4.14.65/drivers/irqchip/irq-ath79-pci.c
+@@ -0,0 +1,188 @@
++/*
++ *  Atheros AR71xx PCI interrupt controller
++ *
++ *  Copyright (C) 2015 Alban Bedel <[email protected]>
++ *  Copyright (C) 2010-2011 Jaiganesh Narayanan <[email protected]>
++ *  Copyright (C) 2008-2011 Gabor Juhos <[email protected]>
++ *  Copyright (C) 2008 Imre Kaloz <[email protected]>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include <linux/irqchip.h>
++#include <linux/irqchip/chained_irq.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++
++#define AR71XX_RESET_REG_PCI_INT_STATUS       0
++#define AR71XX_RESET_REG_PCI_INT_ENABLE       4
++
++#define AR71XX_PCI_INT_CORE                   BIT(4)
++#define AR71XX_PCI_INT_DEV2                   BIT(2)
++#define AR71XX_PCI_INT_DEV1                   BIT(1)
++#define AR71XX_PCI_INT_DEV0                   BIT(0)
++
++#define ATH79_PCI_IRQ_COUNT                   5
++
++static void ath79_pci_irq_handler(struct irq_desc *desc)
++{
++      struct irq_domain *domain = irq_desc_get_handler_data(desc);
++      struct irq_chip *chip = irq_desc_get_chip(desc);
++      void __iomem *base = domain->host_data;
++      u32 pending;
++
++      chained_irq_enter(chip, desc);
++
++      pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) &
++                __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++
++      if (pending & AR71XX_PCI_INT_DEV0)
++              generic_handle_irq(irq_linear_revmap(domain, 1));
++
++      else if (pending & AR71XX_PCI_INT_DEV1)
++              generic_handle_irq(irq_linear_revmap(domain, 2));
++
++      else if (pending & AR71XX_PCI_INT_DEV2)
++              generic_handle_irq(irq_linear_revmap(domain, 3));
++
++      else if (pending & AR71XX_PCI_INT_CORE)
++              generic_handle_irq(irq_linear_revmap(domain, 4));
++
++      else
++              spurious_interrupt();
++
++      chained_irq_exit(chip, desc);
++}
++
++static void ar71xx_pci_irq_unmask(struct irq_data *d)
++{
++      void __iomem *base = irq_data_get_irq_chip_data(d);
++      u32 t;
++
++      t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++
++      switch (d->hwirq) {
++      case 1:
++              t |= AR71XX_PCI_INT_DEV0;
++              break;
++      case 2:
++              t |= AR71XX_PCI_INT_DEV1;
++              break;
++      case 3:
++              t |= AR71XX_PCI_INT_DEV2;
++              break;
++      case 4:
++              t |= AR71XX_PCI_INT_CORE;
++              break;
++      default:
++              WARN(1, "Incorrect IRQ used for PCI device.");
++              return;
++      }
++
++      __raw_writel(t, base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++
++      /* flush write */
++      __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++}
++
++static void ar71xx_pci_irq_mask(struct irq_data *d)
++{
++      void __iomem *base = irq_data_get_irq_chip_data(d);
++      u32 t;
++
++      t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++
++      switch (d->hwirq) {
++      case 1:
++              t &= (~AR71XX_PCI_INT_DEV0);
++              break;
++      case 2:
++              t &= (~AR71XX_PCI_INT_DEV1);
++              break;
++      case 3:
++              t &= (~AR71XX_PCI_INT_DEV2);
++              break;
++      case 4:
++              t &= (~AR71XX_PCI_INT_CORE);
++              break;
++      default:
++              WARN(1, "Incorrect IRQ used for PCI device.");
++              return;
++      }
++
++      __raw_writel(t, base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++
++      /* flush write */
++      __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++}
++
++static struct irq_chip ar71xx_pci_irq_chip = {
++      .name           = "AR71XX PCI",
++      .irq_unmask     = ar71xx_pci_irq_unmask,
++      .irq_mask       = ar71xx_pci_irq_mask,
++      .irq_mask_ack   = ar71xx_pci_irq_mask,
++};
++
++static int ar71xx_pci_irq_map(struct irq_domain *d, unsigned int irq, 
irq_hw_number_t hw)
++{
++      struct ar71xx_pci_controller *apc = d->host_data;
++
++      irq_set_chip_and_handler(irq, &ar71xx_pci_irq_chip, handle_level_irq);
++      irq_set_chip_data(irq, apc);
++
++      return 0;
++}
++
++static const struct irq_domain_ops pci_irq_domain_ops = {
++      .xlate = irq_domain_xlate_onecell,
++      .map = ar71xx_pci_irq_map,
++};
++
++static void __init ath79_pci_intc_domain_init(
++      struct irq_domain *domain, int irq)
++{
++      void __iomem *base = domain->host_data;
++
++      /* Disable and clear all interrupts */
++      __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE);
++      __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS);
++
++      irq_set_chained_handler_and_data(irq, ath79_pci_irq_handler, domain);
++}
++
++static int __init ar7100_pci_intc_of_init(
++      struct device_node *node, struct device_node *parent)
++{
++      struct irq_domain *domain;
++      void __iomem *base;
++      int irq;
++
++      irq = irq_of_parse_and_map(node, 0);
++      if (!irq) {
++              pr_err("Failed to get PCI IRQ\n");
++              return -EINVAL;
++      }
++
++      base = of_iomap(node, 0);
++      if (!base) {
++              pr_err("Failed to get PCI IRQ registers\n");
++              return -ENOMEM;
++      }
++
++      domain = irq_domain_add_linear(node, ATH79_PCI_IRQ_COUNT,
++                              &pci_irq_domain_ops, base);
++      if (!domain) {
++              pr_err("Failed to add PCI irqdomain\n");
++              return -EINVAL;
++      }
++
++      ath79_pci_intc_domain_init(domain, irq);
++      return 0;
++}
++
++IRQCHIP_DECLARE(ar7100_pci_intc, "qca,ar7100-pci-intc",
++              ar7100_pci_intc_of_init);
-- 
2.7.4


_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to