diff mbox series

[OpenWrt-Devel] ath79: ar71xx create a separate driver for ar71xx pci interrupt controller.

Message ID 1534863555-26104-1-git-send-email-hanipouspilot@gmail.com
State Superseded
Delegated to: John Crispin
Headers show
Series [OpenWrt-Devel] ath79: ar71xx create a separate driver for ar71xx pci interrupt controller. | expand

Commit Message

Dmitry Tunin Aug. 21, 2018, 2:59 p.m. UTC
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

Comments

Dmitry Tunin Aug. 21, 2018, 3:45 p.m. UTC | #1
Performance tests look good too.
вт, 21 авг. 2018 г. в 17:59, Dmitry Tunin <hanipouspilot@gmail.com>:
>
> 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 <john@phrozen.org>
>   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 <john@phrozen.org>
>   };
>
>   /* 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 <john@phrozen.org>
>  -              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 <john@phrozen.org>
>   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 <john@phrozen.org>
>         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 <john@phrozen.org>
>         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 <albeu@free.fr>
> ++ *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
> ++ *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
> ++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
> ++ *
> ++ *  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
>
Chuanhong Guo Aug. 21, 2018, 4:03 p.m. UTC | #2
Hi!
Comments inline:
Dmitry Tunin <hanipouspilot@gmail.com> 于2018年8月21日周二 下午10:59写道:
>
> 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.
No it doesn't. Assigning it in dts doesn't mean that we "handled" it.
But I still like this patch because it's doing a cleanup of the messy code.
>
> I am not sure that this kind of cascading is good for performance, but this way we are more flexible when cofiguring IRQs.
It shouldn't affect performance because doing this separation doesn't
change the way it dispatches PCI IRQ.
>
> 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>;
> +                       };
> +
For other chips this node is a subnode of reset-controller. But in
this case here we can just put this above reset-controller@18060024.
Nodes in dts are supposed to be ordered by register address.
> +
>                         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>;
Do we really need this? We don't even have a handler that actually do
anything for it. I think the above two lines can simply be dropped.
>
> -                               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
It's not a good idea to mix the removal of IRQ part into this patch. I
suggest using a separated patch to do the removing.
> @@ -9,8 +9,10 @@ Signed-off-by: John Crispin <john@phrozen.org>
>   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 <john@phrozen.org>
>   };
>
>   /* 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 <john@phrozen.org>
>  -              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 <john@phrozen.org>
>   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 <john@phrozen.org>
>         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 <john@phrozen.org>
>         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
I haven't read the code thoroghly but it seemed that irq-ath79-misc
works in a similar way. Is it possible to use the misc intc driver for
PCI?
> +@@ -0,0 +1,188 @@
> ++/*
> ++ *  Atheros AR71xx PCI interrupt controller
> ++ *
> ++ *  Copyright (C) 2015 Alban Bedel <albeu@free.fr>
> ++ *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
> ++ *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
> ++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
> ++ *
> ++ *  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
>
Dmitry Tunin Aug. 21, 2018, 4:26 p.m. UTC | #3
> > This should fix a bug with one IRQ for all PCI devices and also handle the PCI_CORE interrupt.
> No it doesn't. Assigning it in dts doesn't mean that we "handled" it.
> But I still like this patch because it's doing a cleanup of the messy code.

I am still not very competent in the IRQ handling. I thought that if we set
interrupts = <4>; and the new partent, your "case 4:" may work.

> >
> > +                       pci_intc: interrupt-controller@18060018 {
> > +                               compatible = "qca,ar7100-pci-intc";
> > +                               reg = <0x18060018 0x4>;
> > +                               interrupt-parent = <&cpuintc>;
> > +                               interrupts = <2>;
> > +                               interrupt-controller;
> > +                               #interrupt-cells = <1>;
> > +                       };
> > +
> For other chips this node is a subnode of reset-controller. But in
> this case here we can just put this above reset-controller@18060024.
> Nodes in dts are supposed to be ordered by register address.

No problem with that, I thought about a child node. But it doesn't
make any difference IMHO.
> > +
> >                         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>;
> Do we really need this? We don't even have a handler that actually do
> anything for it. I think the above two lines can simply be dropped.

See above. I thought the existing handler could work. I must be wrong.

> > 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
> It's not a good idea to mix the removal of IRQ part into this patch. I
> suggest using a separated patch to do the removing.

It is a minor issue if everything else looks good. The idea was to
keep number of patches smaller.


> I haven't read the code thoroghly but it seemed that irq-ath79-misc
> works in a similar way. Is it possible to use the misc intc driver for
> PCI?

They are similar. I used that code as an example, but the
irq-ath79-pci has your mask/unmask for pci with reading the registers.
It is possible to make one driver for both, but is it really needed?
Chuanhong Guo Aug. 21, 2018, 5:18 p.m. UTC | #4
Dmitry Tunin <hanipouspilot@gmail.com> 于2018年8月22日周三 上午12:26写道:
> I am still not very competent in the IRQ handling. I thought that if we set
> interrupts = <4>; and the new partent, your "case 4:" may work.
We have it there because it appears in datasheet. But we don't need it
to work unless we know what it's used for.
>
> > >
> > > +                       pci_intc: interrupt-controller@18060018 {
> > > +                               compatible = "qca,ar7100-pci-intc";
> > > +                               reg = <0x18060018 0x4>;
> > > +                               interrupt-parent = <&cpuintc>;
> > > +                               interrupts = <2>;
> > > +                               interrupt-controller;
> > > +                               #interrupt-cells = <1>;
> > > +                       };
> > > +
> > For other chips this node is a subnode of reset-controller. But in
> > this case here we can just put this above reset-controller@18060024.
> > Nodes in dts are supposed to be ordered by register address.
>
> No problem with that, I thought about a child node. But it doesn't
> make any difference IMHO.
> > > +
> > >                         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>;
> > Do we really need this? We don't even have a handler that actually do
> > anything for it. I think the above two lines can simply be dropped.
>
> See above. I thought the existing handler could work. I must be wrong.
All the job of the existing handler is now done by the added cascade
driver. And you have removed the existing handler in driver :)
>
> > > 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
> > It's not a good idea to mix the removal of IRQ part into this patch. I
> > suggest using a separated patch to do the removing.
>
> It is a minor issue if everything else looks good. The idea was to
> keep number of patches smaller.
Keeping patches inside that directory less isn't useful at all.(If
it's useful why not squash all of them into one?)
Instead we need each patch did one job and that job is described in
file name/title in mbox header.
As @blogic put in the mbox header, this patch "turns the existing PCI
driver into a pure OF driver" but what you did is "Removing IRQ
dispatcher from PCI driver". Squashing them together only makes the
patch more confusing.
>
>
> > I haven't read the code thoroghly but it seemed that irq-ath79-misc
> > works in a similar way. Is it possible to use the misc intc driver for
> > PCI?
>
> They are similar. I used that code as an example, but the
> irq-ath79-pci has your mask/unmask for pci with reading the registers.
> It is possible to make one driver for both, but is it really needed?
It helps reducing code duplication.
Dmitry Tunin Aug. 22, 2018, 5:08 a.m. UTC | #5
> > They are similar. I used that code as an example, but the
> > irq-ath79-pci has your mask/unmask for pci with reading the registers.
> > It is possible to make one driver for both, but is it really needed?
> It helps reducing code duplication.

If we completely drop that PCI_CORE IRQ that we are not using anyway,
I see no reason why we can't
define 2 subnodes or the reset controller with the same irq-ath79-misc driver.
We'll need only to set PCI IRQs to 0-2 instead of 1-3. That's all.

After some other feedback is received, I can do the change.
Chuanhong Guo Aug. 22, 2018, 7:10 a.m. UTC | #6
Dmitry Tunin <hanipouspilot@gmail.com> 于2018年8月22日周三 下午1:08写道:
>
> > > They are similar. I used that code as an example, but the
> > > irq-ath79-pci has your mask/unmask for pci with reading the registers.
> > > It is possible to make one driver for both, but is it really needed?
> > It helps reducing code duplication.
>
> If we completely drop that PCI_CORE IRQ that we are not using anyway,
> I see no reason why we can't
> define 2 subnodes or the reset controller with the same irq-ath79-misc driver.
I'm actually saying about directly using irq-ath79-misc for PCI
interrupt, and this means define two nodes using different reg but
make the compatible string the same(qca,ar7100-misc) :)
And this doesn't mean that we can't use PCI_CORE IRQ if we need it.
Simply use hwirq 0-2 for devices and hwirq 4 for PCI_CORE.
> We'll need only to set PCI IRQs to 0-2 instead of 1-3. That's all.
>
> After some other feedback is received, I can do the change.
Dmitry Tunin Aug. 22, 2018, 7:20 a.m. UTC | #7
Yes, the IRQ 4 will go to bit 4. But anyway the IRQ4 is never
triggered, but we can leave it just in case someone needs it for
something ;-)
Now we can't "use hwirq 4" unless there is a handler in PCI driver.

I looked into the irq-ath79-misc.c and I think we need to change
ATH79_MISC_IRQ_COUNT.
We don't need that huge domain. According to spec the misc controller
has 8 IRQs and the PCI has actually 4, but we need 5 to be linear.
So 8 will be enough for both. But it must be another patch.
ср, 22 авг. 2018 г. в 10:11, Chuanhong Guo <gch981213@gmail.com>:
>
> Dmitry Tunin <hanipouspilot@gmail.com> 于2018年8月22日周三 下午1:08写道:
> >
> > > > They are similar. I used that code as an example, but the
> > > > irq-ath79-pci has your mask/unmask for pci with reading the registers.
> > > > It is possible to make one driver for both, but is it really needed?
> > > It helps reducing code duplication.
> >
> > If we completely drop that PCI_CORE IRQ that we are not using anyway,
> > I see no reason why we can't
> > define 2 subnodes or the reset controller with the same irq-ath79-misc driver.
> I'm actually saying about directly using irq-ath79-misc for PCI
> interrupt, and this means define two nodes using different reg but
> make the compatible string the same(qca,ar7100-misc) :)
> And this doesn't mean that we can't use PCI_CORE IRQ if we need it.
> Simply use hwirq 0-2 for devices and hwirq 4 for PCI_CORE.
> > We'll need only to set PCI IRQs to 0-2 instead of 1-3. That's all.
> >
> > After some other feedback is received, I can do the change.
>
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel@lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
diff mbox series

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 <john@phrozen.org>
  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 <john@phrozen.org>
  };
  
  /* 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 <john@phrozen.org>
 -		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 <john@phrozen.org>
  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 <john@phrozen.org>
  	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 <john@phrozen.org>
  	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 <albeu@free.fr>
++ *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
++ *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  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);