[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