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

Dmitry Tunin hanipouspilot at gmail.com
Tue Aug 21 11:45:54 EDT 2018


Performance tests look good too.
вт, 21 авг. 2018 г. в 17:59, Dmitry Tunin <hanipouspilot at 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 at 18060018 {
> +                               compatible = "qca,ar7100-pci-intc";
> +                               reg = <0x18060018 0x4>;
> +                               interrupt-parent = <&cpuintc>;
> +                               interrupts = <2>;
> +                               interrupt-controller;
> +                               #interrupt-cells = <1>;
> +                       };
> +
> +
>                         pcie0: pcie-controller at 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 at 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 at 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 at 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 at 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 at 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 at 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 at free.fr>
> ++ *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan at atheros.com>
> ++ *  Copyright (C) 2008-2011 Gabor Juhos <juhosg at openwrt.org>
> ++ *  Copyright (C) 2008 Imre Kaloz <kaloz at 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
>

_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel


More information about the openwrt-devel mailing list