From: <Steen.Hegelund@microchip.com>
To: <herve.codina@bootlin.com>, <tglx@linutronix.de>,
<robh@kernel.org>, <krzk+dt@kernel.org>, <conor+dt@kernel.org>,
<davem@davemloft.net>, <edumazet@google.com>, <kuba@kernel.org>,
<pabeni@redhat.com>, <lee@kernel.org>, <arnd@arndb.de>,
<Horatiu.Vultur@microchip.com>, <UNGLinuxDriver@microchip.com>,
<andrew@lunn.ch>, <hkallweit1@gmail.com>, <linux@armlinux.org.uk>,
<saravanak@google.com>, <bhelgaas@google.com>,
<p.zabel@pengutronix.de>, <Lars.Povlsen@microchip.com>,
<Steen.Hegelund@microchip.com>, <Daniel.Machon@microchip.com>,
<alexandre.belloni@bootlin.com>
Cc: <linux-kernel@vger.kernel.org>, <devicetree@vger.kernel.org>,
<netdev@vger.kernel.org>, <linux-pci@vger.kernel.org>,
<linux-arm-kernel@lists.infradead.org>,
<Allan.Nielsen@microchip.com>, <luca.ceresoli@bootlin.com>,
<thomas.petazzoni@bootlin.com>
Subject: Re: [PATCH 12/17] irqchip: Add support for LAN966x OIC
Date: Wed, 8 May 2024 08:08:30 +0000 [thread overview]
Message-ID: <D143YFK7334S.3MM7YORC0H24X@microchip.com> (raw)
In-Reply-To: <20240430083730.134918-13-herve.codina@bootlin.com>
Hi Herve,
On Tue Apr 30, 2024 at 10:37 AM CEST, Herve Codina wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
> The Microchip LAN966x outband interrupt controller (OIC) maps the
> internal interrupt sources of the LAN966x device to an external
> interrupt.
> When the LAN966x device is used as a PCI device, the external interrupt
> is routed to the PCI interrupt.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> drivers/irqchip/Kconfig | 12 ++
> drivers/irqchip/Makefile | 1 +
> drivers/irqchip/irq-lan966x-oic.c | 301 ++++++++++++++++++++++++++++++
> 3 files changed, 314 insertions(+)
> create mode 100644 drivers/irqchip/irq-lan966x-oic.c
>
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 72c07a12f5e1..973eebc8d1d1 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -169,6 +169,18 @@ config IXP4XX_IRQ
> select IRQ_DOMAIN
> select SPARSE_IRQ
>
> +config LAN966X_OIC
> + tristate "Microchip LAN966x OIC Support"
> + select GENERIC_IRQ_CHIP
> + select IRQ_DOMAIN
> + help
> + Enable support for the LAN966x Outbound Interrupt Controller.
> + This controller is present on the Microchip LAN966x PCI device and
> + maps the internal interrupts sources to PCIe interrupt.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called irq-lan966x-oic.
> +
> config MADERA_IRQ
> tristate
>
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index ec4a18380998..762d3078aa3b 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -101,6 +101,7 @@ obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
> obj-$(CONFIG_IMX_INTMUX) += irq-imx-intmux.o
> obj-$(CONFIG_IMX_MU_MSI) += irq-imx-mu-msi.o
> obj-$(CONFIG_MADERA_IRQ) += irq-madera.o
> +obj-$(CONFIG_LAN966X_OIC) += irq-lan966x-oic.o
> obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
> obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
> obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
> diff --git a/drivers/irqchip/irq-lan966x-oic.c b/drivers/irqchip/irq-lan966x-oic.c
> new file mode 100644
> index 000000000000..342f0dbf16e3
> --- /dev/null
> +++ b/drivers/irqchip/irq-lan966x-oic.c
> @@ -0,0 +1,301 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Driver for the Microchip LAN966x outbound interrupt controller
> + *
> + * Copyright (c) 2024 Technology Inc. and its subsidiaries.
> + *
> + * Authors:
> + * Horatiu Vultur <horatiu.vultur@microchip.com>
> + * Clément Léger <clement.leger@bootlin.com>
> + * Herve Codina <herve.codina@bootlin.com>
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/build_bug.h>
> +#include <linux/interrupt.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/irq.h>
> +#include <linux/iopoll.h>
> +#include <linux/mfd/core.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/delay.h>
> +
> +struct lan966x_oic_chip_regs {
> + int reg_off_ena_set;
> + int reg_off_ena_clr;
> + int reg_off_sticky;
> + int reg_off_ident;
> + int reg_off_map;
> +};
> +
> +struct lan966x_oic_data {
> + struct irq_domain *domain;
> + void __iomem *regs;
> + int irq;
> +};
> +
> +#define LAN966X_OIC_NR_IRQ 86
> +
> +/* Interrupt sticky status */
> +#define LAN966X_OIC_INTR_STICKY 0x30
> +#define LAN966X_OIC_INTR_STICKY1 0x34
> +#define LAN966X_OIC_INTR_STICKY2 0x38
> +
> +/* Interrupt enable */
> +#define LAN966X_OIC_INTR_ENA 0x48
> +#define LAN966X_OIC_INTR_ENA1 0x4c
> +#define LAN966X_OIC_INTR_ENA2 0x50
> +
> +/* Atomic clear of interrupt enable */
> +#define LAN966X_OIC_INTR_ENA_CLR 0x54
> +#define LAN966X_OIC_INTR_ENA_CLR1 0x58
> +#define LAN966X_OIC_INTR_ENA_CLR2 0x5c
> +
> +/* Atomic set of interrupt */
> +#define LAN966X_OIC_INTR_ENA_SET 0x60
> +#define LAN966X_OIC_INTR_ENA_SET1 0x64
> +#define LAN966X_OIC_INTR_ENA_SET2 0x68
> +
> +/* Mapping of source to destination interrupts (_n = 0..8) */
Are the indices really needed on LAN966X_OIC_DST_INTR_MAP* and _IDENT*
You do not appear to be using them?
> +#define LAN966X_OIC_DST_INTR_MAP(_n) 0x78
> +#define LAN966X_OIC_DST_INTR_MAP1(_n) 0x9c
> +#define LAN966X_OIC_DST_INTR_MAP2(_n) 0xc0
> +
> +/* Currently active interrupt sources per destination (_n = 0..8) */
> +#define LAN966X_OIC_DST_INTR_IDENT(_n) 0xe4
> +#define LAN966X_OIC_DST_INTR_IDENT1(_n) 0x108
> +#define LAN966X_OIC_DST_INTR_IDENT2(_n) 0x12c
> +
> +static unsigned int lan966x_oic_irq_startup(struct irq_data *data)
> +{
> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
> + struct irq_chip_type *ct = irq_data_get_chip_type(data);
> + struct lan966x_oic_chip_regs *chip_regs = gc->private;
> + u32 map;
> +
> + irq_gc_lock(gc);
> +
> + /* Map the source interrupt to the destination */
> + map = irq_reg_readl(gc, chip_regs->reg_off_map);
> + map |= data->mask;
> + irq_reg_writel(gc, map, chip_regs->reg_off_map);
> +
> + irq_gc_unlock(gc);
> +
> + ct->chip.irq_ack(data);
> + ct->chip.irq_unmask(data);
> +
> + return 0;
> +}
> +
> +static void lan966x_oic_irq_shutdown(struct irq_data *data)
> +{
> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
> + struct irq_chip_type *ct = irq_data_get_chip_type(data);
> + struct lan966x_oic_chip_regs *chip_regs = gc->private;
> + u32 map;
> +
> + ct->chip.irq_mask(data);
> +
> + irq_gc_lock(gc);
> +
> + /* Unmap the interrupt */
> + map = irq_reg_readl(gc, chip_regs->reg_off_map);
> + map &= ~data->mask;
> + irq_reg_writel(gc, map, chip_regs->reg_off_map);
> +
> + irq_gc_unlock(gc);
> +}
> +
> +static int lan966x_oic_irq_set_type(struct irq_data *data, unsigned int flow_type)
> +{
> + if (flow_type != IRQ_TYPE_LEVEL_HIGH) {
> + pr_err("lan966x oic doesn't support flow type %d\n", flow_type);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static void lan966x_oic_irq_handler_domain(struct irq_domain *d, u32 first_irq)
> +{
> + struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, first_irq);
> + struct lan966x_oic_chip_regs *chip_regs = gc->private;
> + unsigned long ident;
> + unsigned int hwirq;
> +
> + ident = irq_reg_readl(gc, chip_regs->reg_off_ident);
> + if (!ident)
> + return;
> +
> + for_each_set_bit(hwirq, &ident, 32)
> + generic_handle_domain_irq(d, hwirq + first_irq);
> +}
> +
> +static void lan966x_oic_irq_handler(struct irq_desc *desc)
> +{
> + struct irq_domain *d = irq_desc_get_handler_data(desc);
> + struct irq_chip *chip = irq_desc_get_chip(desc);
> +
> + chained_irq_enter(chip, desc);
> + lan966x_oic_irq_handler_domain(d, 0);
> + lan966x_oic_irq_handler_domain(d, 32);
> + lan966x_oic_irq_handler_domain(d, 64);
> + chained_irq_exit(chip, desc);
> +}
> +
> +static struct lan966x_oic_chip_regs lan966x_oic_chip_regs[3] = {
> + {
> + .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET,
> + .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR,
> + .reg_off_sticky = LAN966X_OIC_INTR_STICKY,
> + .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT(0),
> + .reg_off_map = LAN966X_OIC_DST_INTR_MAP(0),
> + }, {
> + .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET1,
> + .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR1,
> + .reg_off_sticky = LAN966X_OIC_INTR_STICKY1,
> + .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT1(0),
> + .reg_off_map = LAN966X_OIC_DST_INTR_MAP1(0),
> + }, {
> + .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET2,
> + .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR2,
> + .reg_off_sticky = LAN966X_OIC_INTR_STICKY2,
> + .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT2(0),
> + .reg_off_map = LAN966X_OIC_DST_INTR_MAP2(0),
> + }
> +};
> +
> +static void lan966x_oic_chip_init(struct lan966x_oic_data *lan966x_oic,
> + struct irq_chip_generic *gc,
> + struct lan966x_oic_chip_regs *chip_regs)
> +{
> + gc->reg_base = lan966x_oic->regs;
> + gc->chip_types[0].regs.enable = chip_regs->reg_off_ena_set;
> + gc->chip_types[0].regs.disable = chip_regs->reg_off_ena_clr;
> + gc->chip_types[0].regs.ack = chip_regs->reg_off_sticky;
> + gc->chip_types[0].chip.irq_startup = lan966x_oic_irq_startup;
> + gc->chip_types[0].chip.irq_shutdown = lan966x_oic_irq_shutdown;
> + gc->chip_types[0].chip.irq_set_type = lan966x_oic_irq_set_type;
> + gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;
> + gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg;
> + gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
> + gc->private = chip_regs;
> +
> + /* Disable all interrupts handled by this chip */
> + irq_reg_writel(gc, ~0, chip_regs->reg_off_ena_clr);
> +}
> +
> +static void lan966x_oic_chip_exit(struct irq_chip_generic *gc)
> +{
> + /* Disable and ack all interrupts handled by this chip */
> + irq_reg_writel(gc, ~0, gc->chip_types[0].regs.disable);
> + irq_reg_writel(gc, ~0, gc->chip_types[0].regs.ack);
> +}
> +
> +static int lan966x_oic_probe(struct platform_device *pdev)
> +{
> + struct device_node *node = pdev->dev.of_node;
> + struct lan966x_oic_data *lan966x_oic;
> + struct device *dev = &pdev->dev;
> + struct irq_chip_generic *gc;
> + int ret;
> + int i;
> +
> + lan966x_oic = devm_kmalloc(dev, sizeof(*lan966x_oic), GFP_KERNEL);
> + if (!lan966x_oic)
> + return -ENOMEM;
> +
> + lan966x_oic->regs = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(lan966x_oic->regs))
> + return dev_err_probe(dev, PTR_ERR(lan966x_oic->regs),
> + "failed to map resource\n");
> +
> + lan966x_oic->domain = irq_domain_alloc_linear(of_node_to_fwnode(node),
> + LAN966X_OIC_NR_IRQ,
> + &irq_generic_chip_ops, NULL);
> + if (!lan966x_oic->domain) {
> + dev_err(dev, "failed to create an IRQ domain\n");
> + return -EINVAL;
> + }
> +
> + lan966x_oic->irq = platform_get_irq(pdev, 0);
> + if (lan966x_oic->irq < 0) {
> + dev_err_probe(dev, lan966x_oic->irq, "failed to get the IRQ\n");
> + goto err_domain_free;
> + }
> +
> + ret = irq_alloc_domain_generic_chips(lan966x_oic->domain, 32, 1, "lan966x-oic",
> + handle_level_irq, 0, 0, 0);
> + if (ret) {
> + dev_err_probe(dev, ret, "failed to alloc irq domain gc\n");
> + goto err_domain_free;
> + }
> +
> + /* Init chips */
> + BUILD_BUG_ON(DIV_ROUND_UP(LAN966X_OIC_NR_IRQ, 32) != ARRAY_SIZE(lan966x_oic_chip_regs));
> + for (i = 0; i < ARRAY_SIZE(lan966x_oic_chip_regs); i++) {
> + gc = irq_get_domain_generic_chip(lan966x_oic->domain, i * 32);
> + lan966x_oic_chip_init(lan966x_oic, gc, &lan966x_oic_chip_regs[i]);
> + }
> +
> + irq_set_chained_handler_and_data(lan966x_oic->irq, lan966x_oic_irq_handler,
> + lan966x_oic->domain);
> +
> + irq_domain_publish(lan966x_oic->domain);
> + platform_set_drvdata(pdev, lan966x_oic);
> + return 0;
> +
> +err_domain_free:
> + irq_domain_free(lan966x_oic->domain);
> + return ret;
> +}
> +
> +static void lan966x_oic_remove(struct platform_device *pdev)
> +{
> + struct lan966x_oic_data *lan966x_oic = platform_get_drvdata(pdev);
> + struct irq_chip_generic *gc;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(lan966x_oic_chip_regs); i++) {
> + gc = irq_get_domain_generic_chip(lan966x_oic->domain, i * 32);
> + lan966x_oic_chip_exit(gc);
> + }
> +
> + irq_set_chained_handler_and_data(lan966x_oic->irq, NULL, NULL);
> +
> + for (i = 0; i < LAN966X_OIC_NR_IRQ; i++)
> + irq_dispose_mapping(irq_find_mapping(lan966x_oic->domain, i));
> +
> + irq_domain_unpublish(lan966x_oic->domain);
> +
> + for (i = 0; i < ARRAY_SIZE(lan966x_oic_chip_regs); i++) {
> + gc = irq_get_domain_generic_chip(lan966x_oic->domain, i * 32);
> + irq_remove_generic_chip(gc, ~0, 0, 0);
> + }
> +
> + kfree(lan966x_oic->domain->gc);
> + irq_domain_free(lan966x_oic->domain);
> +}
> +
> +static const struct of_device_id lan966x_oic_of_match[] = {
> + { .compatible = "microchip,lan966x-oic" },
> + {} /* sentinel */
> +};
> +MODULE_DEVICE_TABLE(of, lan966x_oic_of_match);
> +
> +static struct platform_driver lan966x_oic_driver = {
> + .probe = lan966x_oic_probe,
> + .remove_new = lan966x_oic_remove,
> + .driver = {
> + .name = "lan966x-oic",
> + .of_match_table = lan966x_oic_of_match,
> + },
> +};
> +module_platform_driver(lan966x_oic_driver);
> +
> +MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
> +MODULE_DESCRIPTION("Microchip LAN966x OIC driver");
> +MODULE_LICENSE("GPL");
> --
> 2.44.0
Best regards
Steen
WARNING: multiple messages have this Message-ID (diff)
From: <Steen.Hegelund@microchip.com>
To: <herve.codina@bootlin.com>, <tglx@linutronix.de>,
<robh@kernel.org>, <krzk+dt@kernel.org>, <conor+dt@kernel.org>,
<davem@davemloft.net>, <edumazet@google.com>, <kuba@kernel.org>,
<pabeni@redhat.com>, <lee@kernel.org>, <arnd@arndb.de>,
<Horatiu.Vultur@microchip.com>, <UNGLinuxDriver@microchip.com>,
<andrew@lunn.ch>, <hkallweit1@gmail.com>, <linux@armlinux.org.uk>,
<saravanak@google.com>, <bhelgaas@google.com>,
<p.zabel@pengutronix.de>, <Lars.Povlsen@microchip.com>,
<Steen.Hegelund@microchip.com>, <Daniel.Machon@microchip.com>,
<alexandre.belloni@bootlin.com>
Cc: <linux-kernel@vger.kernel.org>, <devicetree@vger.kernel.org>,
<netdev@vger.kernel.org>, <linux-pci@vger.kernel.org>,
<linux-arm-kernel@lists.infradead.org>,
<Allan.Nielsen@microchip.com>, <luca.ceresoli@bootlin.com>,
<thomas.petazzoni@bootlin.com>
Subject: Re: [PATCH 12/17] irqchip: Add support for LAN966x OIC
Date: Wed, 8 May 2024 08:08:30 +0000 [thread overview]
Message-ID: <D143YFK7334S.3MM7YORC0H24X@microchip.com> (raw)
In-Reply-To: <20240430083730.134918-13-herve.codina@bootlin.com>
Hi Herve,
On Tue Apr 30, 2024 at 10:37 AM CEST, Herve Codina wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
> The Microchip LAN966x outband interrupt controller (OIC) maps the
> internal interrupt sources of the LAN966x device to an external
> interrupt.
> When the LAN966x device is used as a PCI device, the external interrupt
> is routed to the PCI interrupt.
>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
> drivers/irqchip/Kconfig | 12 ++
> drivers/irqchip/Makefile | 1 +
> drivers/irqchip/irq-lan966x-oic.c | 301 ++++++++++++++++++++++++++++++
> 3 files changed, 314 insertions(+)
> create mode 100644 drivers/irqchip/irq-lan966x-oic.c
>
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 72c07a12f5e1..973eebc8d1d1 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -169,6 +169,18 @@ config IXP4XX_IRQ
> select IRQ_DOMAIN
> select SPARSE_IRQ
>
> +config LAN966X_OIC
> + tristate "Microchip LAN966x OIC Support"
> + select GENERIC_IRQ_CHIP
> + select IRQ_DOMAIN
> + help
> + Enable support for the LAN966x Outbound Interrupt Controller.
> + This controller is present on the Microchip LAN966x PCI device and
> + maps the internal interrupts sources to PCIe interrupt.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called irq-lan966x-oic.
> +
> config MADERA_IRQ
> tristate
>
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index ec4a18380998..762d3078aa3b 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -101,6 +101,7 @@ obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
> obj-$(CONFIG_IMX_INTMUX) += irq-imx-intmux.o
> obj-$(CONFIG_IMX_MU_MSI) += irq-imx-mu-msi.o
> obj-$(CONFIG_MADERA_IRQ) += irq-madera.o
> +obj-$(CONFIG_LAN966X_OIC) += irq-lan966x-oic.o
> obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
> obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
> obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
> diff --git a/drivers/irqchip/irq-lan966x-oic.c b/drivers/irqchip/irq-lan966x-oic.c
> new file mode 100644
> index 000000000000..342f0dbf16e3
> --- /dev/null
> +++ b/drivers/irqchip/irq-lan966x-oic.c
> @@ -0,0 +1,301 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Driver for the Microchip LAN966x outbound interrupt controller
> + *
> + * Copyright (c) 2024 Technology Inc. and its subsidiaries.
> + *
> + * Authors:
> + * Horatiu Vultur <horatiu.vultur@microchip.com>
> + * Clément Léger <clement.leger@bootlin.com>
> + * Herve Codina <herve.codina@bootlin.com>
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/build_bug.h>
> +#include <linux/interrupt.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/irq.h>
> +#include <linux/iopoll.h>
> +#include <linux/mfd/core.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/delay.h>
> +
> +struct lan966x_oic_chip_regs {
> + int reg_off_ena_set;
> + int reg_off_ena_clr;
> + int reg_off_sticky;
> + int reg_off_ident;
> + int reg_off_map;
> +};
> +
> +struct lan966x_oic_data {
> + struct irq_domain *domain;
> + void __iomem *regs;
> + int irq;
> +};
> +
> +#define LAN966X_OIC_NR_IRQ 86
> +
> +/* Interrupt sticky status */
> +#define LAN966X_OIC_INTR_STICKY 0x30
> +#define LAN966X_OIC_INTR_STICKY1 0x34
> +#define LAN966X_OIC_INTR_STICKY2 0x38
> +
> +/* Interrupt enable */
> +#define LAN966X_OIC_INTR_ENA 0x48
> +#define LAN966X_OIC_INTR_ENA1 0x4c
> +#define LAN966X_OIC_INTR_ENA2 0x50
> +
> +/* Atomic clear of interrupt enable */
> +#define LAN966X_OIC_INTR_ENA_CLR 0x54
> +#define LAN966X_OIC_INTR_ENA_CLR1 0x58
> +#define LAN966X_OIC_INTR_ENA_CLR2 0x5c
> +
> +/* Atomic set of interrupt */
> +#define LAN966X_OIC_INTR_ENA_SET 0x60
> +#define LAN966X_OIC_INTR_ENA_SET1 0x64
> +#define LAN966X_OIC_INTR_ENA_SET2 0x68
> +
> +/* Mapping of source to destination interrupts (_n = 0..8) */
Are the indices really needed on LAN966X_OIC_DST_INTR_MAP* and _IDENT*
You do not appear to be using them?
> +#define LAN966X_OIC_DST_INTR_MAP(_n) 0x78
> +#define LAN966X_OIC_DST_INTR_MAP1(_n) 0x9c
> +#define LAN966X_OIC_DST_INTR_MAP2(_n) 0xc0
> +
> +/* Currently active interrupt sources per destination (_n = 0..8) */
> +#define LAN966X_OIC_DST_INTR_IDENT(_n) 0xe4
> +#define LAN966X_OIC_DST_INTR_IDENT1(_n) 0x108
> +#define LAN966X_OIC_DST_INTR_IDENT2(_n) 0x12c
> +
> +static unsigned int lan966x_oic_irq_startup(struct irq_data *data)
> +{
> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
> + struct irq_chip_type *ct = irq_data_get_chip_type(data);
> + struct lan966x_oic_chip_regs *chip_regs = gc->private;
> + u32 map;
> +
> + irq_gc_lock(gc);
> +
> + /* Map the source interrupt to the destination */
> + map = irq_reg_readl(gc, chip_regs->reg_off_map);
> + map |= data->mask;
> + irq_reg_writel(gc, map, chip_regs->reg_off_map);
> +
> + irq_gc_unlock(gc);
> +
> + ct->chip.irq_ack(data);
> + ct->chip.irq_unmask(data);
> +
> + return 0;
> +}
> +
> +static void lan966x_oic_irq_shutdown(struct irq_data *data)
> +{
> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
> + struct irq_chip_type *ct = irq_data_get_chip_type(data);
> + struct lan966x_oic_chip_regs *chip_regs = gc->private;
> + u32 map;
> +
> + ct->chip.irq_mask(data);
> +
> + irq_gc_lock(gc);
> +
> + /* Unmap the interrupt */
> + map = irq_reg_readl(gc, chip_regs->reg_off_map);
> + map &= ~data->mask;
> + irq_reg_writel(gc, map, chip_regs->reg_off_map);
> +
> + irq_gc_unlock(gc);
> +}
> +
> +static int lan966x_oic_irq_set_type(struct irq_data *data, unsigned int flow_type)
> +{
> + if (flow_type != IRQ_TYPE_LEVEL_HIGH) {
> + pr_err("lan966x oic doesn't support flow type %d\n", flow_type);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static void lan966x_oic_irq_handler_domain(struct irq_domain *d, u32 first_irq)
> +{
> + struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, first_irq);
> + struct lan966x_oic_chip_regs *chip_regs = gc->private;
> + unsigned long ident;
> + unsigned int hwirq;
> +
> + ident = irq_reg_readl(gc, chip_regs->reg_off_ident);
> + if (!ident)
> + return;
> +
> + for_each_set_bit(hwirq, &ident, 32)
> + generic_handle_domain_irq(d, hwirq + first_irq);
> +}
> +
> +static void lan966x_oic_irq_handler(struct irq_desc *desc)
> +{
> + struct irq_domain *d = irq_desc_get_handler_data(desc);
> + struct irq_chip *chip = irq_desc_get_chip(desc);
> +
> + chained_irq_enter(chip, desc);
> + lan966x_oic_irq_handler_domain(d, 0);
> + lan966x_oic_irq_handler_domain(d, 32);
> + lan966x_oic_irq_handler_domain(d, 64);
> + chained_irq_exit(chip, desc);
> +}
> +
> +static struct lan966x_oic_chip_regs lan966x_oic_chip_regs[3] = {
> + {
> + .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET,
> + .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR,
> + .reg_off_sticky = LAN966X_OIC_INTR_STICKY,
> + .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT(0),
> + .reg_off_map = LAN966X_OIC_DST_INTR_MAP(0),
> + }, {
> + .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET1,
> + .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR1,
> + .reg_off_sticky = LAN966X_OIC_INTR_STICKY1,
> + .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT1(0),
> + .reg_off_map = LAN966X_OIC_DST_INTR_MAP1(0),
> + }, {
> + .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET2,
> + .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR2,
> + .reg_off_sticky = LAN966X_OIC_INTR_STICKY2,
> + .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT2(0),
> + .reg_off_map = LAN966X_OIC_DST_INTR_MAP2(0),
> + }
> +};
> +
> +static void lan966x_oic_chip_init(struct lan966x_oic_data *lan966x_oic,
> + struct irq_chip_generic *gc,
> + struct lan966x_oic_chip_regs *chip_regs)
> +{
> + gc->reg_base = lan966x_oic->regs;
> + gc->chip_types[0].regs.enable = chip_regs->reg_off_ena_set;
> + gc->chip_types[0].regs.disable = chip_regs->reg_off_ena_clr;
> + gc->chip_types[0].regs.ack = chip_regs->reg_off_sticky;
> + gc->chip_types[0].chip.irq_startup = lan966x_oic_irq_startup;
> + gc->chip_types[0].chip.irq_shutdown = lan966x_oic_irq_shutdown;
> + gc->chip_types[0].chip.irq_set_type = lan966x_oic_irq_set_type;
> + gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;
> + gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg;
> + gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
> + gc->private = chip_regs;
> +
> + /* Disable all interrupts handled by this chip */
> + irq_reg_writel(gc, ~0, chip_regs->reg_off_ena_clr);
> +}
> +
> +static void lan966x_oic_chip_exit(struct irq_chip_generic *gc)
> +{
> + /* Disable and ack all interrupts handled by this chip */
> + irq_reg_writel(gc, ~0, gc->chip_types[0].regs.disable);
> + irq_reg_writel(gc, ~0, gc->chip_types[0].regs.ack);
> +}
> +
> +static int lan966x_oic_probe(struct platform_device *pdev)
> +{
> + struct device_node *node = pdev->dev.of_node;
> + struct lan966x_oic_data *lan966x_oic;
> + struct device *dev = &pdev->dev;
> + struct irq_chip_generic *gc;
> + int ret;
> + int i;
> +
> + lan966x_oic = devm_kmalloc(dev, sizeof(*lan966x_oic), GFP_KERNEL);
> + if (!lan966x_oic)
> + return -ENOMEM;
> +
> + lan966x_oic->regs = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(lan966x_oic->regs))
> + return dev_err_probe(dev, PTR_ERR(lan966x_oic->regs),
> + "failed to map resource\n");
> +
> + lan966x_oic->domain = irq_domain_alloc_linear(of_node_to_fwnode(node),
> + LAN966X_OIC_NR_IRQ,
> + &irq_generic_chip_ops, NULL);
> + if (!lan966x_oic->domain) {
> + dev_err(dev, "failed to create an IRQ domain\n");
> + return -EINVAL;
> + }
> +
> + lan966x_oic->irq = platform_get_irq(pdev, 0);
> + if (lan966x_oic->irq < 0) {
> + dev_err_probe(dev, lan966x_oic->irq, "failed to get the IRQ\n");
> + goto err_domain_free;
> + }
> +
> + ret = irq_alloc_domain_generic_chips(lan966x_oic->domain, 32, 1, "lan966x-oic",
> + handle_level_irq, 0, 0, 0);
> + if (ret) {
> + dev_err_probe(dev, ret, "failed to alloc irq domain gc\n");
> + goto err_domain_free;
> + }
> +
> + /* Init chips */
> + BUILD_BUG_ON(DIV_ROUND_UP(LAN966X_OIC_NR_IRQ, 32) != ARRAY_SIZE(lan966x_oic_chip_regs));
> + for (i = 0; i < ARRAY_SIZE(lan966x_oic_chip_regs); i++) {
> + gc = irq_get_domain_generic_chip(lan966x_oic->domain, i * 32);
> + lan966x_oic_chip_init(lan966x_oic, gc, &lan966x_oic_chip_regs[i]);
> + }
> +
> + irq_set_chained_handler_and_data(lan966x_oic->irq, lan966x_oic_irq_handler,
> + lan966x_oic->domain);
> +
> + irq_domain_publish(lan966x_oic->domain);
> + platform_set_drvdata(pdev, lan966x_oic);
> + return 0;
> +
> +err_domain_free:
> + irq_domain_free(lan966x_oic->domain);
> + return ret;
> +}
> +
> +static void lan966x_oic_remove(struct platform_device *pdev)
> +{
> + struct lan966x_oic_data *lan966x_oic = platform_get_drvdata(pdev);
> + struct irq_chip_generic *gc;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(lan966x_oic_chip_regs); i++) {
> + gc = irq_get_domain_generic_chip(lan966x_oic->domain, i * 32);
> + lan966x_oic_chip_exit(gc);
> + }
> +
> + irq_set_chained_handler_and_data(lan966x_oic->irq, NULL, NULL);
> +
> + for (i = 0; i < LAN966X_OIC_NR_IRQ; i++)
> + irq_dispose_mapping(irq_find_mapping(lan966x_oic->domain, i));
> +
> + irq_domain_unpublish(lan966x_oic->domain);
> +
> + for (i = 0; i < ARRAY_SIZE(lan966x_oic_chip_regs); i++) {
> + gc = irq_get_domain_generic_chip(lan966x_oic->domain, i * 32);
> + irq_remove_generic_chip(gc, ~0, 0, 0);
> + }
> +
> + kfree(lan966x_oic->domain->gc);
> + irq_domain_free(lan966x_oic->domain);
> +}
> +
> +static const struct of_device_id lan966x_oic_of_match[] = {
> + { .compatible = "microchip,lan966x-oic" },
> + {} /* sentinel */
> +};
> +MODULE_DEVICE_TABLE(of, lan966x_oic_of_match);
> +
> +static struct platform_driver lan966x_oic_driver = {
> + .probe = lan966x_oic_probe,
> + .remove_new = lan966x_oic_remove,
> + .driver = {
> + .name = "lan966x-oic",
> + .of_match_table = lan966x_oic_of_match,
> + },
> +};
> +module_platform_driver(lan966x_oic_driver);
> +
> +MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
> +MODULE_DESCRIPTION("Microchip LAN966x OIC driver");
> +MODULE_LICENSE("GPL");
> --
> 2.44.0
Best regards
Steen
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2024-05-08 8:09 UTC|newest]
Thread overview: 111+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-30 8:37 [PATCH 00/17] Add support for the LAN966x PCI device using a DT overlay Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-04-30 8:37 ` [PATCH 01/17] mfd: syscon: Add reference counting and device managed support Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-04-30 20:34 ` Simon Horman
2024-04-30 20:34 ` Simon Horman
2024-05-02 13:29 ` Herve Codina
2024-05-02 13:29 ` Herve Codina
2024-04-30 21:55 ` kernel test robot
2024-04-30 21:55 ` kernel test robot
2024-04-30 22:07 ` kernel test robot
2024-04-30 22:07 ` kernel test robot
2024-04-30 8:37 ` [PATCH 02/17] reset: mchp: sparx5: Remove dependencies and allow building as a module Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-04-30 8:37 ` [PATCH 03/17] reset: mchp: sparx5: Release syscon when not use anymore Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-04-30 8:37 ` [PATCH 04/17] reset: core: add get_device()/put_device on rcdev Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-06-21 10:16 ` Philipp Zabel
2024-04-30 8:37 ` [PATCH 05/17] reset: mchp: sparx5: set the dev member of the reset controller Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-04-30 8:37 ` [PATCH 06/17] dt-bindings: net: mscc-miim: Add resets property Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-04-30 13:55 ` Andrew Lunn
2024-04-30 13:55 ` Andrew Lunn
2024-04-30 15:40 ` Herve Codina
2024-04-30 15:40 ` Herve Codina
2024-04-30 16:31 ` Andrew Lunn
2024-04-30 16:31 ` Andrew Lunn
2024-05-02 9:50 ` Herve Codina
2024-05-02 9:50 ` Herve Codina
2024-05-02 10:31 ` Conor Dooley
2024-05-02 10:31 ` Conor Dooley
2024-05-02 12:26 ` Andrew Lunn
2024-05-02 12:26 ` Andrew Lunn
2024-05-02 13:22 ` Alexandre Belloni
2024-05-02 13:22 ` Alexandre Belloni
2024-05-03 14:21 ` Herve Codina
2024-05-03 14:21 ` Herve Codina
2024-04-30 8:37 ` [PATCH 07/17] net: mdio: mscc-miim: Handle the switch reset Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-04-30 9:21 ` Sai Krishna Gajula
2024-04-30 9:21 ` Sai Krishna Gajula
2024-05-02 13:26 ` Herve Codina
2024-05-02 13:26 ` Herve Codina
2024-04-30 13:46 ` Andrew Lunn
2024-04-30 13:46 ` Andrew Lunn
2024-04-30 15:40 ` Herve Codina
2024-04-30 15:40 ` Herve Codina
2024-04-30 8:37 ` [PATCH 08/17] net: lan966x: remove debugfs directory in probe() error path Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-04-30 13:57 ` Andrew Lunn
2024-04-30 13:57 ` Andrew Lunn
2024-04-30 14:01 ` Andrew Lunn
2024-04-30 14:01 ` Andrew Lunn
2024-04-30 8:37 ` [PATCH 09/17] dt-bindings: interrupt-controller: Add support for Microchip LAN966x OIC Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-05-07 15:28 ` Rob Herring
2024-05-07 15:28 ` Rob Herring
2024-05-13 12:37 ` Herve Codina
2024-05-13 12:37 ` Herve Codina
2024-05-13 14:53 ` Rob Herring
2024-05-13 14:53 ` Rob Herring
2024-05-13 17:04 ` Herve Codina
2024-05-13 17:04 ` Herve Codina
2024-05-22 14:24 ` Rob Herring (Arm)
2024-05-22 14:24 ` Rob Herring (Arm)
2024-04-30 8:37 ` [PATCH 10/17] irqdomain: Add missing parameter descriptions in docs Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-05-02 0:03 ` Thomas Gleixner
2024-05-02 0:03 ` Thomas Gleixner
2024-04-30 8:37 ` [PATCH 11/17] irqdomain: Introduce irq_domain_alloc() and irq_domain_publish() Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-04-30 8:37 ` [PATCH 12/17] irqchip: Add support for LAN966x OIC Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-04-30 20:24 ` Simon Horman
2024-04-30 20:24 ` Simon Horman
2024-05-02 13:24 ` Herve Codina
2024-05-02 13:24 ` Herve Codina
2024-05-01 1:17 ` kernel test robot
2024-05-01 1:17 ` kernel test robot
2024-05-08 8:08 ` Steen.Hegelund [this message]
2024-05-08 8:08 ` Steen.Hegelund
2024-05-13 12:50 ` Herve Codina
2024-05-13 12:50 ` Herve Codina
2024-04-30 8:37 ` [PATCH 13/17] MAINTAINERS: Add the Microchip LAN966x OIC driver entry Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-04-30 8:37 ` [PATCH 14/17] of: dynamic: Introduce of_changeset_add_prop_bool() Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-05-08 18:03 ` Rob Herring
2024-05-08 18:03 ` Rob Herring
2024-04-30 8:37 ` [PATCH 15/17] pci: of_property: Add the interrupt-controller property in PCI device nodes Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-05-01 17:38 ` Bjorn Helgaas
2024-05-01 17:38 ` Bjorn Helgaas
2024-05-03 14:40 ` Herve Codina
2024-05-03 14:40 ` Herve Codina
2024-04-30 8:37 ` [PATCH 16/17] mfd: Add support for LAN966x PCI device Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-05-08 8:20 ` Steen.Hegelund
2024-05-08 8:20 ` Steen.Hegelund
2024-05-14 12:55 ` Herve Codina
2024-05-14 12:55 ` Herve Codina
2024-04-30 8:37 ` [PATCH 17/17] MAINTAINERS: Add the Microchip LAN966x PCI driver entry Herve Codina
2024-04-30 8:37 ` Herve Codina
2024-04-30 13:40 ` [PATCH 00/17] Add support for the LAN966x PCI device using a DT overlay Andrew Lunn
2024-04-30 13:40 ` Andrew Lunn
2024-04-30 16:33 ` Herve Codina
2024-04-30 16:33 ` Herve Codina
2024-04-30 18:15 ` Andrew Lunn
2024-04-30 18:15 ` Andrew Lunn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=D143YFK7334S.3MM7YORC0H24X@microchip.com \
--to=steen.hegelund@microchip.com \
--cc=Allan.Nielsen@microchip.com \
--cc=Daniel.Machon@microchip.com \
--cc=Horatiu.Vultur@microchip.com \
--cc=Lars.Povlsen@microchip.com \
--cc=UNGLinuxDriver@microchip.com \
--cc=alexandre.belloni@bootlin.com \
--cc=andrew@lunn.ch \
--cc=arnd@arndb.de \
--cc=bhelgaas@google.com \
--cc=conor+dt@kernel.org \
--cc=davem@davemloft.net \
--cc=devicetree@vger.kernel.org \
--cc=edumazet@google.com \
--cc=herve.codina@bootlin.com \
--cc=hkallweit1@gmail.com \
--cc=krzk+dt@kernel.org \
--cc=kuba@kernel.org \
--cc=lee@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=luca.ceresoli@bootlin.com \
--cc=netdev@vger.kernel.org \
--cc=p.zabel@pengutronix.de \
--cc=pabeni@redhat.com \
--cc=robh@kernel.org \
--cc=saravanak@google.com \
--cc=tglx@linutronix.de \
--cc=thomas.petazzoni@bootlin.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.