[OpenWrt-Devel] [PATCH] ath79: ar71xx create a separate driver for ar71xx pci interrupt controller.
Dmitry Tunin
hanipouspilot at gmail.com
Tue Aug 21 10:59:15 EDT 2018
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