Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1685167 > unrolled thread

Re: [RFC PATCH v1] irqchip: Add support for tango interrupt router

Started byMason <slash.tmp@free.fr>
First post2017-07-11 18:00 +0200
Last post2017-07-17 23:30 +0200
Articles 6 — 1 participant

Back to article view | Back to linux.kernel

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: [RFC PATCH v1] irqchip: Add support for tango interrupt router Mason <slash.tmp@free.fr> - 2017-07-11 18:00 +0200
    [RFC PATCH v2] irqchip: Add support for tango interrupt router Mason <slash.tmp@free.fr> - 2017-07-12 18:40 +0200
      Re: [RFC PATCH v2] irqchip: Add support for tango interrupt router Mason <slash.tmp@free.fr> - 2017-07-15 15:10 +0200
        Re: [RFC PATCH v2] irqchip: Add support for tango interrupt router Mason <slash.tmp@free.fr> - 2017-07-16 01:50 +0200
          [RFC PATCH v3] irqchip: Add support for tango interrupt router Mason <slash.tmp@free.fr> - 2017-07-17 17:40 +0200
            Re: [RFC PATCH v3] irqchip: Add support for tango interrupt router Mason <slash.tmp@free.fr> - 2017-07-17 23:30 +0200

#1685167 — Re: [RFC PATCH v1] irqchip: Add support for tango interrupt router

FromMason <slash.tmp@free.fr>
Date2017-07-11 18:00 +0200
SubjectRe: [RFC PATCH v1] irqchip: Add support for tango interrupt router
Message-ID<u25JU-4bX-3@gated-at.bofh.it>
On 06/06/2017 17:52, Thomas Petazzoni wrote:

> On Tue, 6 Jun 2017 15:42:36 +0200, Mason wrote:
> 
>> +	interrupt-controller@6f800 {
>> +		compatible = "sigma,smp8759-intc";
>> +		reg = <0x6f800 0x430>;
>> +		interrupt-controller;
>> +		#interrupt-cells = <2>;
>> +		interrupt-parent = <&gic>;
>> +		/*
>> +		 * There probably is a better way than explicitly listing
>> +		 * the 24 interrupts?
>> +		 */
> 
> What we do on Marvell platforms is:
> 
> 	marvell,spi-base = <128>, <136>, <144>, <152>;
> 
> see marvell,odmi-controller.txt.
> 
> In another driver I submitted, we're doing:
> 
> 	marvell,spi-ranges = <64 64>, <288 64>;
> 
> Retrospectively, I would have preferred to use marvell,spi-ranges for
> the first DT binding as well, since it allows to express both the base
> and number of interrupts available in the range.

Sorry for the delay, I got distracted by other drivers
(PCIe, clkgen, i2c, infrared).

Thanks for the suggestion.

So, if I remove the "interrupts" property from the controller's
DT node, I can no longer use irq_of_parse_and_map() followed by
irqd_set_trigger_type(), right?

I would have to "emulate" irq_of_parse_and_map() with
something along the lines of:

#include <dt-bindings/interrupt-controller/arm-gic.h>
static int __init map_irq(struct device_node *gic, int irq, int type)
{
	struct of_phandle_args data = { gic, 3, { GIC_SPI, irq, type }};
	return irq_create_of_mapping(&data);
}

Then map all 24 interrupts at init:

	virq = map_irq(gic, 0, IRQ_TYPE_LEVEL_HIGH);
	for (i = 1; i < 24; ++i)
		virq = map_irq(gic, i, IRQ_TYPE_EDGE_RISING);

Is that correct?

Does it make sense to use a separate ISR for the two kinds
of interrupts?

Regards.

[toc] | [next] | [standalone]


#1685898 — [RFC PATCH v2] irqchip: Add support for tango interrupt router

FromMason <slash.tmp@free.fr>
Date2017-07-12 18:40 +0200
Subject[RFC PATCH v2] irqchip: Add support for tango interrupt router
Message-ID<u2sQa-28X-27@gated-at.bofh.it>
In reply to#1685167
128 inputs, 24 outputs (to GIC SPI 0-23)
---
There might be a few things wrong with this driver.
When I cat /proc/interrupts the interrupt count appears
to be bogus (as if level IRQ counts are added to edge
IRQ counts). Did I mess something up with the IRQ domains?
---
 .../interrupt-controller/sigma,smp8759-intc.txt    |  18 ++
 drivers/irqchip/Makefile                           |   2 +-
 drivers/irqchip/irq-smp8759.c                      | 203 +++++++++++++++++++++
 3 files changed, 222 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sigma,smp8759-intc.txt
 create mode 100644 drivers/irqchip/irq-smp8759.c

diff --git a/Documentation/devicetree/bindings/interrupt-controller/sigma,smp8759-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/sigma,smp8759-intc.txt
new file mode 100644
index 000000000000..9ec922f3c0a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/sigma,smp8759-intc.txt
@@ -0,0 +1,18 @@
+Sigma Designs SMP8759 interrupt router
+
+Required properties:
+- compatible: "sigma,smp8759-intc"
+- reg: address/size of register area
+- interrupt-controller
+- #interrupt-cells: <2>  (hwirq and trigger_type)
+- interrupt-parent: parent phandle
+
+Example:
+
+	interrupt-controller@6f800 {
+		compatible = "sigma,smp8759-intc";
+		reg = <0x6f800 0x430>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		interrupt-parent = <&gic>;
+	};
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index e4dbfc85abdb..013104923b71 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -47,7 +47,7 @@ obj-$(CONFIG_VERSATILE_FPGA_IRQ)	+= irq-versatile-fpga.o
 obj-$(CONFIG_ARCH_NSPIRE)		+= irq-zevio.o
 obj-$(CONFIG_ARCH_VT8500)		+= irq-vt8500.o
 obj-$(CONFIG_ST_IRQCHIP)		+= irq-st.o
-obj-$(CONFIG_TANGO_IRQ)			+= irq-tango.o
+obj-$(CONFIG_TANGO_IRQ)			+= irq-tango.o irq-smp8759.o
 obj-$(CONFIG_TB10X_IRQC)		+= irq-tb10x.o
 obj-$(CONFIG_TS4800_IRQ)		+= irq-ts4800.o
 obj-$(CONFIG_XTENSA)			+= irq-xtensa-pic.o
diff --git a/drivers/irqchip/irq-smp8759.c b/drivers/irqchip/irq-smp8759.c
new file mode 100644
index 000000000000..ec7fee4574ef
--- /dev/null
+++ b/drivers/irqchip/irq-smp8759.c
@@ -0,0 +1,203 @@
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+
+#define IRQ_MAX		128
+#define SPI_MAX		24 /* 24 output lines routed to SPI 0-23 */
+#define LEVEL_SPI	17
+#define IRQ_ENABLE	BIT(31)
+
+/*
+ * 128 inputs mapped to 24 outputs
+ * LEVEL_HIGH IRQs are muxed on output line 'LEVEL_SPI'
+ * EDGE_RISING IRQs get a dedicated output line
+ * gic_spi_to_tango_hwirq array maps GIC SPI hwirq to tango hwirq
+ */
+struct tango_intc {
+	DECLARE_BITMAP(enabled, IRQ_MAX);
+	spinlock_t lock;
+	void __iomem *config;
+	void __iomem *status;
+	struct irq_domain *dom;
+	u8 gic_spi_to_tango_hwirq[SPI_MAX];
+};
+
+static void tango_level_isr(struct irq_desc *desc)
+{
+	unsigned int pos, virq;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct tango_intc *intc = irq_desc_get_handler_data(desc);
+	DECLARE_BITMAP(status, IRQ_MAX);
+
+	chained_irq_enter(chip, desc);
+
+	memcpy_fromio(status, intc->status, IRQ_MAX / BITS_PER_BYTE);
+	spin_lock(&intc->lock);
+	bitmap_and(status, status, intc->enabled, IRQ_MAX);
+	spin_unlock(&intc->lock);
+	for_each_set_bit(pos, status, IRQ_MAX) {
+		virq = irq_find_mapping(intc->dom, pos);
+		generic_handle_irq(virq);
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+static void tango_edge_isr(struct irq_desc *desc)
+{
+	unsigned int virq;
+	struct irq_data *d = &desc->irq_data;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct tango_intc *intc = irq_desc_get_handler_data(desc);
+
+	/* I don't know how to get the SPI number, d->hwirq - 32 is a hack */
+	int hwirq = intc->gic_spi_to_tango_hwirq[d->hwirq - 32];
+	//printk("%s: SPI=%lu hwirq=%d\n", __func__, d->hwirq, hwirq);
+
+	chained_irq_enter(chip, desc);
+	virq = irq_find_mapping(intc->dom, hwirq);
+	generic_handle_irq(virq);
+	chained_irq_exit(chip, desc);
+}
+
+static void tango_mask(struct irq_data *data)
+{
+	unsigned long flags;
+	struct tango_intc *intc = data->chip_data;
+
+	spin_lock_irqsave(&intc->lock, flags);
+	__clear_bit(data->hwirq, intc->enabled);
+	writel_relaxed(0, intc->config + data->hwirq * 4);
+	spin_unlock_irqrestore(&intc->lock, flags);
+}
+
+static void tango_unmask(struct irq_data *data)
+{
+	unsigned long flags;
+	struct tango_intc *intc = data->chip_data;
+
+#if 0
+	if (!in_irq() && !in_interrupt()) {
+		printk("HWIRQ=%lu mask=%u\n", data->hwirq, data->mask);
+		dump_stack();
+	}
+#endif
+
+	spin_lock_irqsave(&intc->lock, flags);
+	__set_bit(data->hwirq, intc->enabled);
+	writel_relaxed(IRQ_ENABLE | data->mask, intc->config + data->hwirq * 4);
+	spin_unlock_irqrestore(&intc->lock, flags);
+}
+
+static int find_free_output_line(struct tango_intc *intc)
+{
+	int spi;
+
+	for (spi = 0; spi < SPI_MAX; ++spi)
+		if (intc->gic_spi_to_tango_hwirq[spi] == 0)
+			return spi;
+
+	return -ENOSPC;
+}
+
+int tango_set_type(struct irq_data *data, unsigned int flow_type)
+{
+	struct tango_intc *intc = data->chip_data;
+	printk("%s: IRQ=%lu type=%x\n", __func__, data->hwirq, flow_type);
+	dump_stack();
+	if (flow_type & IRQ_TYPE_LEVEL_HIGH) {
+		data->mask = LEVEL_SPI;
+		return 0;
+	}
+
+	if (flow_type & IRQ_TYPE_EDGE_RISING) {
+		int res = find_free_output_line(intc);
+		if (res < 0)
+			return res;
+		data->mask = res;
+		intc->gic_spi_to_tango_hwirq[res] = data->hwirq;
+		printk("Map tango hwirq %lu to GIC SPI %d\n", data->hwirq, res);
+		return 0;
+	}
+
+	/* LEVEL_LOW and EDGE_FALLING are not supported */
+	return -ENOSYS;
+}
+
+static struct irq_chip tango_chip = {
+	.name		= "tango",
+	.irq_mask	= tango_mask,
+	.irq_unmask	= tango_unmask,
+	.irq_set_type	= tango_set_type,
+};
+
+static int tango_map(struct irq_domain *dom, unsigned int virq, irq_hw_number_t hw)
+{
+	struct tango_intc *intc = dom->host_data;
+	struct irq_desc *desc = irq_to_desc(virq);
+	printk("%s: dom=%p virq=%u hwirq=%lu desc=%p\n", __func__, dom, virq, hw, desc);
+	irq_domain_set_info(dom, virq, hw, &tango_chip, intc, handle_simple_irq, NULL, NULL);
+	return 0;
+}
+
+static void tango_unmap(struct irq_domain *d, unsigned int virq)
+{
+	printk("%s: dom=%p virq=%u\n", __func__, d, virq);
+	dump_stack();
+}
+
+struct irq_domain_ops dom_ops =
+{
+	.map	= tango_map,
+	.unmap	= tango_unmap,
+	.xlate	= irq_domain_xlate_twocell,
+};
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+static int __init map_irq(struct device_node *gic, int irq, int type)
+{
+	struct of_phandle_args irq_data = { gic, 3, { GIC_SPI, irq, type }};
+	return irq_create_of_mapping(&irq_data);
+}
+
+static int __init tango_irq_init(struct device_node *node, struct device_node *parent)
+{
+	int spi, virq;
+	struct irq_domain *irq_dom;
+	void __iomem *base;
+	struct tango_intc *intc = kzalloc(sizeof(*intc), GFP_KERNEL);
+
+	base = of_iomap(node, 0);
+	if (!base)
+		panic("%s: of_iomap failed", node->name);
+
+	virq = map_irq(parent, LEVEL_SPI, IRQ_TYPE_LEVEL_HIGH);
+	if (!virq)
+		panic("%s: Failed to map IRQ %d\n", node->name, LEVEL_SPI);
+
+	irq_set_chained_handler_and_data(virq, tango_level_isr, intc);
+
+	for (spi = 0; spi < SPI_MAX; ++spi) {
+		if (spi == LEVEL_SPI)
+			continue;
+
+		virq = map_irq(parent, spi, IRQ_TYPE_EDGE_RISING);
+		if (!virq)
+			panic("%s: Failed to map IRQ %d\n", node->name, spi);
+
+		irq_set_chained_handler_and_data(virq, tango_edge_isr, intc);
+	}
+
+	irq_dom = irq_domain_add_linear(node, IRQ_MAX, &dom_ops, intc);
+
+	spin_lock_init(&intc->lock);
+	intc->config = base;
+	intc->status = base + 0x420;
+	intc->dom = irq_dom;
+	intc->gic_spi_to_tango_hwirq[LEVEL_SPI] = ~0;
+
+	return 0;
+}
+IRQCHIP_DECLARE(tango_intc, "sigma,smp8759-intc", tango_irq_init);

[toc] | [prev] | [next] | [standalone]


#1687946 — Re: [RFC PATCH v2] irqchip: Add support for tango interrupt router

FromMason <slash.tmp@free.fr>
Date2017-07-15 15:10 +0200
SubjectRe: [RFC PATCH v2] irqchip: Add support for tango interrupt router
Message-ID<u3uZB-1SL-25@gated-at.bofh.it>
In reply to#1685898
On 12/07/2017 18:39, Mason wrote:

> 128 inputs, 24 outputs (to GIC SPI 0-23)
> 
> There might be a few things wrong with this driver. When I
> cat /proc/interrupts the interrupt count appears to be bogus
> (as if level IRQ counts are added to edge IRQ counts).

OK, I found the issue.

It occurred on the interrupt lines that stay high when
the HW block is idle, so I mishandled them on every
level interrupt.

I have two remaining issues:

1) In the ISR, I get the hwirq from the GIC. What is the
API to translate that to the SPI? I'm currently just
subtracting 32.

2) I'm currently using a single domain, with a
handle_simple_irq domain handler. That's probably
wrong. Should I define two domains, one for edge
IRQs and one for level IRQs, and use the appropriate
handler?  Should both domain have 128 entries?
(I.e. are they indexed by the hwirq?)
And should I use linear or tree?

Regards.

[toc] | [prev] | [next] | [standalone]


#1688020 — Re: [RFC PATCH v2] irqchip: Add support for tango interrupt router

FromMason <slash.tmp@free.fr>
Date2017-07-16 01:50 +0200
SubjectRe: [RFC PATCH v2] irqchip: Add support for tango interrupt router
Message-ID<u3EYV-7SX-1@gated-at.bofh.it>
In reply to#1687946
On 15/07/2017 15:06, Mason wrote:

> I have two remaining issues:
> 
> 1) In the ISR, I get the hwirq from the GIC. What is the
> API to translate that to the SPI? I'm currently just
> subtracting 32.

gic_set_type() in drivers/irqchip/irq-gic.c

	/* SPIs have restrictions on the supported types */
	if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
			    type != IRQ_TYPE_EDGE_RISING)
		return -EINVAL;


gic_irq_domain_translate() in the same file:

		/* Get the interrupt number and add 16 to skip over SGIs */
		*hwirq = fwspec->param[1] + 16;

		/*
		 * For SPIs, we need to add 16 more to get the GIC irq
		 * ID number
		 */
		if (!fwspec->param[0])
			*hwirq += 16;


So it seems "acceptable" to compute spi = d->hwirq - 32;


> 2) I'm currently using a single domain, with a
> handle_simple_irq domain handler. That's probably
> wrong. Should I define two domains, one for edge
> IRQs and one for level IRQs, and use the appropriate
> handler?  Should both domain have 128 entries?
> (I.e. are they indexed by the hwirq?)
> And should I use linear or tree?

I will read this again carefully:
https://www.kernel.org/doc/Documentation/IRQ-domain.txt

Regards.

[toc] | [prev] | [next] | [standalone]


#1689180 — [RFC PATCH v3] irqchip: Add support for tango interrupt router

FromMason <slash.tmp@free.fr>
Date2017-07-17 17:40 +0200
Subject[RFC PATCH v3] irqchip: Add support for tango interrupt router
Message-ID<u4ghP-6Sd-7@gated-at.bofh.it>
In reply to#1688020
This controller maps 128 input lines to 24 output lines.
The output lines are routed to GIC SPI 0 to 23.
This driver muxes LEVEL_HIGH IRQs onto output line 0,
and gives every EDGE_RISING IRQ a dedicated output line.
---
I think the driver is mostly finished. It works without errors
for my basic use-cases. There is one required feature missing:
suspend/resume support. Should it be a separate patch, or just
squashed into this patch? Regards.
---
 .../interrupt-controller/sigma,smp8759-intc.txt    |  18 +++
 drivers/irqchip/Makefile                           |   2 +-
 drivers/irqchip/irq-smp8759.c                      | 169 +++++++++++++++++++++
 3 files changed, 188 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sigma,smp8759-intc.txt
 create mode 100644 drivers/irqchip/irq-smp8759.c

diff --git a/Documentation/devicetree/bindings/interrupt-controller/sigma,smp8759-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/sigma,smp8759-intc.txt
new file mode 100644
index 000000000000..9ec922f3c0a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/sigma,smp8759-intc.txt
@@ -0,0 +1,18 @@
+Sigma Designs SMP8759 interrupt router
+
+Required properties:
+- compatible: "sigma,smp8759-intc"
+- reg: address/size of register area
+- interrupt-controller
+- #interrupt-cells: <2>  (hwirq and trigger_type)
+- interrupt-parent: parent phandle
+
+Example:
+
+	interrupt-controller@6f800 {
+		compatible = "sigma,smp8759-intc";
+		reg = <0x6f800 0x430>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		interrupt-parent = <&gic>;
+	};
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index e4dbfc85abdb..013104923b71 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -47,7 +47,7 @@ obj-$(CONFIG_VERSATILE_FPGA_IRQ)	+= irq-versatile-fpga.o
 obj-$(CONFIG_ARCH_NSPIRE)		+= irq-zevio.o
 obj-$(CONFIG_ARCH_VT8500)		+= irq-vt8500.o
 obj-$(CONFIG_ST_IRQCHIP)		+= irq-st.o
-obj-$(CONFIG_TANGO_IRQ)			+= irq-tango.o
+obj-$(CONFIG_TANGO_IRQ)			+= irq-tango.o irq-smp8759.o
 obj-$(CONFIG_TB10X_IRQC)		+= irq-tb10x.o
 obj-$(CONFIG_TS4800_IRQ)		+= irq-ts4800.o
 obj-$(CONFIG_XTENSA)			+= irq-xtensa-pic.o
diff --git a/drivers/irqchip/irq-smp8759.c b/drivers/irqchip/irq-smp8759.c
new file mode 100644
index 000000000000..b3274779ee7a
--- /dev/null
+++ b/drivers/irqchip/irq-smp8759.c
@@ -0,0 +1,169 @@
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+
+/*
+ * This controller maps IRQ_MAX input lines to SPI_MAX output lines.
+ * The output lines are routed to GIC SPI 0 to 23.
+ * This driver muxes LEVEL_HIGH IRQs onto output line 0,
+ * and gives every EDGE_RISING IRQ a dedicated output line.
+ */
+#define IRQ_MAX		128
+#define SPI_MAX		24
+#define LEVEL_SPI	0
+#define IRQ_ENABLE	BIT(31)
+#define STATUS		0x420
+
+struct tango_intc {
+	void __iomem *base;
+	struct irq_domain *dom;
+	u8 spi_to_tango_irq[SPI_MAX];
+	DECLARE_BITMAP(enabled_level, IRQ_MAX);
+	spinlock_t lock;
+};
+
+static void tango_level_isr(struct irq_desc *desc)
+{
+	unsigned int pos, virq;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct tango_intc *intc = irq_desc_get_handler_data(desc);
+	DECLARE_BITMAP(status, IRQ_MAX);
+
+	chained_irq_enter(chip, desc);
+
+	spin_lock(&intc->lock);
+	memcpy_fromio(status, intc->base + STATUS, IRQ_MAX / BITS_PER_BYTE);
+	bitmap_and(status, status, intc->enabled_level, IRQ_MAX);
+	spin_unlock(&intc->lock);
+
+	for_each_set_bit(pos, status, IRQ_MAX) {
+		virq = irq_find_mapping(intc->dom, pos);
+		generic_handle_irq(virq);
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+static void tango_edge_isr(struct irq_desc *desc)
+{
+	unsigned int virq;
+	struct irq_data *data = irq_desc_get_irq_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct tango_intc *intc = irq_desc_get_handler_data(desc);
+	int tango_irq = intc->spi_to_tango_irq[data->hwirq - 32];
+
+	chained_irq_enter(chip, desc);
+	virq = irq_find_mapping(intc->dom, tango_irq);
+	generic_handle_irq(virq);
+	chained_irq_exit(chip, desc);
+}
+
+static void tango_mask(struct irq_data *data)
+{
+	unsigned long flags;
+	struct tango_intc *intc = data->chip_data;
+
+	spin_lock_irqsave(&intc->lock, flags);
+	writel_relaxed(0, intc->base + data->hwirq * 4);
+	if (data->mask == LEVEL_SPI)
+		__clear_bit(data->hwirq, intc->enabled_level);
+	spin_unlock_irqrestore(&intc->lock, flags);
+}
+
+static void tango_unmask(struct irq_data *data)
+{
+	unsigned long flags;
+	struct tango_intc *intc = data->chip_data;
+
+	spin_lock_irqsave(&intc->lock, flags);
+	writel_relaxed(IRQ_ENABLE | data->mask, intc->base + data->hwirq * 4);
+	if (data->mask == LEVEL_SPI)
+		__set_bit(data->hwirq, intc->enabled_level);
+	spin_unlock_irqrestore(&intc->lock, flags);
+}
+
+static int tango_set_type(struct irq_data *data, unsigned int flow_type)
+{
+	struct tango_intc *intc = data->chip_data;
+	int spi;
+
+	if (flow_type & IRQ_TYPE_LEVEL_HIGH) {
+		data->mask = LEVEL_SPI;
+		return 0;
+	}
+
+	if (flow_type & IRQ_TYPE_EDGE_RISING) {
+		for (spi = 1; spi < SPI_MAX; ++spi) {
+			if (intc->spi_to_tango_irq[spi] == 0) {
+				data->mask = spi;
+				intc->spi_to_tango_irq[spi] = data->hwirq;
+				return 0;
+			}
+		}
+		return -ENOSPC;
+	}
+
+	return -EINVAL;
+}
+
+static struct irq_chip tango_chip = {
+	.name		= "tango",
+	.irq_mask	= tango_mask,
+	.irq_unmask	= tango_unmask,
+	.irq_set_type	= tango_set_type,
+};
+
+static int tango_map(struct irq_domain *dom, unsigned int virq, irq_hw_number_t hwirq)
+{
+	struct tango_intc *intc = dom->host_data;
+
+	irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &tango_chip, intc);
+	irq_set_handler(virq, handle_simple_irq);
+
+	return 0;
+}
+
+static struct irq_domain_ops dom_ops = {
+	.map	= tango_map,
+	.xlate	= irq_domain_xlate_twocell,
+};
+
+static int __init map_irq(struct device_node *gic, int spi, int trigger)
+{
+	struct of_phandle_args irq_data = { gic, 3, { 0, spi, trigger }};
+	return irq_create_of_mapping(&irq_data);
+}
+
+static int __init tango_irq_init(struct device_node *node, struct device_node *parent)
+{
+	int spi, virq;
+	void __iomem *base;
+	struct tango_intc *intc;
+
+	intc = kzalloc(sizeof(*intc), GFP_KERNEL);
+	base = of_iomap(node, 0);
+	if (!intc || !base)
+		panic("%s: Failed to kzalloc and iomap\n", node->name);
+
+	virq = map_irq(parent, LEVEL_SPI, IRQ_TYPE_LEVEL_HIGH);
+	if (!virq)
+		panic("%s: Failed to map IRQ %d\n", node->name, LEVEL_SPI);
+
+	irq_set_chained_handler_and_data(virq, tango_level_isr, intc);
+
+	for (spi = 1; spi < SPI_MAX; ++spi) {
+		virq = map_irq(parent, spi, IRQ_TYPE_EDGE_RISING);
+		if (!virq)
+			panic("%s: Failed to map IRQ %d\n", node->name, spi);
+
+		irq_set_chained_handler_and_data(virq, tango_edge_isr, intc);
+	}
+
+	intc->base = base;
+	intc->dom = irq_domain_add_linear(node, IRQ_MAX, &dom_ops, intc);
+	spin_lock_init(&intc->lock);
+
+	return 0;
+}
+IRQCHIP_DECLARE(tango_intc, "sigma,smp8759-intc", tango_irq_init);
-- 
2.11.0

[toc] | [prev] | [next] | [standalone]


#1689492 — Re: [RFC PATCH v3] irqchip: Add support for tango interrupt router

FromMason <slash.tmp@free.fr>
Date2017-07-17 23:30 +0200
SubjectRe: [RFC PATCH v3] irqchip: Add support for tango interrupt router
Message-ID<u4lKx-1Tb-5@gated-at.bofh.it>
In reply to#1689180
On 17/07/2017 17:36, Mason wrote:

> This controller maps 128 input lines to 24 output lines.
> The output lines are routed to GIC SPI 0 to 23.
> This driver muxes LEVEL_HIGH IRQs onto output line 0,
> and gives every EDGE_RISING IRQ a dedicated output line.
> ---
> I think the driver is mostly finished. It works without
> errors for my basic use-cases.

I spotted a problem. Output lines are allocated
for edge interrupts in tango_set_type() but they
are never released. So if we insmod/rmmod modules
in a loop, we will run out of output lines.

It seems set_type() is not the right place for an
allocation. Perhaps that should be done in tango_map()?

I'll try to trace the code to figure out when the
unmap function is called, as well.

> There is one required feature missing:
> suspend/resume support.
> Should it be a separate patch, or just squashed
> into this patch?

That question still stands.

Regards.

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web