Skip to contentSkip to conversation

irqchip: add support for SMP irq router

RFC PATCH Superseded Sebastian Frias 6 participants 32 messages Jun 30, 2016 – Jul 20, 2016

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 irqchip: add support for SMP irq router

This adds support for a second-gen irq router/controller present on some Sigma Designs chips.

---

This is a RFC because I have a few doubts:
1) I had to unroll irq_of_parse_and_map() in order to get the HW IRQ declared in the device tree so that I can associate it with a given domain.

2) I'm not sure about the DT specification, in particular, the use of child nodes to declare different domains, but it works

3) I'm calling this an irq router to somehow highlight the fact that it is not a simple interrupt controller. Indeed it does not latch the IRQ lines by itself, and does not supports edge detection.

4) Do I have to do something more to handle the affinity stuff?

5) checkpatch.pl reports warnings, etc. but I guess it's ok for now since it is a RFC :-)

Please feel free to comment and suggest improvements.

---
 .../sigma,smp87xx-irqrouter.txt                    |  69 +++
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-tango_v2.c                     | 594 +++++++++++++++++++++
 3 files changed, 664 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt
 create mode 100644 drivers/irqchip/irq-tango_v2.c
Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt new file +69 -0
new file mode 100644
index 0000000..0e404f0
@@ -0,0 +1,69 @@
+* Sigma Designs Interrupt Router
+
+This module can route N IRQ inputs into M IRQ outputs, with N>M.
+For instance N=128, M=24.
+
+Note however that the HW does not latches the IRQ lines, so devices
+connecting to the router are expected to latch their IRQ line by themselves.
+
+A single node in the device tree is used to describe the interrupt router.
+Child nodes (up to a maximum of 'outputs') describe irqdomains for the outputs
+of the interrupt router.
+These child nodes specify, via their 'interrupts' property, how the
+interrupt router is connected to its parent interrupt controller (usually the
+GIC), and define irqdomains that can be used in other nodes' 'interrupts'
+property.
+
+Required properties:
+- compatible: Should be "sigma,smp87xx-irqrouter".
+- interrupt-controller: Identifies the node as an interrupt controller.
+- inputs: The number of IRQ lines entering the router
+- outputs: The number of IRQ lines exiting the router
+- reg: Base address and size of interrupt router registers.
+- #interrupt-cells: Should be <2>. Defines how other nodes will be able to
+interact with this node. The meaning of the cells are
+	* First Cell: HW IRQ number.
+	* Second Cell: IRQ polarity (level high or low).
+
+Required properties of child nodes:
+- interrupt-controller: Identifies the node as an interrupt controller.
+- interrupts: Defines the hwirq associated with a domain and connected to
+the parent interrupt controller. The format of the interrupt specifier
+depends on the interrupt parent controller.
+
+Optional properties:
+- interrupt-parent: pHandle of the parent interrupt controller, if not
+  inherited from the parent node.
+
+
+Example:
+
+See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt and
+Documentation/devicetree/bindings/arm/gic.txt for further details.
+
+The following example declares a irqrouter with 128 inputs and 24 outputs,
+with registers @ 0x6F800 and connected to the GIC.
+The two child nodes define two irqdomains, one connected to GIC input 2
+(hwirq=2, level=high), and ther other connected to GIC input 3 (hwirq=3,
+level=low)
+
+		irq_router: irq_router@6f800 {
+			 compatible = "sigma,smp87xx-irqrouter";
+			 reg = <0x6f800 0x800>;
+			 interrupt-controller;
+			 interrupt-parent = <&gic>;
+			 inputs = <128>;
+			 outputs = <24>;
+
+			 irq0: irqdomain0@parentirq2 {
+			       interrupt-controller;
+			       #interrupt-cells = <2>;
+			       interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+			 };
+
+			 irq1: irqdomain1@parentirq3 {
+			       interrupt-controller;
+			       #interrupt-cells = <2>;
+			       interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_LOW>;
+			 };
+		};
drivers/irqchip/Makefile +1 -0
index 7451245..703a2b5 100644
@@ -39,6 +39,7 @@ 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_v2.o
 obj-$(CONFIG_TB10X_IRQC)		+= irq-tb10x.o
 obj-$(CONFIG_XTENSA)			+= irq-xtensa-pic.o
 obj-$(CONFIG_XTENSA_MX)			+= irq-xtensa-mx.o
drivers/irqchip/irq-tango_v2.c new file +594 -0

594 lines not on this page · raw message

Signature · 1 line
1.7.11.2
#1 lore raw
Quoted 2 lines · Sebastian Frias

This adds support for a second-gen irq router/controller present on some Sigma Designs chips.

In the patch subject, do you mean SMP as in Symmetric Multi Processor?

Quoted 1 line

Is that the address you intend to submit with?

Quoted 13 lines

This is a RFC because I have a few doubts:
1) I had to unroll irq_of_parse_and_map() in order to get the HW IRQ declared in the device tree so that I can associate it with a given domain.

2) I'm not sure about the DT specification, in particular, the use of child nodes to declare different domains, but it works

3) I'm calling this an irq router to somehow highlight the fact that it is not a simple interrupt controller. Indeed it does not latch the IRQ lines by itself, and does not supports edge detection.

Quoted 6 lines

4) Do I have to do something more to handle the affinity stuff?

5) checkpatch.pl reports warnings, etc. but I guess it's ok for now since it is a RFC :-)

Please feel free to comment and suggest improvements.

The "core" topic is over my head, so I'll just discuss the color of the bike shed.

Quoted 1 line
 .../sigma,smp87xx-irqrouter.txt                    |  69 +++

In the *actual* submission, we can't use a wildcard like smp87xx we'll have to use an actual part number.

Quoted 2 lines
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-tango_v2.c                     | 594 +++++++++++++++++++++

Likewise, I don't like the "_v2" suffix, it's too generic. Actual submission should use something more specific.

Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt line 6

Quoted 8 lines

+++ b/Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt

Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt new file +6 -0
@@ -0,0 +1,69 @@
+* Sigma Designs Interrupt Router
+
+This module can route N IRQ inputs into M IRQ outputs, with N>M.
+For instance N=128, M=24.
+
+Note however that the HW does not latches the IRQ lines, so devices
                                     ^^^^^^^

"does not latch"

Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt line 18

Quoted 2 lines
Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt new file +2 -0
+Required properties:
+- compatible: Should be "sigma,smp87xx-irqrouter".

Same comment about wildcard.

Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt line 21

Quoted 3 lines
Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt new file +3 -0
+- interrupt-controller: Identifies the node as an interrupt controller.
+- inputs: The number of IRQ lines entering the router
+- outputs: The number of IRQ lines exiting the router

As far as I can tell, if N > 256 then the register layout would have to change. (Likewise, if M > 32)

Also, you hard-code the fact that N/32 = 4 with the status_i variables.

Would it make sense to use for loops?
(instead of unrolling the loops)

e.g. for (i = 0; i < N/4; ++i) { ... }

Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt line 36

Quoted 3 lines
Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt new file +3 -0
+Optional properties:
+- interrupt-parent: pHandle of the parent interrupt controller, if not
+  inherited from the parent node.

I'm not sure this is what "optional" means.

Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt line 47

Quoted 4 lines
Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt new file +4 -0
+The following example declares a irqrouter with 128 inputs and 24 outputs,
+with registers @ 0x6F800 and connected to the GIC.
+The two child nodes define two irqdomains, one connected to GIC input 2
+(hwirq=2, level=high), and ther other connected to GIC input 3 (hwirq=3,
                              ^^^^

drivers/irqchip/irq-tango_v2.c line 92

Quoted 2 lines
drivers/irqchip/irq-tango_v2.c new file +2 -0
+#define ROUTER_INPUTS  (128)
+#define ROUTER_OUTPUTS (24)

Parentheses are unnecessary around constants.

drivers/irqchip/irq-tango_v2.c line 95

Quoted 2 lines
drivers/irqchip/irq-tango_v2.c new file +2 -0
+#define IRQ_ROUTER_ENABLE_MASK (BIT(31))
+#define IRQ_ROUTER_INVERT_MASK (BIT(16))

Parentheses already provided in BIT macro.

drivers/irqchip/irq-tango_v2.c line 100

Quoted 4 lines
drivers/irqchip/irq-tango_v2.c new file +4 -0
+#define READ_SYS_IRQ_GROUP0 (0x420)
+#define READ_SYS_IRQ_GROUP1 (0x424)
+#define READ_SYS_IRQ_GROUP2 (0x428)
+#define READ_SYS_IRQ_GROUP3 (0x42C)

If a for loop were used, we'd only need to
#define SYSTEM_IRQ 0x420

  for (i = 0; i < N/4; ++i) {
    status_i = readl(base + SYSTEM_IRQ + i*4);

drivers/irqchip/irq-tango_v2.c line 107

Quoted 5 lines
drivers/irqchip/irq-tango_v2.c new file +5 -0
+#if 0
+#define SHORT_OR_FULL_NAME full_name
+#else
+#define SHORT_OR_FULL_NAME name
+#endif

Just pick one?

drivers/irqchip/irq-tango_v2.c line 109

Quoted 1 line
drivers/irqchip/irq-tango_v2.c new file +1 -0
+#define NODE_NAME(__node__) (__node__ ? __node__->SHORT_OR_FULL_NAME : "<no-node>")

Is it possible for a node to not have a name?

I also think prefixing/postfixing macro parameters with underscores is positively fugly.

drivers/irqchip/irq-tango_v2.c line 133

Quoted 5 lines
drivers/irqchip/irq-tango_v2.c new file +5 -0
+/*
+  context for the driver
+*/
+struct tango_irqrouter {
+	raw_spinlock_t lock;

Is this lock really needed?

Is tango_irqdomain_handle_cascade_irq() expected to be called concurrently on multiple cores?

Even then, is it necessary to lock, in order to read 4 MMIO regs?

drivers/irqchip/irq-tango_v2.c line 141

Quoted 8 lines
drivers/irqchip/irq-tango_v2.c new file +8 -0
+	struct device_node *node;
+	void __iomem *base;
+	u32 input_count;
+	u32 output_count;
+	u32 irq_mask[BITMASK_VECTOR_SIZE(ROUTER_INPUTS)];
+	u32 irq_invert_mask[BITMASK_VECTOR_SIZE(ROUTER_INPUTS)];
+	struct tango_irqrouter_output output[ROUTER_OUTPUTS];
+};

Hmmm, if the driver were truly "parameterizable", I guess we should dynamically allocate the arrays.

Quoted 33 lines
drivers/irqchip/irq-tango_v2.c new file +33 -0
+static void tango_irqchip_mask_irq(struct irq_data *data)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+	u32 hwirq = data->hwirq;
+	u32 offset = IRQ_TO_OFFSET(hwirq);
+	u32 value = tango_readl(irqrouter, offset);
+	u32 hwirq_reg_index = hwirq / 32;
+	u32 hwirq_bit_index = hwirq % 32;
+
+	DBGLOG("%s: mask hwirq(in) %d : current regvalue 0x%x (routed to hwirq(out) %d)\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),
+	       hwirq, value, irqrouter_output->hwirq);
+
+	//mask cache
+	irqrouter->irq_mask[hwirq_reg_index] &= ~(1 << hwirq_bit_index);
+
+	value &= ~(IRQ_ROUTER_ENABLE_MASK);
+	tango_writel(irqrouter, offset, value);
+}
+
+static void tango_irqchip_unmask_irq(struct irq_data *data)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+	u32 hwirq = data->hwirq;
+	u32 offset = IRQ_TO_OFFSET(hwirq);
+	u32 value = tango_readl(irqrouter, offset);
+	u32 hwirq_reg_index = hwirq / 32;
+	u32 hwirq_bit_index = hwirq % 32;
+

drivers/irqchip/irq-tango_v2.c line 234

Quoted 10 lines
drivers/irqchip/irq-tango_v2.c new file +10 -0
+	DBGLOG("%s: unmask hwirq(in) %d : current regvalue 0x%x (routed to hwirq(out) %d)\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),
+	       hwirq, value, irqrouter_output->hwirq);
+
+	//unmask cache
+	irqrouter->irq_mask[hwirq_reg_index] |= (1 << hwirq_bit_index);
+
+	value |= IRQ_ROUTER_ENABLE_MASK;
+	tango_writel(irqrouter, offset, value);
+}

There might be an opportunity to factorize the two functions, and have mask/unmask call such "helper" with the proper args.

drivers/irqchip/irq-tango_v2.c line 420

Quoted 2 lines
drivers/irqchip/irq-tango_v2.c new file +2 -0
+#define HANDLE_INVERTED_LINES(__irqstatus__, __x__) ((((~__irqstatus__) & irqrouter->irq_invert_mask[__x__]) & irqrouter->irq_mask[__x__]) | __irqstatus__)
+#define HANDLE_ENABLE_AND_INVERSION_MASKS(__irqstatus__, __y__) (HANDLE_INVERTED_LINES(__irqstatus__, __y__) & irqrouter->irq_mask[__y__])

I'm pretty sure these macros make baby Jesus cry.

Quoted 21 lines
drivers/irqchip/irq-tango_v2.c new file +21 -0
+static int __init tango_of_irq_init(struct device_node *node,
+				    struct device_node *parent)
+{
+	struct tango_irqrouter *irqrouter;
+	struct device_node *child;
+	void __iomem *base;
+	u32 input_count, output_count, i;
+
+	base = of_iomap(node, 0);
+	if (!base) {
+		DBGERR("%s: failed to map combiner registers\n", node->name);
+		return -ENXIO;
+	}
+
+	of_property_read_u32(node, "inputs", &input_count);
+	if (!input_count) {
+		DBGERR("%s: missing 'inputs' property\n", node->name);
+		return -EINVAL;
+	}
+
+	of_property_read_u32(node, "outputs", &output_count);

drivers/irqchip/irq-tango_v2.c line 564

Quoted 10 lines
drivers/irqchip/irq-tango_v2.c new file +10 -0
+	if (!output_count) {
+		DBGERR("%s: missing 'outputs' property\n", node->name);
+		return -EINVAL;
+	}
+
+	if ((input_count != ROUTER_INPUTS)
+	    || (output_count != ROUTER_OUTPUTS)) {
+		DBGERR("%s: input/output count mismatch", node->name);
+		return -EINVAL;
+	}

So the driver is not intended to be parameterized? (or perhaps only in a follow-up?)

Regards.

#2 lore raw
Quoted 2 lines · Mason

In the patch subject, do you mean SMP as in Symmetric Multi Processor?

As in Sigma Multimedia Processor :-)
The prefix for Sigma's chips is SMP.

I can change that to "Tango" if it is confusing.

Quoted 2 lines

Is that the address you intend to submit with?

Yes.

Quoted 3 lines

The "core" topic is over my head, so I'll just discuss the color of the bike shed.

:-)
Thanks for your comments, hopefully some knowledgeable people will discuss the core topic as well.

Quoted 5 lines
Quoted 2 lines
 .../sigma,smp87xx-irqrouter.txt                    |  69 +++

In the *actual* submission, we can't use a wildcard like smp87xx we'll have to use an actual part number.

Are you sure?
That would hinder genericity.
Actually I wanted to call it "sigma,smp-irqrouter.txt" (or "sigma,smp,irqrouter.txt").

To me there's no need to link the compatible string of a given HW module with that of the chip name the module it is embedded into.
For example, the generic USB3 driver is "generic-xhci".
While this module is not generic to be embedded in chips from different manufacturers, it is supposed to be generic within Sigma, and multiple Sigma chips (with potentially different denominations) can use it.

Quoted 6 lines
Quoted 3 lines
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-tango_v2.c                     | 594 +++++++++++++++++++++

Likewise, I don't like the "_v2" suffix, it's too generic. Actual submission should use something more specific.

Well, the other driver is irq-tango.c that is generic as well. I prefer versioning, as it is unrelated with the actual chip name.

Following the reasoning from my previous reply, I think the file name should be something like "smp-irqrouter.c" to be close to the "compatible" string.

However, IMHO there is a mix of various naming conventions on the kernel tree so I don't know which one is recommended.

Quoted 11 lines

Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt line 6

Quoted 9 lines

+++ b/Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt

Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt new file +6 -0
@@ -0,0 +1,69 @@
+* Sigma Designs Interrupt Router
+
+This module can route N IRQ inputs into M IRQ outputs, with N>M.
+For instance N=128, M=24.
+
+Note however that the HW does not latches the IRQ lines, so devices
                                     ^^^^^^^

"does not latch"

Ok.

Quoted 8 lines

Also, you hard-code the fact that N/32 = 4 with the status_i variables.

Would it make sense to use for loops?
(instead of unrolling the loops)

e.g. for (i = 0; i < N/4; ++i) { ... }

Actually my current version uses this (also on "tango_irqdomain_handle_cascade_irq()"), but I'm not sure I'm happy with it because the person reading may think the code is generic while it is not. I mean, there is no guarantee on how the HW guys will extend this in the future, and trying to make the code generic could end up as wasted premature optimization.

Quoted 9 lines

Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt line 36

Quoted 4 lines
Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt new file +3 -0
+Optional properties:
+- interrupt-parent: pHandle of the parent interrupt controller, if not
+  inherited from the parent node.

I'm not sure this is what "optional" means.

From what I've seen in the documentation for other DT bindings, this is the meaning of "optional".

But I don't mind changing it if I get some hints about the meaning.

Quoted 11 lines

Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt line 47

Quoted 5 lines
Documentation/devicetree/bindings/interrupt-controller/sigma,smp87xx-irqrouter.txt new file +4 -0
+The following example declares a irqrouter with 128 inputs and 24 outputs,
+with registers @ 0x6F800 and connected to the GIC.
+The two child nodes define two irqdomains, one connected to GIC input 2
+(hwirq=2, level=high), and ther other connected to GIC input 3 (hwirq=3,
                              ^^^^

drivers/irqchip/irq-tango_v2.c line 92

Quoted 2 lines
drivers/irqchip/irq-tango_v2.c new file +2 -0
+#define ROUTER_INPUTS  (128)
+#define ROUTER_OUTPUTS (24)

Parentheses are unnecessary around constants.

I'm used to use parenthesis in macros to avoid operator priority side effects.

Quoted 5 lines

drivers/irqchip/irq-tango_v2.c line 95

Quoted 3 lines
drivers/irqchip/irq-tango_v2.c new file +2 -0
+#define IRQ_ROUTER_ENABLE_MASK (BIT(31))
+#define IRQ_ROUTER_INVERT_MASK (BIT(16))

Parentheses already provided in BIT macro.

Same as above.

Quoted 9 lines

drivers/irqchip/irq-tango_v2.c line 100

Quoted 5 lines
drivers/irqchip/irq-tango_v2.c new file +4 -0
+#define READ_SYS_IRQ_GROUP0 (0x420)
+#define READ_SYS_IRQ_GROUP1 (0x424)
+#define READ_SYS_IRQ_GROUP2 (0x428)
+#define READ_SYS_IRQ_GROUP3 (0x42C)

If a for loop were used, we'd only need to
#define SYSTEM_IRQ 0x420

Quoted 3 lines
  for (i = 0; i < N/4; ++i) {
    status_i = readl(base + SYSTEM_IRQ + i*4);

I suppose you mean "status[i]".
There's a trade-off between explicit and clear code, and compact code.
I believe in this case the unrolled code not only is more clear, it may end up being faster.

As I was saying earlier, my current version uses a mixed approach with the loop unrolled for reading the registers and a for loop for the dispatch.

If in the future we have to read much more registers, we should revisit this.

Quoted 7 lines

drivers/irqchip/irq-tango_v2.c line 107

Quoted 5 lines
drivers/irqchip/irq-tango_v2.c new file +5 -0
+#if 0
+#define SHORT_OR_FULL_NAME full_name
+#else
+#define SHORT_OR_FULL_NAME name
+#endif

Just pick one?

By making the choice explicit, the person reading/debugging is aware of the possibilities. Picking "full_name" or "name" would likely prevent the person from knowing it has other debug options.

Quoted 4 lines

drivers/irqchip/irq-tango_v2.c line 109

Quoted 2 lines
drivers/irqchip/irq-tango_v2.c new file +1 -0
+#define NODE_NAME(__node__) (__node__ ? __node__->SHORT_OR_FULL_NAME : "<no-node>")

Is it possible for a node to not have a name?

The code is about checking the 'node' is not NULL before dereferencing it;
Furthermore, printk is supposed to handle NULL pointers for %s ("be lenient with your input and strict with your output")

Quoted 15 lines

I also think prefixing/postfixing macro parameters with underscores is positively fugly.

From my point of view, it makes a clear difference between macro parameters and rest of the code.

drivers/irqchip/irq-tango_v2.c line 133

Quoted 5 lines
drivers/irqchip/irq-tango_v2.c new file +5 -0
+/*
+  context for the driver
+*/
+struct tango_irqrouter {
+	raw_spinlock_t lock;

Is this lock really needed?

Quoted 2 lines

Is tango_irqdomain_handle_cascade_irq() expected to be called concurrently on multiple cores?

Good question, I had asked myself the same.
include/linux/irq.h:irq_set_chained_handler_and_data() declaration has a comment saying that IRQ_NOTHREAD is used, but since I had seen a lock being used by other drivers, I thought to give it a try on this RFC.

Quoted 14 lines

Even then, is it necessary to lock, in order to read 4 MMIO regs?

drivers/irqchip/irq-tango_v2.c line 141

Quoted 8 lines
drivers/irqchip/irq-tango_v2.c new file +8 -0
+	struct device_node *node;
+	void __iomem *base;
+	u32 input_count;
+	u32 output_count;
+	u32 irq_mask[BITMASK_VECTOR_SIZE(ROUTER_INPUTS)];
+	u32 irq_invert_mask[BITMASK_VECTOR_SIZE(ROUTER_INPUTS)];
+	struct tango_irqrouter_output output[ROUTER_OUTPUTS];
+};

Hmmm, if the driver were truly "parameterizable", I guess we should dynamically allocate the arrays.

The key is "if it were...", since it is likely it will never be generic, I thought that dynamically allocating the arrays was not worth it.

I agree that there's a sort of hybrid approach, part "static", part "dynamic", in the sense that some things could be dynamically allocated (like the fields above), or dynamically handled (like the "status" registers), yet constant (and thus "static") macros or unrolled loops are used to define them because the driver is not really generic.

I can bet that if I had dynamically allocated the arrays, somebody could have commented that it was not necessary since the driver is not fully generic :-)

Quoted 16 lines
Quoted 16 lines
drivers/irqchip/irq-tango_v2.c new file +16 -0
+static void tango_irqchip_unmask_irq(struct irq_data *data)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+	u32 hwirq = data->hwirq;
+	u32 offset = IRQ_TO_OFFSET(hwirq);
+	u32 value = tango_readl(irqrouter, offset);
+	u32 hwirq_reg_index = hwirq / 32;
+	u32 hwirq_bit_index = hwirq % 32;
+
+	DBGLOG("%s: unmask hwirq(in) %d : current regvalue 0x%x (routed to hwirq(out) %d)\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),
+	       hwirq, value, irqrouter_output->hwirq);
+
+	//unmask cache
Quoted 9 lines

drivers/irqchip/irq-tango_v2.c line 234

Quoted 5 lines
drivers/irqchip/irq-tango_v2.c new file +5 -0
+	irqrouter->irq_mask[hwirq_reg_index] |= (1 << hwirq_bit_index);
+
+	value |= IRQ_ROUTER_ENABLE_MASK;
+	tango_writel(irqrouter, offset, value);
+}

There might be an opportunity to factorize the two functions, and have mask/unmask call such "helper" with the proper args.

You are right, these grew from just logging to actually doing something and did not get factored.

Quoted 9 lines

drivers/irqchip/irq-tango_v2.c line 564

Quoted 6 lines
drivers/irqchip/irq-tango_v2.c new file +6 -0
+
+	if ((input_count != ROUTER_INPUTS)
+	    || (output_count != ROUTER_OUTPUTS)) {
+		DBGERR("%s: input/output count mismatch", node->name);
+		return -EINVAL;
+	}

So the driver is not intended to be parameterized? (or perhaps only in a follow-up?)

It would be nice to have a fully generic driver, but I doubt that is possible.
Small changes would always be necessary due to the fact that the HW description itself (register distribution and their meaning) is not on the DT.
In the end it is a trade-off between code (and DT) clarity and simplicity, and fully generic code that would require lots of glue to handle a complex DT capable of describing the generic HW. In the current form, most of the code is actually to handle the IRQs, if it were generic I think a significant part of the code would be there just to deal with genericity, obscuring what the driver does.

So I went for a warning :-)

Best regards,

Sebastian

#3 lore raw

Hey Sebastian, Mason,

* Please fix mailer to wrap text at a sane length. I've re-wrapped and trimmed.

Quoted 1 line · Sebastian Frias

On 07/04/2016 02:11 PM, Mason wrote:

...

Quoted 8 lines
Quoted 4 lines
Quoted 1 line
 .../sigma,smp87xx-irqrouter.txt                    |  69 +++

In the *actual* submission, we can't use a wildcard like smp87xx we'll have to use an actual part number.

Are you sure?
That would hinder genericity.
Actually I wanted to call it "sigma,smp-irqrouter.txt" (or "sigma,smp,irqrouter.txt").

sigma,smp-irqrouter.txt should be fine. The devicetree maintainers should yelp if they want something different.

Quoted 8 lines

To me there's no need to link the compatible string of a given HW module with that of the chip name the module it is embedded into. For example, the generic USB3 driver is "generic-xhci". While this module is not generic to be embedded in chips from different manufacturers, it is supposed to be generic within Sigma, and multiple Sigma chips (with potentially different denominations) can use it.

Quoted 1 line
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-tango_v2.c                     | 594 +++++++++++++++++++++

Likewise, I don't like the "_v2" suffix, it's too generic. Actual submission should use something more specific.

Well, the other driver is irq-tango.c that is generic as well. I prefer versioning, as it is unrelated with the actual chip name.

Is there a name, similar to 'tango', for this version of the IP? Something that would spark recognition for someone looking for "the damn driver for this XYZ irqchip I have". If not, irq-tango_v2.c is fine.

thx,

Jason.

#4 lore raw
Quoted 11 lines · Jason Cooper
Quoted 9 lines · Sebastian Frias
Quoted 6 lines · Mason
Quoted 1 line · Sebastian Frias
 .../sigma,smp87xx-irqrouter.txt                    |  69 +++

In the *actual* submission, we can't use a wildcard like smp87xx we'll have to use an actual part number.

Quoted 6 lines
Quoted 3 lines

Are you sure?
That would hinder genericity.
Actually I wanted to call it "sigma,smp-irqrouter.txt" (or "sigma,smp,irqrouter.txt").

sigma,smp-irqrouter.txt should be fine. The devicetree maintainers should yelp if they want something different.

Personally, I don't like "smp" because it's too easy to confuse that for "symmetric multi-processor".

Come to think of it, I'm not sure the *name* of the file documenting a binding is as important to DT maintainers as the compatible string.

Quoted 14 lines
Quoted 14 lines

To me there's no need to link the compatible string of a given HW module with that of the chip name the module it is embedded into. For example, the generic USB3 driver is "generic-xhci". While this module is not generic to be embedded in chips from different manufacturers, it is supposed to be generic within Sigma, and multiple Sigma chips (with potentially different denominations) can use it.

Quoted 6 lines
Quoted 3 lines
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-tango_v2.c                     | 594 +++++++++++++++++++++

Likewise, I don't like the "_v2" suffix, it's too generic. Actual submission should use something more specific.

Quoted 6 lines
Quoted 2 lines

Well, the other driver is irq-tango.c that is generic as well. I prefer versioning, as it is unrelated with the actual chip name.

Is there a name, similar to 'tango', for this version of the IP? Something that would spark recognition for someone looking for "the damn driver for this XYZ irqchip I have". If not, irq-tango_v2.c is fine.

If we go with the v2 naming scheme, I vote for irq-tango-v2.c for consistency with the GIC drivers.

Regards.

#5 lore raw

Hi Mason,

Quoted 14 lines · Mason
Quoted 13 lines · Jason Cooper
Quoted 11 lines · Sebastian Frias
Quoted 6 lines · Mason
Quoted 1 line · Sebastian Frias
 .../sigma,smp87xx-irqrouter.txt                    |  69 +++

In the *actual* submission, we can't use a wildcard like smp87xx we'll have to use an actual part number.

Are you sure?
That would hinder genericity.
Actually I wanted to call it "sigma,smp-irqrouter.txt" (or "sigma,smp,irqrouter.txt").

Quoted 5 lines
Quoted 2 lines

sigma,smp-irqrouter.txt should be fine. The devicetree maintainers should yelp if they want something different.

Personally, I don't like "smp" because it's too easy to confuse that for "symmetric multi-processor".

Respectfully, it's not about what any of us 'likes'. If Sigma's marketing people inadvertently chose a bad acronym, then it is what it is. Trying to paper over it just adds unnecessary layers of complexity and confusion. A simple expansion of the acronym in a comment block or in the commit message is all that's needed to remove the ambiguity.

Quoted 2 lines

Come to think of it, I'm not sure the *name* of the file documenting a binding is as important to DT maintainers as the compatible string.

Correct. devicetee compatible strings need to be as specific as possible. In a series of compatible IP blocks, the string should refer to the first version in the series, e.g. sigma,smp8710 for a series of compatible IP blocks like 8710, 8712, 8715, 8724. If an 8751 came along with a different register layout or some other incompatibility, then a new string would be sigma,smp8751. So,

8710 uses "sigma,smp8710"
8712 uses "sigma,smp8710"
8715 uses "sigma,smp8710"
8724 uses "sigma,smp8710"
8751 uses "sigma,smp8751"
8754 uses "sigma,smp8751"

thx,

Jason.

#6 lore raw

Hi Jason,

Quoted 5 lines · Jason Cooper
Quoted 2 lines

Come to think of it, I'm not sure the *name* of the file documenting a binding is as important to DT maintainers as the compatible string.

Correct. devicetee compatible strings need to be as specific as possible.

Specific with respect to what thing? To the HW module they are describing (USB, IRQ controller, etc.) or to the chip the HW module it is embedded into?

Quoted 6 lines

In a series of compatible IP blocks, the string should refer to the first version in the series, e.g. sigma,smp8710 for a series of compatible IP blocks like 8710, 8712, 8715, 8724. If an 8751 came along with a different register layout or some other incompatibility, then a new string would be sigma,smp8751. So,

Quoted 7 lines

8710 uses "sigma,smp8710"
8712 uses "sigma,smp8710"
8715 uses "sigma,smp8710"
8724 uses "sigma,smp8710"
8751 uses "sigma,smp8751"
8754 uses "sigma,smp8751"

But this is not consistent with the strings for generic drivers, like "generic-xhci", etc.

A SoC is composed of several HW modules, some are shared among different manufacturers (i.e.: "generic-xhci"), and some are shared among different product lines of the same manufacturer (i.e.: "sigma,smp,irqrouter").

And the DT for a given chip should describe the collection of HW modules that make up the SoC, regardless of what chip introduced them or what other chip uses it. Why would that be relevant anyway?

By that reasoning, I also think that drivers/net/ethernet/aurora/nb8800.c should have had a string like "aurora,nb8800,sigma" or something, to specify that it is a NB8800 from Aurora integrated in a Sigma platform. That way it can behave as vanilla NB8800 when the string is "aurora,nb8800" and it can adapt its behaviour to Sigma's platform when a different string (like "aurora,nb8800,sigma") is used in the DT.

Later if Sigma modified the nb8800 HW, it could be "aurora,nb8800,sigma-v2". The same way, if later Sigma used a different Aurora HW module, the DT would say "aurora,nb2000,sigma" (to signal that another driver is required)

Instead, drivers/net/ethernet/aurora/nb8800.c has "sigma,smp8642-ethernet" string, which ties it to a particular chip, and I don't see how does that convey version about the module or other relevant information; Plus it is confusing if the same module is then embedded on a SMP8756 chip.

Would you mind explaining how does that contrasts with the logic used by DT naming conventions?

Best regards,

Sebastian

#7 lore raw

Hi Sebastian,

Quoted 10 lines · Sebastian Frias
Quoted 5 lines · Jason Cooper
Quoted 2 lines

Come to think of it, I'm not sure the *name* of the file documenting a binding is as important to DT maintainers as the compatible string.

Correct. devicetee compatible strings need to be as specific as possible.

Specific with respect to what thing? To the HW module they are describing (USB, IRQ controller, etc.) or to the chip the HW module it is embedded into?

The compatible string uniquely identifies an interface between an IP block and the software (the devicetree binding). We use the most specific model number or name we can for that IP block when we create the binding and the compatible string.

If future SoCs come out and the IP block contained within, regardless of identifier, is compatible with the existing binding, then we can reuse it. This is what I was trying to show with my little chart quoted below.

For ethernet and other major blocks it's easy because they have their own model numbers and such. For the smaller blocks, like irqchips, we have to use the model number or unique name of the SoC we first found it in.

Quoted 14 lines
Quoted 6 lines

In a series of compatible IP blocks, the string should refer to the first version in the series, e.g. sigma,smp8710 for a series of compatible IP blocks like 8710, 8712, 8715, 8724. If an 8751 came along with a different register layout or some other incompatibility, then a new string would be sigma,smp8751. So,

Quoted 7 lines

8710 uses "sigma,smp8710"
8712 uses "sigma,smp8710"
8715 uses "sigma,smp8710"
8724 uses "sigma,smp8710"
8751 uses "sigma,smp8751"
8754 uses "sigma,smp8751"

Quoted 2 lines

But this is not consistent with the strings for generic drivers, like "generic-xhci", etc.

True. I've not dealt with xhci/dt at all. My guess would be that there are a lot of xhci chips whose interfaces conform to specification. Those that do can just use "generic-xhci".

Quoted 3 lines

A SoC is composed of several HW modules, some are shared among different manufacturers (i.e.: "generic-xhci"), and some are shared among different product lines of the same manufacturer (i.e.: "sigma,smp,irqrouter").

Yes, that's why it's critical to be specific. We want to reuse drivers where it makes sense. We can if the interface is the same.

Quoted 3 lines

And the DT for a given chip should describe the collection of HW modules that make up the SoC, regardless of what chip introduced them or what other chip uses it. Why would that be relevant anyway?

Because the first time we see a new IP block, we can't predict the future. We don't know where it's going to be reused. We don't know when it's going to be changed, or how. So we mark it as specifically as we can based on the information we have when we first encounter it.

When a new version comes out, we see if the interface is still compatible. If it is, there's nothing to do. If it changed, we see if we can address it by adding a property to the existing binding. Failing that, we create a new compatible string to indicate a new interface.

Quoted 3 lines

By that reasoning, I also think that drivers/net/ethernet/aurora/nb8800.c should have had a string like "aurora,nb8800,sigma" or something, to specify that it is a NB8800 from Aurora integrated in a Sigma platform.

The fact that it is in the Sigma dts file tells this already. Based on the above, did the interface change when adding it to the sigma platform? Can the binding be reused?

Quoted 3 lines

That way it can behave as vanilla NB8800 when the string is "aurora,nb8800" and it can adapt its behaviour to Sigma's platform when a different string (like "aurora,nb8800,sigma") is used in the DT.

I would have to look at the specifics of "adapt its behaviour" in order to determine wether a new compatible is warranted, or maybe just add a property to the binding.

Quoted 3 lines

Later if Sigma modified the nb8800 HW, it could be "aurora,nb8800,sigma-v2". The same way, if later Sigma used a different Aurora HW module, the DT would say "aurora,nb2000,sigma" (to signal that another driver is required)

The compatible string is important, but we try not to overload it. There are many flexible ways we can indicate properties or quirks in the binding.

Quoted 4 lines

Instead, drivers/net/ethernet/aurora/nb8800.c has "sigma,smp8642-ethernet" string, which ties it to a particular chip, and I don't see how does that convey version about the module or other relevant information; Plus it is confusing if the same module is then embedded on a SMP8756 chip.

Sorry, it's just understood that the compatible string means they have the same binding/interface.

Quoted 2 lines

Would you mind explaining how does that contrasts with the logic used by DT naming conventions?

I think you may be looking at DT the wrong way :-P It's not an inventory of components for the end user to look at. It a list of hardware interfaces and how they're attached; for the OS to interpret and use.

hth,

Jason.

#8 lore raw

Hi Jason,

Quoted 10 lines · Jason Cooper

Hi Sebastian,

Quoted 7 lines · Sebastian Frias
Quoted 5 lines · Jason Cooper
Quoted 2 lines

Come to think of it, I'm not sure the *name* of the file documenting a binding is as important to DT maintainers as the compatible string.

Correct. devicetee compatible strings need to be as specific as possible.

Quoted 8 lines
Quoted 3 lines

Specific with respect to what thing? To the HW module they are describing (USB, IRQ controller, etc.) or to the chip the HW module it is embedded into?

The compatible string uniquely identifies an interface between an IP block and the software (the devicetree binding). We use the most specific model number or name we can for that IP block when we create the binding and the compatible string.

Ok, so we agree that the string identifies the HW block itself, and not the chip in which it is embedded into.

Quoted 5 lines

If future SoCs come out and the IP block contained within, regardless of identifier, is compatible with the existing binding, then we can reuse it. This is what I was trying to show with my little chart quoted below.

I understand, is just that the chart was using chip IDs so I was a bit confused.

Quoted 5 lines

For ethernet and other major blocks it's easy because they have their own model numbers and such. For the smaller blocks, like irqchips, we have to use the model number or unique name of the SoC we first found it in.

Ok, but I'm not sure I understand the logic, I thought (and it is my understanding of your previous paragraphs) that the string is supposed to identify the IP block (or HW module) itself.

That seems more generic and flexible than attaching it some "external" property, like the name of the chip the HW module happens to be embedded into.

Normally such "small HW blocks" you talk about, because they are not generic enough, probably require documentation/engineering effort from the SoC manufacturer, so I would guess that the naming can be decided with the SoC them.

Why is there a difference on the naming convention for "smaller blocks, like irqchips" and other blocks (ethernet, USB, UART, etc.) ?

Quoted 6 lines
Quoted 3 lines

A SoC is composed of several HW modules, some are shared among different manufacturers (i.e.: "generic-xhci"), and some are shared among different product lines of the same manufacturer (i.e.: "sigma,smp,irqrouter").

Yes, that's why it's critical to be specific. We want to reuse drivers where it makes sense. We can if the interface is the same.

Ok, so is "sigma,smp,irqrouter" good or not?

Quoted 10 lines
Quoted 4 lines

And the DT for a given chip should describe the collection of HW modules that make up the SoC, regardless of what chip introduced them or what other chip uses it. Why would that be relevant anyway?

Because the first time we see a new IP block, we can't predict the future. We don't know where it's going to be reused. We don't know when it's going to be changed, or how. So we mark it as specifically as we can based on the information we have when we first encounter it.

Quoted 4 lines

When a new version comes out, we see if the interface is still compatible. If it is, there's nothing to do. If it changed, we see if we can address it by adding a property to the existing binding. Failing that, we create a new compatible string to indicate a new interface.

I see. I think this process is ok for when there's no information, like when somebody reverse engineer a HW block of a chip of a given line of chips. In that case I can understand that there's no way to know if previous, similar or future chips use the same block, nor its name.

Yet, I still fail to see the reason to attach the chip ID to what clearly are submodules. Especially when one can assume that such submodules can be shared on different chip IDs.

Quoted 8 lines
Quoted 4 lines

By that reasoning, I also think that drivers/net/ethernet/aurora/nb8800.c should have had a string like "aurora,nb8800,sigma" or something, to specify that it is a NB8800 from Aurora integrated in a Sigma platform.

The fact that it is in the Sigma dts file tells this already. Based on the above, did the interface change when adding it to the sigma platform? Can the binding be reused?

I think it did not change.
Actually, I think only Sigma uses it, as the driver only has Sigma-specific initialisations for two Sigma-specific strings.

Quoted 8 lines
Quoted 4 lines

That way it can behave as vanilla NB8800 when the string is "aurora,nb8800" and it can adapt its behaviour to Sigma's platform when a different string (like "aurora,nb8800,sigma") is used in the DT.

I would have to look at the specifics of "adapt its behaviour" in order to determine wether a new compatible is warranted, or maybe just add a property to the binding.

Ok.

Quoted 8 lines
Quoted 4 lines

Later if Sigma modified the nb8800 HW, it could be "aurora,nb8800,sigma-v2". The same way, if later Sigma used a different Aurora HW module, the DT would say "aurora,nb2000,sigma" (to signal that another driver is required)

The compatible string is important, but we try not to overload it. There are many flexible ways we can indicate properties or quirks in the binding.

Ok.

Quoted 8 lines
Quoted 5 lines

Instead, drivers/net/ethernet/aurora/nb8800.c has "sigma,smp8642-ethernet" string, which ties it to a particular chip, and I don't see how does that convey version about the module or other relevant information; Plus it is confusing if the same module is then embedded on a SMP8756 chip.

Sorry, it's just understood that the compatible string means they have the same binding/interface.

Ok, so same binding/interface = same module, so we could as well name the compatible string after the module's name, and that, regardless of which chip it is embedded into, right? Obviously some prefix can be used, and that's why I had proposed "sigma,smp".

Quoted 8 lines
Quoted 3 lines

Would you mind explaining how does that contrasts with the logic used by DT naming conventions?

I think you may be looking at DT the wrong way :-P It's not an inventory of components for the end user to look at. It a list of hardware interfaces and how they're attached; for the OS to interpret and use.

Exactly, and such hardware interfaces (usually HW IP blocks) are usually shared by a number of chips, sometimes from different companies, sometimes from the same company.

That is why I find strange to use a given chip ID to describe some HW IP submodule.

Best regards,

Sebastian

#9 lore raw

Hey Sebastian,

Quoted 13 lines · Sebastian Frias
Quoted 12 lines · Jason Cooper
Quoted 10 lines · Sebastian Frias
Quoted 5 lines · Jason Cooper
Quoted 2 lines

Come to think of it, I'm not sure the *name* of the file documenting a binding is as important to DT maintainers as the compatible string.

Correct. devicetee compatible strings need to be as specific as possible.

Specific with respect to what thing? To the HW module they are describing (USB, IRQ controller, etc.) or to the chip the HW module it is embedded into?

Quoted 7 lines
Quoted 4 lines

The compatible string uniquely identifies an interface between an IP block and the software (the devicetree binding). We use the most specific model number or name we can for that IP block when we create the binding and the compatible string.

Ok, so we agree that the string identifies the HW block itself, and not the chip in which it is embedded into.

If *possible*. When we converted kirkwood and the other legacy Marvell ARMv5 SoCs to devicetree, the most specific way we could identify the irq controller was 'marvell,orion-intc'. Orion being the name of the first platform it was seen on.

When that was chosen, mv68xx0, orion5x, kirkwood, and I think dove were already deployed to market. So we had a *lot* more latent information to look at.

Now that SoC manufacturers are doing a much better job mainlining code, the situation is reversed. There's little information on what is actually delivered to the market (because code is getting posted *prior* to SoC deployment), but we have better access to specifications and software devs.

So, if we have access to specific IP block identifiers, we'll use them. If we don't, we're not going to let that hold up the train waiting for the 'perfect' binding.

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

A SoC is composed of several HW modules, some are shared among different manufacturers (i.e.: "generic-xhci"), and some are shared among different product lines of the same manufacturer (i.e.: "sigma,smp,irqrouter").

Yes, that's why it's critical to be specific. We want to reuse drivers where it makes sense. We can if the interface is the same.

Ok, so is "sigma,smp,irqrouter" good or not?

If you have a unique identifier for the irqchip, use it. If not, the convention is to use the identifier of the SoC.

thx,

Jason.

#10 lore raw
In reply to Jason Cooper

Hi Jason,

Quoted 34 lines · Jason Cooper

Hey Sebastian, Mason,

* Please fix mailer to wrap text at a sane length. I've re-wrapped and trimmed.

Quoted 1 line · Sebastian Frias

On 07/04/2016 02:11 PM, Mason wrote:

...

Quoted 8 lines
Quoted 4 lines
Quoted 1 line
 .../sigma,smp87xx-irqrouter.txt                    |  69 +++

In the *actual* submission, we can't use a wildcard like smp87xx we'll have to use an actual part number.

Are you sure?
That would hinder genericity.
Actually I wanted to call it "sigma,smp-irqrouter.txt" (or "sigma,smp,irqrouter.txt").

sigma,smp-irqrouter.txt should be fine. The devicetree maintainers should yelp if they want something different.

Quoted 14 lines

To me there's no need to link the compatible string of a given HW module with that of the chip name the module it is embedded into. For example, the generic USB3 driver is "generic-xhci". While this module is not generic to be embedded in chips from different manufacturers, it is supposed to be generic within Sigma, and multiple Sigma chips (with potentially different denominations) can use it.

Quoted 6 lines
Quoted 3 lines
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-tango_v2.c                     | 594 +++++++++++++++++++++

Likewise, I don't like the "_v2" suffix, it's too generic. Actual submission should use something more specific.

Quoted 7 lines
Quoted 2 lines

Well, the other driver is irq-tango.c that is generic as well. I prefer versioning, as it is unrelated with the actual chip name.

Is there a name, similar to 'tango', for this version of the IP? Something that would spark recognition for someone looking for "the damn driver for this XYZ irqchip I have". If not, irq-tango_v2.c is fine.

Thanks for your comments.
So, aside from some naming issues, do you think the driver is ok? Indeed, I'm not sure about the following:

1) I had to unroll irq_of_parse_and_map() in order to get the HW IRQ declared in the device tree so that I can associate it with a given domain. Is there another way?

2) I'm not sure about the DT specification, in particular, the use of child nodes to declare different domains, but it works. Advise and/or hints regarding this are welcome.

3) I'm calling this an irq router to somehow highlight the fact that it is not a simple interrupt controller. Indeed it does not latch the IRQ lines by itself, and does not supports edge detection.
Does anybody else has a better idea for the name?

4) Do I have to do something more to handle the affinity stuff?

5) checkpatch.pl reports warnings, etc. but I guess it's ok for now since it is a RFC

6) Do we need a lock in the cascade_irq callback set with irq_set_chained_handler_and_data() ?

Thanks in advance.
Best regards,

Sebastian

#11 lore raw

Hey Sebastian,

Quoted 33 lines · Sebastian Frias
Quoted 32 lines · Jason Cooper
Quoted 1 line · Sebastian Frias

On 07/04/2016 02:11 PM, Mason wrote:

...

Quoted 8 lines
Quoted 4 lines
Quoted 1 line
 .../sigma,smp87xx-irqrouter.txt                    |  69 +++

In the *actual* submission, we can't use a wildcard like smp87xx we'll have to use an actual part number.

Are you sure?
That would hinder genericity.
Actually I wanted to call it "sigma,smp-irqrouter.txt" (or "sigma,smp,irqrouter.txt").

sigma,smp-irqrouter.txt should be fine. The devicetree maintainers should yelp if they want something different.

Quoted 16 lines

To me there's no need to link the compatible string of a given HW module with that of the chip name the module it is embedded into. For example, the generic USB3 driver is "generic-xhci". While this module is not generic to be embedded in chips from different manufacturers, it is supposed to be generic within Sigma, and multiple Sigma chips (with potentially different denominations) can use it.

Quoted 6 lines
Quoted 3 lines
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-tango_v2.c                     | 594 +++++++++++++++++++++

Likewise, I don't like the "_v2" suffix, it's too generic. Actual submission should use something more specific.

Well, the other driver is irq-tango.c that is generic as well. I prefer versioning, as it is unrelated with the actual chip name.

Quoted 7 lines
Quoted 4 lines

Is there a name, similar to 'tango', for this version of the IP? Something that would spark recognition for someone looking for "the damn driver for this XYZ irqchip I have". If not, irq-tango_v2.c is fine.

Thanks for your comments.
So, aside from some naming issues, do you think the driver is ok?

Well, it's going to be few days before I can really dig in to this. Until then, what I can say I see is that it looks like you're using devicetree to tell Linux how to lay out the irq domains. That's not right :(

The devicetree should *only* describe the hardware. Would *BSD be able to use the description in the dtb effectively?

iiuc, I think irq-crossbar.c may be a similar enough in task to give you an idea or two.

Beyond that, as you mention, there are a bunch of style issues, unneeded macros, etc.

thx,

Jason.

#12 lore raw

Hi Jason,

Quoted 8 lines · Jason Cooper
Quoted 3 lines

Thanks for your comments.
So, aside from some naming issues, do you think the driver is ok?

Well, it's going to be few days before I can really dig in to this. Until then, what I can say I see is that it looks like you're using devicetree to tell Linux how to lay out the irq domains. That's not right :(

Ok, so that replies my questions 1 and 2, thanks.

Quoted 6 lines

The devicetree should *only* describe the hardware. Would *BSD be able to use the description in the dtb effectively?

iiuc, I think irq-crossbar.c may be a similar enough in task to give you an idea or two.

I already did something like that, you can see it here:

https://marc.info/?l=linux-kernel&m=146592235919308&w=2

the problem with that code is that it cannot handle more than 24 IRQs (the number of outputs of the router), because they are not being shared.

Maybe I need a sort of hybrid approach by reintroducing part of "irq-crossbar.c" code to replace the irq domain layout that is currently being done using DT properties ?

However, I have not seen any examples of how to describe, using the DT, an association between a device HW irq, and the GIC hwirq where it goes to, nor how to express in the DT that multiple devices should share a given GIC hwirq.
Basically, when a device requests the IRQ specified in its DT, I need:
- to know which GIC hwirq line should I route it to (or the GIC to tell me which one it expects)
- two devices should be able to request to share the same GIC hwirq

If you take a look at the DT for drivers/irqchip/irq-tango.c (arch/arm/boot/dts/tango4-common.dtsi) you will see that 3 domains are created using DT nodes. The difference being that in the irq-tango.c case the routing is fixed w.r.t the GIC.

Best regards,

Sebastian

#13 lore raw
Quoted 32 lines · Sebastian Frias

Hi Jason,

Quoted 8 lines · Jason Cooper
Quoted 3 lines

Thanks for your comments.
So, aside from some naming issues, do you think the driver is ok?

Well, it's going to be few days before I can really dig in to this. Until then, what I can say I see is that it looks like you're using devicetree to tell Linux how to lay out the irq domains. That's not right :(

Ok, so that replies my questions 1 and 2, thanks.

Quoted 6 lines

The devicetree should *only* describe the hardware. Would *BSD be able to use the description in the dtb effectively?

iiuc, I think irq-crossbar.c may be a similar enough in task to give you an idea or two.

I already did something like that, you can see it here:

https://marc.info/?l=linux-kernel&m=146592235919308&w=2

the problem with that code is that it cannot handle more than 24 IRQs (the number of outputs of the router), because they are not being shared.

Maybe I need a sort of hybrid approach by reintroducing part of "irq-crossbar.c" code to replace the irq domain layout that is currently being done using DT properties ?

Quoted 7 lines

However, I have not seen any examples of how to describe, using the DT, an association between a device HW irq, and the GIC hwirq where it goes to, nor how to express in the DT that multiple devices should share a given GIC hwirq.
Basically, when a device requests the IRQ specified in its DT, I need:
- to know which GIC hwirq line should I route it to (or the GIC to tell me which one it expects)

You really don't need to describe this. The configuration that is applied to your router in entirely under software control, and none of that should appear in the DT. You could decide to mux all the interrupts to a single one, or decide that the 23 first interrupts you discover get their own private line to the GIC and that everything else is muxed.

So given that this is completely defined by software, it has no place in DT. There may not be an example of such an interrupt controller in the tree, but this doesn't look too hard to implement.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#14 lore raw

Hi Marc,

Quoted 19 lines · Marc Zyngier
Quoted 11 lines

I already did something like that, you can see it here:

https://marc.info/?l=linux-kernel&m=146592235919308&w=2

the problem with that code is that it cannot handle more than 24 IRQs (the number of outputs of the router), because they are not being shared.

Maybe I need a sort of hybrid approach by reintroducing part of "irq-crossbar.c" code to replace the irq domain layout that is currently being done using DT properties ?

Quoted 7 lines

However, I have not seen any examples of how to describe, using the DT, an association between a device HW irq, and the GIC hwirq where it goes to, nor how to express in the DT that multiple devices should share a given GIC hwirq.
Basically, when a device requests the IRQ specified in its DT, I need:
- to know which GIC hwirq line should I route it to (or the GIC to tell me which one it expects)

Quoted 2 lines

You really don't need to describe this. The configuration that is applied to your router in entirely under software control,

With "entirely under software control" do you mean this driver's code?

Quoted 7 lines

and none of
that should appear in the DT. You could decide to mux all the interrupts to a single one, or decide that the 23 first interrupts you discover get their own private line to the GIC and that everything else is muxed.

So given that this is completely defined by software, it has no place in DT.

I think I'm missing something, what is the difference between the domains described by nodes in the DT for irq-tango.c (arch/arm/boot/dts/tango4-common.dtsi) and the DT from my RFC?

Alternatively, the previous DT (arch/arm/boot/dts/tango4-common.dtsi) allowed IRQ sharing to be specified in the DT, is that wrong?

Quoted 2 lines

There may not be an example of such an interrupt controller in the tree, but this doesn't look too hard to implement.

Well, if you the domains should not be described in the DT and that they should be somehow hardcoded into the drivers' code, it should not be hard indeed.

Best regards,

Sebastian

#15 lore raw
Quoted 22 lines · Sebastian Frias

Hi Marc,

Quoted 19 lines · Marc Zyngier
Quoted 18 lines

I already did something like that, you can see it here:

https://marc.info/?l=linux-kernel&m=146592235919308&w=2

the problem with that code is that it cannot handle more than 24 IRQs (the number of outputs of the router), because they are not being shared.

Maybe I need a sort of hybrid approach by reintroducing part of "irq-crossbar.c" code to replace the irq domain layout that is currently being done using DT properties ?

However, I have not seen any examples of how to describe, using the DT, an association between a device HW irq, and the GIC hwirq where it goes to, nor how to express in the DT that multiple devices should share a given GIC hwirq.
Basically, when a device requests the IRQ specified in its DT, I need:
- to know which GIC hwirq line should I route it to (or the GIC to tell me which one it expects)

Quoted 4 lines
Quoted 2 lines

You really don't need to describe this. The configuration that is applied to your router in entirely under software control,

With "entirely under software control" do you mean this driver's code?

Yes.

Quoted 6 lines
Quoted 6 lines

and none of
that should appear in the DT. You could decide to mux all the interrupts to a single one, or decide that the 23 first interrupts you discover get their own private line to the GIC and that everything else is muxed.

Quoted 6 lines
Quoted 2 lines

So given that this is completely defined by software, it has no place in DT.

I think I'm missing something, what is the difference between the domains described by nodes in the DT for irq-tango.c (arch/arm/boot/dts/tango4-common.dtsi) and the DT from my RFC?

The fundamental difference is that with your new fancy controller, you can decide what is going where, while the previous one is completely set in stone (the output line is a direct function of the input line).

Quoted 9 lines

Alternatively, the previous DT (arch/arm/boot/dts/tango4-common.dtsi) allowed IRQ sharing to be specified in the DT, is that wrong?

Quoted 2 lines

There may not be an example of such an interrupt controller in the tree, but this doesn't look too hard to implement.

Well, if you the domains should not be described in the DT and that they should be somehow hardcoded into the drivers' code, it should not be hard indeed.

Hardcoded? No way. You simply implement a route allocator in your driver, assigning them as needed. And yes, if you have more than 24 interrupts, they get muxed.

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#16 lore raw
Quoted 7 lines · Marc Zyngier
Quoted 2 lines · Sebastian Frias

Well, if you the domains should not be described in the DT and that they should be somehow hardcoded into the drivers' code, it should not be hard indeed.

Hardcoded? No way. You simply implement a route allocator in your driver, assigning them as needed. And yes, if you have more than 24 interrupts, they get muxed.

There is one caveat though. Under some circumstances (think RT) you want to configure which interrupts get muxed and which not. We really should have that option, but yes for anything which has less than 24 autorouting is the way to go.

Thanks,

tglx

#17 lore raw
Quoted 5 lines · Thomas Gleixner
Quoted 4 lines · Marc Zyngier
Quoted 2 lines · Sebastian Frias

Well, if you the domains should not be described in the DT and that they should be somehow hardcoded into the drivers' code, it should not be hard indeed.

Quoted 8 lines
Quoted 3 lines

Hardcoded? No way. You simply implement a route allocator in your driver, assigning them as needed. And yes, if you have more than 24 interrupts, they get muxed.

There is one caveat though. Under some circumstances (think RT) you want to configure which interrupts get muxed and which not. We really should have that option, but yes for anything which has less than 24 autorouting is the way to go.

Good point. I can see two possibilities for that:

- either we describe this DT with some form of hint, indicating what are the inputs that can be muxed to a single output. Easy, but the DT guys are going to throw rocks at me for being Linux-specific.

- or we have a way to express QoS in the irq subsystem, and a driver can request an interrupt with a "make it fast" flag. Of course, everybody and his dog are going to ask for it, and we're back to square one.

Do we have a way to detect which interrupt is more likely to be sensitive to muxing? My hunch is that if it is requested with IRQF_SHARED, then it is effectively muxable. Thoughts?

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#18 lore raw
Quoted 11 lines · Marc Zyngier
Quoted 9 lines · Thomas Gleixner
Quoted 3 lines · Marc Zyngier

Hardcoded? No way. You simply implement a route allocator in your driver, assigning them as needed. And yes, if you have more than 24 interrupts, they get muxed.

There is one caveat though. Under some circumstances (think RT) you want to configure which interrupts get muxed and which not. We really should have that option, but yes for anything which has less than 24 autorouting is the way to go.

Quoted 5 lines

Good point. I can see two possibilities for that:

- either we describe this DT with some form of hint, indicating what are the inputs that can be muxed to a single output. Easy, but the DT guys are going to throw rocks at me for being Linux-specific.

That's not necessarily Linux specific. The problem arises with any other OS as well.

Quoted 3 lines

- or we have a way to express QoS in the irq subsystem, and a driver can request an interrupt with a "make it fast" flag. Of course, everybody and his dog are going to ask for it, and we're back to square one.

That and the driver does not know about the particular application scenario/system configuration.

Quoted 3 lines

Do we have a way to detect which interrupt is more likely to be sensitive to muxing? My hunch is that if it is requested with IRQF_SHARED, then it is effectively muxable. Thoughts?

That's too late. request_irq happens _after_ the interrupt is set up and the routing established.

Thanks,

tglx

#19 lore raw

Hi,

Quoted 28 lines · Thomas Gleixner
Quoted 11 lines · Marc Zyngier
Quoted 9 lines · Thomas Gleixner
Quoted 3 lines · Marc Zyngier

Hardcoded? No way. You simply implement a route allocator in your driver, assigning them as needed. And yes, if you have more than 24 interrupts, they get muxed.

There is one caveat though. Under some circumstances (think RT) you want to configure which interrupts get muxed and which not. We really should have that option, but yes for anything which has less than 24 autorouting is the way to go.

Quoted 5 lines

Good point. I can see two possibilities for that:

- either we describe this DT with some form of hint, indicating what are the inputs that can be muxed to a single output. Easy, but the DT guys are going to throw rocks at me for being Linux-specific.

That's not necessarily Linux specific. The problem arises with any other OS as well.

Quoted 3 lines

- or we have a way to express QoS in the irq subsystem, and a driver can request an interrupt with a "make it fast" flag. Of course, everybody and his dog are going to ask for it, and we're back to square one.

That and the driver does not know about the particular application scenario/system configuration.

Quoted 7 lines
Quoted 3 lines

Do we have a way to detect which interrupt is more likely to be sensitive to muxing? My hunch is that if it is requested with IRQF_SHARED, then it is effectively muxable. Thoughts?

That's too late. request_irq happens _after_ the interrupt is set up and the routing established.

What about using 3 values for the interrupt description like the GIC does? When connecting to the GIC we say "interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;" If devices using this driver (the one from the RFC) requested the interrupt like:
"interrupts = <0 38 IRQ_TYPE_LEVEL_HIGH>;"
"interrupts = <2 27 IRQ_TYPE_LEVEL_HIGH>;"
etc.
with the first field being the "group", then the driver could create a domain for the device's IRQ (or associate it to an existing one if it has already been created). It would thus serve as a hint on how to create domains and how to share IRQs into the same line (domain).

I guess I can get such information from the .translate and .alloc callbacks from a newly created domain hierarchy attached to the GIC, right?

What do you think?

Best regards,

Sebastian

#20 lore raw
Quoted 50 lines · Sebastian Frias

Hi,

Quoted 28 lines · Thomas Gleixner
Quoted 11 lines · Marc Zyngier
Quoted 9 lines · Thomas Gleixner
Quoted 3 lines · Marc Zyngier

Hardcoded? No way. You simply implement a route allocator in your driver, assigning them as needed. And yes, if you have more than 24 interrupts, they get muxed.

There is one caveat though. Under some circumstances (think RT) you want to configure which interrupts get muxed and which not. We really should have that option, but yes for anything which has less than 24 autorouting is the way to go.

Quoted 5 lines

Good point. I can see two possibilities for that:

- either we describe this DT with some form of hint, indicating what are the inputs that can be muxed to a single output. Easy, but the DT guys are going to throw rocks at me for being Linux-specific.

That's not necessarily Linux specific. The problem arises with any other OS as well.

Quoted 3 lines

- or we have a way to express QoS in the irq subsystem, and a driver can request an interrupt with a "make it fast" flag. Of course, everybody and his dog are going to ask for it, and we're back to square one.

That and the driver does not know about the particular application scenario/system configuration.

Quoted 7 lines
Quoted 3 lines

Do we have a way to detect which interrupt is more likely to be sensitive to muxing? My hunch is that if it is requested with IRQF_SHARED, then it is effectively muxable. Thoughts?

That's too late. request_irq happens _after_ the interrupt is set up and the routing established.

What about using 3 values for the interrupt description like the GIC does? When connecting to the GIC we say "interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;" If devices using this driver (the one from the RFC) requested the interrupt like:
"interrupts = <0 38 IRQ_TYPE_LEVEL_HIGH>;"
"interrupts = <2 27 IRQ_TYPE_LEVEL_HIGH>;"
etc.
with the first field being the "group", then the driver could create a domain for the device's IRQ (or associate it to an existing one if it has already been created). It would thus serve as a hint on how to create domains and how to share IRQs into the same line (domain).

Quoted 2 lines

I guess I can get such information from the .translate and .alloc callbacks from a newly created domain hierarchy attached to the GIC, right?

This wouldn't work. You need to instantiate the domains long before you've parsed a single interrupt specifier, otherwise you don't know where to allocate it from.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#21 lore raw
In reply to Thomas Gleixner
Quoted 12 lines · Thomas Gleixner
Quoted 11 lines · Marc Zyngier
Quoted 9 lines · Thomas Gleixner
Quoted 3 lines · Marc Zyngier

Hardcoded? No way. You simply implement a route allocator in your driver, assigning them as needed. And yes, if you have more than 24 interrupts, they get muxed.

There is one caveat though. Under some circumstances (think RT) you want to configure which interrupts get muxed and which not. We really should have that option, but yes for anything which has less than 24 autorouting is the way to go.

Quoted 8 lines
Quoted 5 lines

Good point. I can see two possibilities for that:

- either we describe this DT with some form of hint, indicating what are the inputs that can be muxed to a single output. Easy, but the DT guys are going to throw rocks at me for being Linux-specific.

That's not necessarily Linux specific. The problem arises with any other OS as well.

I could see a property

	irq,no-mux = <3 7 13 19 23 ...>;

Or "irq,fastpath". It's describing an optimal configuration of the system. $driver for $OS can route those first individually. The others would be eligible for muxing.

thx,

Jason.

#22 lore raw
In reply to Marc Zyngier

Hi Marc,

Quoted 6 lines · Marc Zyngier
Quoted 4 lines
Quoted 2 lines

You really don't need to describe this. The configuration that is applied to your router in entirely under software control,

With "entirely under software control" do you mean this driver's code?

Yes.

Ok.

Quoted 10 lines
Quoted 10 lines
Quoted 9 lines

and none of
that should appear in the DT. You could decide to mux all the interrupts to a single one, or decide that the 23 first interrupts you discover get their own private line to the GIC and that everything else is muxed.

So given that this is completely defined by software, it has no place in DT.

Quoted 7 lines
Quoted 3 lines

I think I'm missing something, what is the difference between the domains described by nodes in the DT for irq-tango.c (arch/arm/boot/dts/tango4-common.dtsi) and the DT from my RFC?

The fundamental difference is that with your new fancy controller, you can decide what is going where, while the previous one is completely set in stone (the output line is a direct function of the input line).

I think that's where part the misunderstanding comes from.
IMHO the output line is not a direct function of the input line. Any of the 64 IRQ lines entering the "old controller" (irq-tango.c) can be routed to any of its 3 outputs.
The only thing fixed is which GIC input is connected to those 3 outputs, ie:
GIC inputs 2, 3 and 4.

In the the "new controller" (irq-tango_v2.c, this RFC), any of 128 IRQ lines can be routed to any of 24 outputs, connected to GIC inputs 0...23.

In a nutshell:
- "old controller": routes [0...N] => GIC inputs [2...4]
- "new controller": routes [0...M] => GIC inputs [0...23]

So, when we think about it, if the "new DT" specified 24 domains, it would be equivalent of the "old DT" with 3 domains, right?

That's why it seemed more or less natural to keep describing the domains in the DT, the main reason for that being that it allowed the user to specify the IRQ sharing in the DT, and this is precisely the key point of this.

So, putting aside routing considerations and the discussion above, I think a simpler question is: if the domains should not be described in the DT, how can we define the IRQ sharing in the DT?

Best regards,

Sebastian

#23 lore raw
Quoted 4 lines · Sebastian Frias
Quoted 4 lines
Quoted 3 lines

I think I'm missing something, what is the difference between the domains described by nodes in the DT for irq-tango.c (arch/arm/boot/dts/tango4-common.dtsi) and the DT from my RFC?

Quoted 8 lines
Quoted 3 lines

The fundamental difference is that with your new fancy controller, you can decide what is going where, while the previous one is completely set in stone (the output line is a direct function of the input line).

I think that's where part the misunderstanding comes from. IMHO the output line is not a direct function of the input line. Any of the 64 IRQ lines entering the "old controller" (irq-tango.c) can be routed to any of its 3 outputs.

Then the current DT binding isn't properly describing the HW.

Quoted 6 lines

The only thing fixed is which GIC input is connected to those 3 outputs, ie:
GIC inputs 2, 3 and 4.

In the the "new controller" (irq-tango_v2.c, this RFC), any of 128 IRQ lines can be routed to any of 24 outputs, connected to GIC inputs 0...23.

Quoted 6 lines

In a nutshell:
- "old controller": routes [0...N] => GIC inputs [2...4]
- "new controller": routes [0...M] => GIC inputs [0...23]

So, when we think about it, if the "new DT" specified 24 domains, it would be equivalent of the "old DT" with 3 domains, right?

Indeed, but I consider the "old" binding to be rather misleading. It should have been described as a router too, rather than hardcoding things in DT. Granted, it doesn't matter much when you only have 3 possible output lines. But with 24 outputs, that becomes much more relevant.

Quoted 8 lines

That's why it seemed more or less natural to keep describing the domains in the DT, the main reason for that being that it allowed the user to specify the IRQ sharing in the DT, and this is precisely the key point of this.

So, putting aside routing considerations and the discussion above, I think a simpler question is: if the domains should not be described in the DT, how can we define the IRQ sharing in the DT?

You could have a set of sub-nodes saying something like this:

	mux-hint0 {
		inputs = <1 45 127>;
	}

	mux-hint1 {
		inputs = <2 33>;
	}

(or maybe you can have that as direct properties, but you get the idea). Here, you have two output pins dedicated to muxed interrupts (assuming they are all level interrupts), and the last 22 can be freely allocated as direct routes.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#24 lore raw

Hi Marc,

Quoted 6 lines · Marc Zyngier
Quoted 4 lines

I think that's where part the misunderstanding comes from. IMHO the output line is not a direct function of the input line. Any of the 64 IRQ lines entering the "old controller" (irq-tango.c) can be routed to any of its 3 outputs.

Then the current DT binding isn't properly describing the HW.

Ok, thanks, so it is not a good example then.

Quoted 11 lines
Quoted 6 lines

In a nutshell:
- "old controller": routes [0...N] => GIC inputs [2...4]
- "new controller": routes [0...M] => GIC inputs [0...23]

So, when we think about it, if the "new DT" specified 24 domains, it would be equivalent of the "old DT" with 3 domains, right?

Indeed, but I consider the "old" binding to be rather misleading. It should have been described as a router too, rather than hardcoding things in DT. Granted, it doesn't matter much when you only have 3 possible output lines. But with 24 outputs, that becomes much more relevant.

I see.

Quoted 14 lines
Quoted 3 lines

So, putting aside routing considerations and the discussion above, I think a simpler question is: if the domains should not be described in the DT, how can we define the IRQ sharing in the DT?

You could have a set of sub-nodes saying something like this:

	mux-hint0 {
		inputs = <1 45 127>;
	}

	mux-hint1 {
		inputs = <2 33>;
	}
Quoted 5 lines

(or maybe you can have that as direct properties, but you get the idea). Here, you have two output pins dedicated to muxed interrupts (assuming they are all level interrupts), and the last 22 can be freely allocated as direct routes.

Ok, I'll try to do that.
So, aside from the DT issues (that is, that it is describing domains), would it be ok to create a domain for each of the outputs?

Because I was looking at:
- Documentation/devicetree/bindings/interrupt-controller/samsung,exynos4210-combiner.txt
- drivers/irqchip/exynos-combiner.c
- arch/arm/boot/dts/exynos4210.dtsi

and what I see is that the DT basically list all outputs [0...15] connected to the parent interrupt controller, although the driver does not creates separate domains, just one. Then it attaches a chained handler for each of the outputs. On the .map callback it attaches a irqchip to the domain.

There is also:
- Documentation/devicetree/bindings/arm/omap/crossbar.txt
- drivers/irqchip/irq-crossbar.c
- arch/arm/boot/dts/dra7.dtsi

This one creates a domain hierarchy linked to the parent domain and uses irq_domain_alloc_irqs_parent() and irq_domain_set_hwirq_and_chip() to attach a irqchip to the domain on the .alloc callback.

Both use a single domain, as opposed to irq-tango.c which creates 3 domains. Right now irq-tango_v2.c is supposed to create one domain per output (if so the DT says)
Are there guidelines regarding that?

Thanks in advance.
Best regards,

Sebastian

#25 lore raw
Quoted 65 lines · Sebastian Frias

Hi Marc,

Quoted 6 lines · Marc Zyngier
Quoted 4 lines

I think that's where part the misunderstanding comes from. IMHO the output line is not a direct function of the input line. Any of the 64 IRQ lines entering the "old controller" (irq-tango.c) can be routed to any of its 3 outputs.

Then the current DT binding isn't properly describing the HW.

Ok, thanks, so it is not a good example then.

Quoted 11 lines
Quoted 6 lines

In a nutshell:
- "old controller": routes [0...N] => GIC inputs [2...4]
- "new controller": routes [0...M] => GIC inputs [0...23]

So, when we think about it, if the "new DT" specified 24 domains, it would be equivalent of the "old DT" with 3 domains, right?

Indeed, but I consider the "old" binding to be rather misleading. It should have been described as a router too, rather than hardcoding things in DT. Granted, it doesn't matter much when you only have 3 possible output lines. But with 24 outputs, that becomes much more relevant.

I see.

Quoted 14 lines
Quoted 3 lines

So, putting aside routing considerations and the discussion above, I think a simpler question is: if the domains should not be described in the DT, how can we define the IRQ sharing in the DT?

You could have a set of sub-nodes saying something like this:

	mux-hint0 {
		inputs = <1 45 127>;
	}

	mux-hint1 {
		inputs = <2 33>;
	}
Quoted 5 lines

(or maybe you can have that as direct properties, but you get the idea). Here, you have two output pins dedicated to muxed interrupts (assuming they are all level interrupts), and the last 22 can be freely allocated as direct routes.

Ok, I'll try to do that.
So, aside from the DT issues (that is, that it is describing domains), would it be ok to create a domain for each of the outputs?

Because I was looking at:
- Documentation/devicetree/bindings/interrupt-controller/samsung,exynos4210-combiner.txt
- drivers/irqchip/exynos-combiner.c
- arch/arm/boot/dts/exynos4210.dtsi

and what I see is that the DT basically list all outputs [0...15] connected to the parent interrupt controller, although the driver does not creates separate domains, just one. Then it attaches a chained handler for each of the outputs. On the .map callback it attaches a irqchip to the domain.

There is also:
- Documentation/devicetree/bindings/arm/omap/crossbar.txt
- drivers/irqchip/irq-crossbar.c
- arch/arm/boot/dts/dra7.dtsi

Quoted 8 lines

This one creates a domain hierarchy linked to the parent domain and uses irq_domain_alloc_irqs_parent() and irq_domain_set_hwirq_and_chip() to attach a irqchip to the domain on the .alloc callback.

Both use a single domain, as opposed to irq-tango.c which creates 3 domains. Right now irq-tango_v2.c is supposed to create one domain per output (if so the DT says)
Are there guidelines regarding that?

The sensible thing would be to have one domain per output that muxes inputs, and a hierarchical domain for all the other inputs (which are mapped 1:1 with their output).

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#26 lore raw

RFC PATCH v2 1/1 irqchip: add support for SMP irq router

This adds support for a second-gen irq router/controller present on some Sigma Designs chips.

---

This is RFC v2 attempts to address the comments given on the previous RFC:
- domains used to be created by the DT, now they are created internally by the driver:
https://marc.info/?l=linux-kernel&m=146773883324507&w=2
- IRQ sharing (which does not seems to be handled by current DT spec,
https://marc.info/?l=linux-kernel&m=146779759405950&w=2) is implemented as:
- explicit grouping: https://marc.info/?l=linux-kernel&m=146781302410442&w=2
- implicit grouping: https://marc.info/?l=linux-kernel&m=146780217707395&w=2

However, I still have a few doubts:
1) I have implemented two ways of declaring the IRQ sharing, implicit and explicit IRQ grouping, see:
Documentation/devicetree/bindings/interrupt-controller/sigma,smp,irqrouter.txt for more information.

Since it is still not clear how this is going to be used, I prefer to keep both available for the moment.

2) In order to get a virq mapping for the domains associated with the outputs (the outputs connected to the GIC) I request a sort of "Fake HW IRQ" See irq-tango_v4.c:1400

	/* To request a virq we need a HW IRQ, use a "Fake HW IRQ" */
	hwirq      = index + irqrouter->input_count + irqrouter->swirq_count;

This feels a bit like a hack, so suggestions are welcome.

3) The file is called 'irq-tango_v4.c' but I think it should match the compatible string, so I was thinking of renaming:
irq-tango_v4.c => irq-sigma_smp_irqrouter.c
irq-tango_v4.h => irq-sigma_smp_irqrouter.h

What do you think?

4) Do I have to do something more to handle the affinity stuff?

5) checkpatch.pl reports a few warnings:

- WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? I have not changed the file because I would like to be settled on the naming first (see point 2 above)
- WARNING: quoted string split across lines
I think it is not an issue
- WARNING: line over 80 characters
This is for two big macros, I think it is not an issue

6) More of a theoretical question:
I have to #include <dt-bindings/interrupt-controller/irq-tango_v4.h> from code that is not in the Linux tree. That's fine for now, but if in the future there are other irq controllers and another header is required, how can the code know which header to #include ?
Are we supposed to #include all of them, and then somehow detect which module is actually active and act accordingly? If so, can we detect which module matched and probed correctly to know which controller version we need to talk to?

Please feel free to comment and suggest improvements.

---
 .../interrupt-controller/sigma,smp,irqrouter.txt   |  135 ++
 drivers/irqchip/Makefile                           |    1 +
 drivers/irqchip/irq-tango_v4.c                     | 1729 ++++++++++++++++++++
 .../interrupt-controller/irq-tango_v4.h            |   39 +
 4 files changed, 1904 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sigma,smp,irqrouter.txt
 create mode 100644 drivers/irqchip/irq-tango_v4.c
 create mode 100644 include/dt-bindings/interrupt-controller/irq-tango_v4.h
Documentation/devicetree/bindings/interrupt-controller/sigma,smp,irqrouter.txt new file +135 -0
new file mode 100644
index 0000000..ff7c4d5
@@ -0,0 +1,135 @@
+* Sigma Designs Interrupt Router
+
+This module can route X IRQ inputs and Y SW IRQ inputs into Z IRQ outputs,
+with X+Y>Z.
+For instance X=128, Y=16, Z=24.
+
+Note however that the HW does not latch the IRQ lines, so devices
+connecting to the router are expected to latch their IRQ line by themselves.
+
+SW IRQs can be used by firmware running on different parts of the SoC to
+communicate with the CPU.
+They can be registered by specific drivers, and any entity capable of writing
+to the Interrupt Router registers can trigger and clear these interrupts.
+
+A single node in the device tree is used to describe the Interrupt Router.
+Since X+Y>Z, some IRQ inputs may need to be routed to the same IRQ output,
+thus "sharing the IRQ line".
+
+There are two ways of defining such sharing, either by specifying the number
+of IRQ groups, either by listing the IRQ groups and their contents.
+In the former case the groups are created and named "implicitly", in the
+later case the groups are created "explicitly" by grouping IRQs.
+An IRQ group will share an IRQ output, thus all input IRQs falling into that
+group will share a given IRQ line.
+
+If SW IRQs are enabled ("swirq-count" != 0), they will *ALL* be grouped
+together.
+
+Required properties:
+- compatible: Should be "sigma,smp,irqrouter".
+- interrupt-controller: Identifies the node as an interrupt controller.
+- inputs: The number of IRQ lines entering the router
+- outputs: The number of IRQ lines exiting the router
+- swirq-count: The number of SW IRQs supported. If 0, none is supported.
+- reg: Base address and size of interrupt router registers.
+- #interrupt-cells: Should be <3>. Defines how other nodes will be able to
+interact with this node. The meaning of the cells are
+	* First Cell: SIGMA_HWIRQ, SIGMA_SWIRQ, [SIGMA_IRQGROUP_1, ...,
+SIGMA_IRQGROUP_15].
+	* Second Cell: IRQ ID
+	* Third Cell: IRQ polarity (level high or low).
+
+Optional properties:
+- irq-groups: The number of IRQ groups used.
+NOTE: if present, it forces implicit group definition.
+- irq-group{i}: if 'irq-groups' is not present, then explicit group declaration
+may be required, and can be done by creating child nodes of the form:
+   irq-group0: {
+      shared-irqs = <1 38 56>;
+   };
+NOTE: the number of groups cannot exceed the number of outputs.
+NOTE2: SW IRQs have their own group so the number of total groups is
+'irq-groups'+1.
+- interrupt-parent: pHandle of the parent interrupt controller, if not
+  inherited from the parent node. It should be the GIC.
+
+
+Example:
+
+See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt and
+Documentation/devicetree/bindings/arm/gic.txt for further details.
+
+The following example declares a irqrouter with 128 inputs, 24 outputs, 16
+SW IRQs, declaring 4 implicit IRQ groups, with registers @ 0x6F800 and
+connected to the GIC.
+
+		irqrouter: irqrouter@6f800 {
+			 compatible = "sigma,smp,irqrouter";
+			 reg = <0x6f800 0x800>;
+			 interrupt-controller;
+			 interrupt-parent = <&gic>;
+
+			 #interrupt-cells = <3>;
+
+			 inputs = <128>;
+			 outputs = <24>;
+			 swirq-count = <16>;
+
+			 irq-groups = <4>;
+		};
+
+Devices can then request IRQs using:
+
+a) interrupts = <SIGMA_SWIRQ      10 IRQ_TYPE_LEVEL_HIGH>;
+b) interrupts = <SIGMA_HWIRQ      10 IRQ_TYPE_LEVEL_HIGH>;
+c) interrupts = <SIGMA_IRQGROUP_2 10 IRQ_TYPE_LEVEL_HIGH>;
+
+Case a) is for SWIRQs: requests SW IRQ 10
+Case b) is for non-shared HW IRQs: requests HW IRQ 10, the irqrouter will
+assign a direct route from input (10) to a free output reserving an IRQ line on
+the parent Interrupt controller.
+Case c) is for shared HW IRQs: indeed, SIGMA_IRQGROUP_2 is used as ID, thus the
+irqrouter will then route this input (10) to the output assigned to IRQ group 2.
+
+NOTE: SW IRQ 10 and HW IRQ 10 are not the same.
+
+The following example declares the same irqrouter as the preceding example
+but using explicit IRQ group declaration.
+
+		irqrouter: irqrouter@6f800 {
+			 compatible = "sigma,smp,irqrouter";
+			 reg = <0x6f800 0x800>;
+			 interrupt-controller;
+			 interrupt-parent = <&gic>;
+
+			 #interrupt-cells = <3>;
+
+			 inputs = <128>;
+			 outputs = <24>;
+			 swirq-count = <16>;
+
+			 irq-group0 {
+			       shared-irqs = <1 38 56 11>;
+			 };
+
+			 irq-group1 {
+			       shared-irqs = <67 68>;
+			 };
+		};
+
+Devices can then request IRQs using:
+
+d) interrupts = <SIGMA_SWIRQ 10 IRQ_TYPE_LEVEL_HIGH>;
+e) interrupts = <SIGMA_HWIRQ 10 IRQ_TYPE_LEVEL_HIGH>;
+f) interrupts = <SIGMA_HWIRQ 11 IRQ_TYPE_LEVEL_HIGH>;
+
+Case d) is for SWIRQs: requests SW IRQ 10
+Case e) is for non-shared HW IRQs: requests HW IRQ 10, the irqrouter will
+assign a direct route from input (10) to a free output reserving an IRQ line on
+the parent Interrupt controller.
+Case f) is for a shared HW IRQ: indeed, 'irq-group0' lists IRQ 11 as belonging
+to a group ('irq-group0' but it is not really important), thus the irqrouter
+will route this input (11) to the output assigned to IRQ group 'irq-group0'.
+
+NOTE: SW IRQ 10 and HW IRQ 10 are not the same.
drivers/irqchip/Makefile +1 -0
index 4c203b6..2be8c3f 100644
@@ -47,6 +47,7 @@ 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_v4.o
 obj-$(CONFIG_TB10X_IRQC)		+= irq-tb10x.o
 obj-$(CONFIG_TS4800_IRQ)		+= irq-ts4800.o
 obj-$(CONFIG_XTENSA)			+= irq-xtensa-pic.o
drivers/irqchip/irq-tango_v4.c new file +1729 -0

1,729 lines not on this page · raw message

include/dt-bindings/interrupt-controller/irq-tango_v4.h new file +39 -0
new file mode 100644
index 0000000..eb85d54
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 Sebastian Frias <[email protected]>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_SIGMA_SMP_TANGO_V4_H
+#define _DT_BINDINGS_INTERRUPT_CONTROLLER_SIGMA_SMP_TANGO_V4_H
+
+#define SIGMA_HWIRQ (0xAA)
+#define SIGMA_SWIRQ (0x55)
+
+#define SIGMA_MAX_IRQGROUPS (16)
+
+#define SIGMA_IRQGROUP_KEY (0x80)
+
+/* NOTE: SW IRQs have their own IRQ group reserved, that's why there are
+ * only (SIGMA_MAX_IRQGROUPS - 1)=15 groups listed below and available
+ */
+#define SIGMA_IRQGROUP_1  (SIGMA_IRQGROUP_KEY + 0x1)
+#define SIGMA_IRQGROUP_2  (SIGMA_IRQGROUP_KEY + 0x2)
+#define SIGMA_IRQGROUP_3  (SIGMA_IRQGROUP_KEY + 0x3)
+#define SIGMA_IRQGROUP_4  (SIGMA_IRQGROUP_KEY + 0x4)
+#define SIGMA_IRQGROUP_5  (SIGMA_IRQGROUP_KEY + 0x5)
+#define SIGMA_IRQGROUP_6  (SIGMA_IRQGROUP_KEY + 0x6)
+#define SIGMA_IRQGROUP_7  (SIGMA_IRQGROUP_KEY + 0x7)
+#define SIGMA_IRQGROUP_8  (SIGMA_IRQGROUP_KEY + 0x8)
+#define SIGMA_IRQGROUP_9  (SIGMA_IRQGROUP_KEY + 0x9)
+#define SIGMA_IRQGROUP_10 (SIGMA_IRQGROUP_KEY + 0xa)
+#define SIGMA_IRQGROUP_11 (SIGMA_IRQGROUP_KEY + 0xb)
+#define SIGMA_IRQGROUP_12 (SIGMA_IRQGROUP_KEY + 0xc)
+#define SIGMA_IRQGROUP_13 (SIGMA_IRQGROUP_KEY + 0xd)
+#define SIGMA_IRQGROUP_14 (SIGMA_IRQGROUP_KEY + 0xe)
+#define SIGMA_IRQGROUP_15 (SIGMA_IRQGROUP_KEY + 0xf)
+
+#endif
Signature · 1 line
1.7.11.2
#27 lore raw

drivers/irqchip/irq-tango_v4.c line 25

Quoted 4 lines · Sebastian Frias
drivers/irqchip/irq-tango_v4.c new file +4 -0
+
+#define DBGERR(__format, ...)	panic("[%s:%d] %s(): " __format,	\
+				      __FILE__, __LINE__,		\
+				      __func__, ##__VA_ARGS__)

Please get rid of this macro mess. Use the functions (panic, ...) directly. There is no value for this file, line, func crappola. Think about proper texts which can be grepped for.

Review

Quoted 2 lines
(quoted diff) +2 -0
+
+#define DBGWARN(__format, ...)	pr_err("[%s:%d] %s(): " __format,	\

Very consistent. WARN == err ....

drivers/irqchip/irq-tango_v4.c line 32

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+				       __FILE__, __LINE__,		\
+				       __func__, ##__VA_ARGS__)
+
+
+#if 0

Don't even think about posting code with "#if 0" or such in it.

drivers/irqchip/irq-tango_v4.c line 38

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+#define DBGLOG(__format, ...)   pr_info("[%s:%d] %s(): " __format,	\
+					__FILE__, __LINE__,		\
+					__func__, ##__VA_ARGS__)
+#else
+#define DBGLOG(__format, ...) do {} while (0)
+#endif

pr_debug() is there for a reason.

drivers/irqchip/irq-tango_v4.c line 139

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+#if 0
+#define SHORT_OR_FULL_NAME full_name
+#else
+#define SHORT_OR_FULL_NAME name
+#endif

Use one and be done with it. Really.

drivers/irqchip/irq-tango_v4.c line 142

Quoted 3 lines
drivers/irqchip/irq-tango_v4.c new file +3 -0
+
+#define NODE_NAME(__node__) (__node__ ? __node__->SHORT_OR_FULL_NAME :	\
+			     "<no-node>")

Sigh. pr_xxx("%s", NULL) prints <null>. That's really sufficient for your debug/error handling.

Quoted 22 lines
drivers/irqchip/irq-tango_v4.c new file +22 -0
+
+#define BITMASK_VECTOR_SIZE(__count__) (__count__ / 32)
+#define IRQ_TO_OFFSET(__hwirq__) (__hwirq__ * 4)
+
+struct tango_irqrouter;
+
+/*
+ * Maintains the mapping between a Linux virq and a hwirq
+ * on the parent controller.
+ * It is used by tango_irqdomain_map() or tango_irqdomain_hierarchy_alloc()
+ * to setup the route between input IRQ and output IRQ
+ */
+struct tango_irqrouter_output {
+	struct tango_irqrouter *context;
+
+	u32 domain_id;
+
+	u32 hwirq;
+	u32 hwirq_level;
+	u32 virq;
+
+	int shared_count;

drivers/irqchip/irq-tango_v4.c line 174

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+	int *shared_irqs;
+};
+
+/*
+ * Context for the driver
+ */
+struct tango_irqrouter {
+	raw_spinlock_t lock;
+	struct device_node *node;
+	void __iomem *base;

Plase align struct members proper

	raw_spinlock_t		lock;
	struct device_node	*node;
	void __iomem		*base;

drivers/irqchip/irq-tango_v4.c line 178

Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+
+	int input_count;
+	u32 irq_mask[BITMASK_VECTOR_SIZE(ROUTER_INPUTS)];
+	u32 irq_invert_mask[BITMASK_VECTOR_SIZE(ROUTER_INPUTS)];

You only ever use BITMASK_VECTOR_SIZE(ROUTER_INPUTS). Why can't you simply do:

#define ROUTER_INPUTs_MASK_SIZE (ROUTER__INPUTS / 32) ????

drivers/irqchip/irq-tango_v4.c line 349

Quoted 7 lines
drivers/irqchip/irq-tango_v4.c new file +7 -0
+static inline u32 tango_readl(struct tango_irqrouter *irqrouter,
+			      int reg)
+{
+	u32 val = readl_relaxed(irqrouter->base + reg);
+	/*DBGLOG("r[0x%08x + 0x%08x = 0x%08x] = 0x%08x\n",
+	  irqrouter->base, reg, irqrouter->base + reg, val);*/
+	return val;

Please get rid of this debug nonsense.

Quoted 8 lines
drivers/irqchip/irq-tango_v4.c new file +8 -0
+}
+
+
+static inline void tango_writel(struct tango_irqrouter *irqrouter,
+				int reg,
+				u32 val)
+{
+	/*DBGLOG("w[0x%08x + 0x%08x = 0x%08x] = 0x%08x\n",

drivers/irqchip/irq-tango_v4.c line 367

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+	  irqrouter->base, reg, irqrouter->base + reg, val);*/
+	writel_relaxed(val, irqrouter->base + reg);
+}
+
+
+static inline void tango_set_swirq_enable(struct tango_irqrouter *irqrouter,
+					  int swirq,
+					  bool enable)
+{
+	u32 offset = SWIRQ_ENABLE;

If you name that varible 'reg' then it becomes obvious what it does.

drivers/irqchip/irq-tango_v4.c line 378

Quoted 11 lines
drivers/irqchip/irq-tango_v4.c new file +11 -0
+	u32 value = tango_readl(irqrouter, offset);
+	u32 swirq_bit_index = swirq % SWIRQ_COUNT;
+
+#if 1
+	DBGLOG("%smask swirq(in) %d : current regvalue 0x%x\n",
+	       enable ? "un":"",
+	       swirq, value);
+#endif
+
+	if (enable) {
+		/* unmask swirq */

The whole code lacks comments, but here you document the obvious ....

Quoted 41 lines
drivers/irqchip/irq-tango_v4.c new file +41 -0
+		irqrouter->swirq_mask |= (1 << swirq_bit_index);
+		value |= (1 << swirq_bit_index);
+	} else {
+		/* mask swirq */
+		irqrouter->swirq_mask &= ~(1 << swirq_bit_index);
+		value &= ~(1 << swirq_bit_index);
+	}
+
+	tango_writel(irqrouter, offset, value);
+}
+
+
+static inline void tango_set_hwirq_enable(struct tango_irqrouter *irqrouter,
+					  int hwirq,
+					  bool enable)
+{
+	u32 offset = IRQ_TO_OFFSET(hwirq);
+	u32 value = tango_readl(irqrouter, offset);
+	u32 hwirq_reg_index = hwirq / 32;
+	u32 hwirq_bit_index = hwirq % 32;
+	u32 *enable_mask = &(irqrouter->irq_mask[hwirq_reg_index]);
+
+#if 1
+	DBGLOG("%smask hwirq(in) %d : current regvalue 0x%x\n",
+	       enable ? "un":"",
+	       hwirq, value);
+#endif
+
+	if (enable) {
+		/* unmask irq */
+		*enable_mask |= (1 << hwirq_bit_index);
+		value |= IRQ_ROUTER_ENABLE_MASK;
+	} else {
+		/* mask irq */
+		*enable_mask &= ~(1 << hwirq_bit_index);
+		value &= ~(IRQ_ROUTER_ENABLE_MASK);
+	}
+
+	tango_writel(irqrouter, offset, value);
+}
+

drivers/irqchip/irq-tango_v4.c line 429

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+
+static inline void tango_set_swirq_inversion(struct tango_irqrouter *irqrouter,
+					     int swirq,
+					     bool invert)
+{
+
+	DBGLOG("swirq(in) %d %s inverted\n", swirq, invert ? "":"not");
+
+	if (invert)
+		DBGERR("SW IRQs cannot be inverted!\n");

Groan.

Quoted 39 lines
drivers/irqchip/irq-tango_v4.c new file +39 -0
+}
+
+
+static inline void tango_set_hwirq_inversion(struct tango_irqrouter *irqrouter,
+					     int hwirq,
+					     bool invert)
+{
+	u32 offset = IRQ_TO_OFFSET(hwirq);
+	u32 value = tango_readl(irqrouter, offset);
+	u32 hwirq_reg_index = hwirq / 32;
+	u32 hwirq_bit_index = hwirq % 32;
+	u32 *invert_mask = &(irqrouter->irq_invert_mask[hwirq_reg_index]);
+
+	if (invert) {
+		*invert_mask |= (1 << hwirq_bit_index);
+		value |= IRQ_ROUTER_INVERT_MASK;
+	} else {
+		*invert_mask &= ~(1 << hwirq_bit_index);
+		value &= ~(IRQ_ROUTER_INVERT_MASK);
+	}
+
+	DBGLOG("hwirq(in) %d %s inverted\n", hwirq, invert ? "":"not");
+
+	tango_writel(irqrouter, offset, value);
+}
+
+
+static inline void tango_set_swirq_route(struct tango_irqrouter *irqrouter,
+					 int swirq_in,
+					 int irq_out)
+{
+	u32 swirq_reg_index = swirq_in / 4;
+	u32 swirq_bit_index = (swirq_in % 4) * 8;
+	u32 mask = ~(0x1f << swirq_bit_index);
+	u32 offset = SWIRQ_MAP_GROUP0 + (swirq_reg_index * 4);
+	u32 value = tango_readl(irqrouter, offset);
+
+	DBGLOG("ri %d, bi %d, mask 0x%x, offset 0x%x, val 0x%x\n",
+	       swirq_reg_index,

drivers/irqchip/irq-tango_v4.c line 478

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+	       swirq_bit_index,
+	       mask,
+	       offset,
+	       value);
+
+	DBGLOG("route swirq %d => hwirq(out) %d\n", swirq_in, irq_out);
+
+	value &= mask;
+
+	if (irq_out < 0) {

This logic is utterly confusing, really. What's a negative interrupt number?

drivers/irqchip/irq-tango_v4.c line 481

Quoted 3 lines
drivers/irqchip/irq-tango_v4.c new file +3 -0
+		tango_set_irq_enable(irqrouter,
+				     swirq_in + irqrouter->input_count,
+				     0);

Now you write back 'value' with the bit for this irq masked. Is that correct?

Review

Quoted 1 line
(quoted diff) +1 -0
+	} else
  } else {

please

Quoted 9 lines
drivers/irqchip/irq-tango_v4.c new file +9 -0
+		value |= ((irq_out & 0x1f) << swirq_bit_index);
+
+	tango_writel(irqrouter, offset, value);
+}
+
+
+static inline void tango_set_hwirq_route(struct tango_irqrouter *irqrouter,
+					 int irq_in,
+					 int irq_out)

drivers/irqchip/irq-tango_v4.c line 501

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+{
+	u32 offset = IRQ_TO_OFFSET(irq_in);
+	u32 value;
+
+	DBGLOG("route hwirq(in) %d => hwirq(out) %d\n", irq_in, irq_out);
+
+	if (irq_out < 0) {
+		tango_set_irq_enable(irqrouter,
+				     irq_in,
+				     0);

This fits in a single line.

drivers/irqchip/irq-tango_v4.c line 502

Quoted 1 line
drivers/irqchip/irq-tango_v4.c new file +1 -0
+		value = 0;

Please document why you are setting the value to 0 here.

drivers/irqchip/irq-tango_v4.c line 515

Quoted 13 lines
drivers/irqchip/irq-tango_v4.c new file +13 -0
+	} else
+		value = (irq_out & 0x1f);
+
+	tango_writel(irqrouter, offset, value);
+}
+
+
+static inline int tango_set_irq_enable(struct tango_irqrouter *irqrouter,
+				       int irq,
+				       bool enable)
+{
+	if (irq >= (irqrouter->input_count + irqrouter->swirq_count))
+		return -EINVAL;

How can that happen? Paranoia programming?

drivers/irqchip/irq-tango_v4.c line 516

Quoted 1 line
drivers/irqchip/irq-tango_v4.c new file +1 -0
+	else if (irq >= irqrouter->input_count)

That "else" is pointless. You return above.

drivers/irqchip/irq-tango_v4.c line 523

Quoted 7 lines
drivers/irqchip/irq-tango_v4.c new file +7 -0
+		tango_set_swirq_enable(irqrouter,
+				       irq - irqrouter->input_count,
+				       enable);
+	else
+		tango_set_hwirq_enable(irqrouter,
+				       irq,
+				       enable);

This can be written way simpler.

     	if (irq >= irqrouter->input_count)
	   	irq -= irqrouter->input_count;
	tango_set_hwirq_enable(irqrouter, irq, enable);

Hmm?

drivers/irqchip/irq-tango_v4.c line 576

Quoted 13 lines
drivers/irqchip/irq-tango_v4.c new file +13 -0
+static int tango_set_irq_type(struct tango_irqrouter *irqrouter,
+			      int hwirq_in,
+			      u32 type,
+			      u32 parent_type)
+{
+	int err;
+
+	if (parent_type & (type & IRQ_TYPE_SENSE_MASK))
+		/* same polarity */
+		err = tango_set_irq_inversion(irqrouter, hwirq_in, 0);
+	else
+		/* invert polarity */
+		err = tango_set_irq_inversion(irqrouter, hwirq_in, 1);
  	bool invert = parent_type & (type & IRQ_TYPE_SENSE_MASK);

  	err = tango_set_irq_inversion(irqrouter, hwirq_in, invert);	

drivers/irqchip/irq-tango_v4.c line 586

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+
+	if (err < 0) {
+		DBGWARN("Failed to setup IRQ %d polarity\n", hwirq_in);
+		return err;
+	}
+
+	switch (type & IRQ_TYPE_SENSE_MASK) {
+	case IRQ_TYPE_EDGE_RISING:
+	case IRQ_TYPE_EDGE_FALLING:
+		DBGERR("Does not support edge triggers\n");

This really sucks. In fact you panic here while the code suggests that you print a DEBUG error and continue .....

drivers/irqchip/irq-tango_v4.c line 589

Quoted 3 lines
drivers/irqchip/irq-tango_v4.c new file +3 -0
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		break;

You can spare that break.

drivers/irqchip/irq-tango_v4.c line 594

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+	case IRQ_TYPE_LEVEL_LOW:
+		break;
+	default:
+		DBGWARN("Invalid trigger mode 0x%x for hwirq(in) %d\n",
+			type, hwirq_in);

So here you continue with an error code, but above for EDGE you panic. I really don't get that logic.

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+		return -EINVAL;
+	}
+
+	return 0;
+}
+

drivers/irqchip/irq-tango_v4.c line 610

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+
+static int tango_get_output_for_hwirq(struct tango_irqrouter *irqrouter,
+				      int hwirq_in,
+				      struct tango_irqrouter_output **out_val)
+{
+	struct tango_irqrouter_output *irqrouter_output;
+	int i;
+
+	if (!out_val)
+		return -EINVAL;

This is utter crap. Look at the call site:

drivers/irqchip/irq-tango_v4.c line 1075

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+	struct tango_irqrouter_output *irqrouter_output = NULL;
+
+	tango_get_output_for_hwirq(irqrouter, hwirq_in, &irqrouter_output);
+	if (!irqrouter_output)
+		goto handle_parent;

So out_val CANNOT be NULL. What's the purpose of your return values if you ignore them?

drivers/irqchip/irq-tango_v4.c line 612

Quoted 2 lines
drivers/irqchip/irq-tango_v4.c new file +2 -0
+
+	/* Get the irqrouter_output for the hwirq */

This is another really helpful comment.

drivers/irqchip/irq-tango_v4.c line 623

Quoted 11 lines
drivers/irqchip/irq-tango_v4.c new file +11 -0
+	for (i = 0; i < irqrouter->output_count; i++) {
+		int j;
+
+		irqrouter_output = &(irqrouter->output[i]);
+
+		for (j = 0; j < irqrouter_output->shared_count; j++) {
+			if (hwirq_in == irqrouter_output->shared_irqs[j])
+				goto found_router_output;
+		}
+	}
+	if (i == irqrouter->output_count) {

What other reason would be to get here than this?

drivers/irqchip/irq-tango_v4.c line 632

Quoted 9 lines
drivers/irqchip/irq-tango_v4.c new file +9 -0
+		DBGWARN("Couldn't find hwirq mapping\n");
+		return -ENODEV;
+	}
+
+found_router_output:
+
+	*out_val = irqrouter_output;
+	return 0;
+}

This whole thing can be condensed to:

static struct tango_irqrouter_output * tango_get_output_for_hwirq(struct tango_irqrouter *irqr, int hwirq_in)

{
	struct tango_irqrouter_output *rout;
	int i, j;

	/* Scan the outputs for a matching hwirq number */
	for (i = 0, rout = irqr->output; i < irqr->output_count; i++, rout++) {
		for (j = 0; j < rout->shared_count; j++) {
			if (rout->shared_irqs[j] == hwirq_in)
			   	return rout;
		}
	}
	return NULL;
}

And the call site would become:

    	struct tango_irqrouter_output *rout;

	rout = tango_get_output_for_hwirq(irqrouter, hwirq_in);
	if (!rout)
		goto handle_parent;

Hmm?

drivers/irqchip/irq-tango_v4.c line 262

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+/* 'irqchip' handling callbacks
+ * Used for 'shared' IRQs, i.e.: IRQs that share a GIC input
+ * This driver performs the IRQ dispatch based on the flags
+ */
+

Multiline comments have this format:

/*
* First line
* ....
* Last line
*/

drivers/irqchip/irq-tango_v4.c line 685

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+static void tango_irqchip_mask_irq(struct irq_data *data)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+	int hwirq_in = (int)data->hwirq;

Huch? What's that silly typecast for? Why can't you use u32 for hwirq_in?

Quoted 12 lines
drivers/irqchip/irq-tango_v4.c new file +11 -0
+	tango_set_irq_enable(irqrouter, hwirq_in, 0);
+}
 
+#ifdef CONFIG_SMP
+static int tango_irqchip_set_irq_affinity(struct irq_data *data,
+					  const struct cpumask *mask_val,
+					  bool force)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct irq_chip *parent_chip = irq_get_chip(irqrouter_output->virq);
+	struct irq_data *parent_data = irq_get_irq_data(irqrouter_output->virq);

drivers/irqchip/irq-tango_v4.c line 743

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+
+	DBGLOG("%s:%s(0x%p)\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)), domain->name, domain);
+
+	if (parent_chip && parent_chip->irq_set_affinity)
+		return parent_chip->irq_set_affinity(parent_data,
+						     mask_val,
+						     force);
+	else
+		return -EINVAL;

You really can spare identation levels by writing it a bit more clever:

    	if (!parent || !parent->irq_set_affinity)
	   	 return -EINVAL;

	return parent->irq_set_affinity(parent, mask, force);

You might notice that I shortened the variable names and it still is entirely clear what the code does.

Aside of that mask_val is a clear misnomer.

drivers/irqchip/irq-tango_v4.c line 754

Quoted 11 lines
drivers/irqchip/irq-tango_v4.c new file +11 -0
+}
+#endif
+
+
+static inline u32 tango_dispatch_irqs(struct irq_domain *domain,
+				      struct irq_desc *desc,
+				      u32 status,
+				      int base)
+{
+	u32 hwirq;
+	u32 virq;

Please put same types onto a single line

drivers/irqchip/irq-tango_v4.c line 767

Quoted 13 lines
drivers/irqchip/irq-tango_v4.c new file +13 -0
+
+	while (status) {
+		hwirq = __ffs(status);
+		virq = irq_find_mapping(domain, base + hwirq);
+		if (unlikely(!virq))
+			handle_bad_irq(desc);
+		else
+			generic_handle_irq(virq);
+
+		status &= ~BIT(hwirq);
+	}
+
+	return status;

Huch? status is guaranteed to be 0 here. So what's the point of this return value.

Quoted 14 lines
drivers/irqchip/irq-tango_v4.c new file +14 -0
+}
+
+static void tango_irqdomain_handle_cascade_irq(struct irq_desc *desc)
+{
+	struct irq_domain *domain = irq_desc_get_handler_data(desc);
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+	struct irq_chip *host_chip = irq_desc_get_chip(desc);
+	u32 i, status;
+	u32 swirq_status, irq_status[BITMASK_VECTOR_SIZE(ROUTER_INPUTS)];
+
+#if 0
+	DBGLOG("%s:%s(0x%p): irqrouter_output 0x%p, hwirq(out) %d\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)), domain->name, domain,

drivers/irqchip/irq-tango_v4.c line 792

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+	       irqrouter_output, irqrouter_output->hwirq);
+#endif
+
+	chained_irq_enter(host_chip, desc);
+
+	raw_spin_lock(&(irqrouter->lock));
+	swirq_status = tango_readl(irqrouter, READ_SWIRQ_STATUS);
+	for (i = 0; i < BITMASK_VECTOR_SIZE(ROUTER_INPUTS); i++)
+		irq_status[i] = tango_readl(irqrouter,
+					    READ_SYS_IRQ_GROUP0 + i*4);

i * 4 please

drivers/irqchip/irq-tango_v4.c line 795

Quoted 3 lines
drivers/irqchip/irq-tango_v4.c new file +3 -0
+	raw_spin_unlock(&(irqrouter->lock));
+
+	/* HW irqs */

And that comment tells us what?

drivers/irqchip/irq-tango_v4.c line 806

Quoted 11 lines
drivers/irqchip/irq-tango_v4.c new file +11 -0
+	for (i = 0; i < BITMASK_VECTOR_SIZE(ROUTER_INPUTS); i++) {
+#if 0
+		DBGLOG("%d: 0x%08x (en 0x%08x, inv 0x%08x)\n",
+		       i,
+		       irq_status[i],
+		       irqrouter->irq_mask[0],
+		       irqrouter->irq_invert_mask[0]);
+#endif
+
+#define HANDLE_INVERTED_LINES(__irqstatus__, __x__) ((((~__irqstatus__) & irqrouter->irq_invert_mask[__x__]) & irqrouter->irq_mask[__x__]) | __irqstatus__)
+#define HANDLE_EN_AND_INV_MASKS(__irqstatus__, __y__) (HANDLE_INVERTED_LINES(__irqstatus__, __y__) & irqrouter->irq_mask[__y__])

What the hell does this unparseable macro mess? What's so wrong with a proper inline function?

drivers/irqchip/irq-tango_v4.c line 810

Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+
+		irq_status[i] = HANDLE_EN_AND_INV_MASKS(irq_status[i], i);
+		status = tango_dispatch_irqs(domain, desc, irq_status[i], i*32);
+		if (status & irq_status[i])

Can you pretty please explain how this can happen? It can't. Because you clear every single bit of status in tango_dispatch_irqs(). See above.

Please clean up that unholy mess of nonsensical checks and debug code.

drivers/irqchip/irq-tango_v4.c line 819

Quoted 9 lines
drivers/irqchip/irq-tango_v4.c new file +9 -0
+			DBGERR("%s: %d unhandled IRQs (as a mask) 0x%x\n",
+			       NODE_NAME(irq_domain_get_of_node(domain)),
+			       i,
+			       status & irq_status[i]);
+	}
+
+	/* SW irqs */
+	swirq_status &= irqrouter->swirq_mask;
+	status = tango_dispatch_irqs(domain, desc, swirq_status, 128);

128 is the magic number pulled out of thin air or what?

drivers/irqchip/irq-tango_v4.c line 823

Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+	if (status & swirq_status)
+		DBGERR("%s: Unhandled IRQs (as a mask) 0x%x\n",
+		       NODE_NAME(irq_domain_get_of_node(domain)),
+		       status & swirq_status);

See above.

drivers/irqchip/irq-tango_v4.c line 832

Quoted 9 lines
drivers/irqchip/irq-tango_v4.c new file +9 -0
+
+	chained_irq_exit(host_chip, desc);
+}
+
+
+/**
+ * tango_irqdomain_map - route a hwirq(in) to a hwirq(out).
+ * NOTE: The hwirq(out) must have been already allocated and enabled on
+ * the parent controller.

Please put notes AFTER the argument descriptions

Quoted 5 lines

+ * @hwirq: HW IRQ of the device requesting an IRQ
+ * if hwirq > inputs it is a SW IRQ
+ * @virq: Linux IRQ (associated to the domain) to be given to the device
+ * @domain: IRQ domain (from the domain, we get the irqrouter_output
+ * in order to know to which output we need to route hwirq to)

And if you spend a few seconds to align this proper, then it becomes suddenly readable.

* @hwirq: HW IRQ of the device requesting an IRQ
* if hwirq > inputs it is a SW IRQ
* @virq: Linux IRQ (associated to the domain) to be given to the device
* @domain: IRQ domain (from the domain, we get the irqrouter_output
* in order to know to which output we need to route hwirq to)

Hmm?

Quoted 33 lines

+ */

drivers/irqchip/irq-tango_v4.c new file +32 -0
+static int tango_irqdomain_map(struct irq_domain *domain,
+			       unsigned int virq,
+			       irq_hw_number_t hwirq)
+{
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+
+	DBGLOG("%s:%s(0x%p): hwirq(in) %d := virq %d, and route "
+	       "hwirq(in) %d => hwirq(out) %d (virq %d)\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),
+	       domain->name,
+	       domain,
+	       (u32)hwirq,
+	       virq,
+	       (u32)hwirq,
+	       irqrouter_output->hwirq,
+	       irqrouter_output->virq);
+
+	if (hwirq >= (irqrouter->input_count + irqrouter->swirq_count))
+		DBGERR("%s: Invalid hwirq(in) %d >= %d + %d\n",
+		       NODE_NAME(irq_domain_get_of_node(domain)),
+		       (u32)hwirq,
+		       irqrouter->input_count,
+		       irqrouter->swirq_count);
+	else if (hwirq >= irqrouter->input_count)
+		DBGLOG("Map swirq %ld\n", hwirq - irqrouter->input_count);
+
+	irq_set_chip_and_handler(virq,
+				 &tango_irq_chip_shared_ops,
+				 handle_level_irq);
+	irq_set_chip_data(virq, domain);
+	irq_set_probe(virq);

drivers/irqchip/irq-tango_v4.c line 880

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+
+	tango_set_irq_route(irqrouter, hwirq, irqrouter_output->hwirq);
+
+	return 0;
+}
+
+
+/**
+ * tango_irqdomain_translate - used to select the domain for a given
+ * irq_fwspec

It hardly selects the domain. @domain is handed in as a argument. And please get rid of that silly 'used to'. That just adds characters and no information.

- Select the router section for a firmware spec

Hmm?

Quoted 3 lines

+ * @domain: a registered domain
+ * @fwspec: an IRQ specification. This callback is used to translate the
+ * parameters given as irq_fwspec into a HW IRQ and Type values.

fwspec is a callback?

Quoted 2 lines

+ * @out_hwirq:
+ * @out_type:

Missing docs.....

Quoted 14 lines

+ */

drivers/irqchip/irq-tango_v4.c new file +13 -0
+static int tango_irqdomain_translate(struct irq_domain *domain,
+				     struct irq_fwspec *fwspec,
+				     unsigned long *out_hwirq,
+				     unsigned int *out_type)
+{
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+	irq_hw_number_t irq;
+	u32 domain_id, type;
+	int err;
+
+	DBGLOG("%s:%s(0x%p): argc %d for hwirq(out) %d\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),

drivers/irqchip/irq-tango_v4.c line 909

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+	       domain->name,
+	       domain,
+	       fwspec->param_count,
+	       irqrouter_output->hwirq);
+
+	err = tango_parse_fwspec(domain,
+				 fwspec,
+				 &domain_id,
+				 &irq,
+				 &type);

Please use the full 80 characters. Your patch does not become more valuable when you inflate the line count. It's more valuable when it is easy to read and understand.

Quoted 7 lines
drivers/irqchip/irq-tango_v4.c new file +7 -0
+	if (err < 0) {
+		DBGWARN("Failed to parse fwspec\n");
+		return err;
+	}
+
+	switch (domain_id) {
+	case SIGMA_HWIRQ:

drivers/irqchip/irq-tango_v4.c line 926

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+		DBGLOG("Request is for SIGMA_HWIRQ\n");
+		break;
+	case SIGMA_SWIRQ:
+		DBGLOG("Request is for SIGMA_SWIRQ\n");
+		irq += irqrouter->input_count;
+		break;
+	default:
+		DBGLOG("Request is for domain ID 0x%x (we are 0x%x)\n",
+		       domain_id,
+		       irqrouter_output->domain_id);

Huch what? You only ever handle HW and SW irqs and now you happily proceed if the id is something else. Consistent error handling is optional and can be replaced by random debug prints, right?

Quoted 8 lines
drivers/irqchip/irq-tango_v4.c new file +8 -0
+		break;
+	};
+
+	*out_hwirq = irq;
+	*out_type  = type & IRQ_TYPE_SENSE_MASK;
+
+	DBGLOG("hwirq %d type 0x%x\n", (u32)*out_hwirq, (u32)*out_type);
+

drivers/irqchip/irq-tango_v4.c line 944

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+	return 0;
+}
+
+
+/**
+ * tango_irqdomain_select - used to select the domain for a given irq_fwspec
+ * @domain: a registered domain
+ * @fwspec: an IRQ specification. This callback should return zero if the
+ * irq_fwspec does not belong to the given domain. If it does, it should
+ * return non-zero.

Callback????

Quoted 33 lines

+ * In practice it will return non-zero if the irq_fwspec matches one of the
+ * IRQs shared within the given domain.
+ * @bus_token: a bus token
+ */

drivers/irqchip/irq-tango_v4.c new file +29 -0
+static int tango_irqdomain_select(struct irq_domain *domain,
+				  struct irq_fwspec *fwspec,
+				  enum irq_domain_bus_token bus_token)
+{
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+	irq_hw_number_t irq;
+	u32 domain_id, type;
+	int err;
+
+	DBGLOG("%s:%s(0x%p): argc %d, 0x%p, bus 0x%x\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)), domain->name, domain,
+	       fwspec->param_count, fwspec->fwnode, bus_token);
+
+	DBGLOG("router 0x%p, output 0x%p\n", irqrouter, irqrouter_output);
+
+	err = tango_parse_fwspec(domain, fwspec, &domain_id, &irq, &type);
+	if (err < 0)
+		return 0;
+
+	switch (domain_id) {
+	case SIGMA_HWIRQ:
+		DBGLOG("Request is for SIGMA_HWIRQ\n");
+		break;
+	case SIGMA_SWIRQ:
+		DBGLOG("Request is for SIGMA_SWIRQ\n");
+		break;
+	default:
+		DBGLOG("Request is for domain ID 0x%x (we are 0x%x)\n",

drivers/irqchip/irq-tango_v4.c line 988

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+		       domain_id,
+		       irqrouter_output->domain_id);
+		break;
+	};
+
+	if (!irqrouter->implicit_groups) {
+		int i;
+
+		/* Check if the requested IRQ belongs to those listed
+		 * to be sharing the output assigned to this domain

Your using of 'domain' is utterly confusing. Please use something like hwdomain or whatever which makes it clear that this is something else than the irq domain. I tripped over this several times now.

Quoted 77 lines
drivers/irqchip/irq-tango_v4.c new file +77 -0
+		 */
+		if (irqrouter_output->shared_count <= 0) {
+			DBGLOG("Not shared IRQ line?\n");
+			return 0;
+		}
+
+		for (i = 0; i < irqrouter_output->shared_count; i++) {
+			if (irq == irqrouter_output->shared_irqs[i]) {
+				DBGLOG("Match: IRQ %lu\n", irq);
+				return 1;
+			}
+		}
+	} else {
+		/* Otherwise, check if the domain_id given matches
+		 * the one assigned to this output
+		 */
+		if (domain_id == irqrouter_output->domain_id) {
+			DBGLOG("Match: Domain ID %d\n", domain_id);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+/* 'irqrouter' handling callbacks
+ * Used for 'direct' IRQs, i.e.: IRQs that are directly routed to the GIC
+ * This driver does not dispatch the IRQs, the GIC does.
+ */
+
+
+static void tango_irqrouter_mask_irq(struct irq_data *data)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter *irqrouter = domain->host_data;
+	int hwirq_in = (int)data->hwirq;
+
+	DBGLOG("%s:%s(0x%p) hwirq(in) %d\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),
+	       domain->name,
+	       domain,
+	       hwirq_in);
+
+	tango_set_irq_enable(irqrouter, hwirq_in, 0);
+
+	irq_chip_mask_parent(data);
+}
+
+
+static void tango_irqrouter_unmask_irq(struct irq_data *data)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter *irqrouter = domain->host_data;
+	int hwirq_in = (int)data->hwirq;
+
+	DBGLOG("%s:%s(0x%p) hwirq(in) %d\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),
+	       domain->name,
+	       domain,
+	       hwirq_in);
+
+	tango_set_irq_enable(irqrouter, hwirq_in, 1);
+
+	irq_chip_unmask_parent(data);
+}
+
+
+static int tango_irqrouter_set_irq_type(struct irq_data *data,
+					unsigned int type)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter_output *irqrouter_output = NULL;
+	struct tango_irqrouter *irqrouter = domain->host_data;
+	int hwirq_in = (int)data->hwirq;
+	u32 parent_type;
+

drivers/irqchip/irq-tango_v4.c line 1075

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+	DBGLOG("%s:%s(0x%p) type 0x%x for hwirq(in) %d\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),
+	       domain->name,
+	       domain,
+	       type,
+	       hwirq_in);
+
+	tango_get_output_for_hwirq(irqrouter, hwirq_in, &irqrouter_output);
+	if (!irqrouter_output)
+		goto handle_parent;

So if there is no output, then you unconditionally set the type on the parent. If that's correct, this needs a big fat comment at least.

drivers/irqchip/irq-tango_v4.c line 1082

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+	parent_type = (irqrouter_output->hwirq_level & IRQ_TYPE_SENSE_MASK);
+	tango_set_irq_type(irqrouter, hwirq_in, type, parent_type);
+
+handle_parent:
+	return irq_chip_set_type_parent(data, type);
+}

I'm stopping here. You can apply the above to the rest of the code as well.

Thanks,

tglx

#28 lore raw

Hi Thomas,

Thanks for your comments.
I appreciate the time you dedicated to the review.
I will take your comments into account, in the meanwhile, and since this was a RFC, would it be possible to also get some feedback/comments from a conceptual point of view?

I'm copy/pasting some of the questions I attached to the RFC email here:

----
2) In order to get a virq mapping for the domains associated with the outputs (the outputs connected to the GIC) I request a sort of "Fake HW IRQ" See irq-tango_v4.c:1400

	/* To request a virq we need a HW IRQ, use a "Fake HW IRQ" */
	hwirq      = index + irqrouter->input_count + irqrouter->swirq_count;

This feels a bit like a hack, so suggestions are welcome.

3) The file is called 'irq-tango_v4.c' but I think it should match the compatible string, so I was thinking of renaming:
irq-tango_v4.c => irq-sigma_smp_irqrouter.c
irq-tango_v4.h => irq-sigma_smp_irqrouter.h

What do you think?

4) Do I have to do something more to handle the affinity stuff?

6) More of a theoretical question:
I have to #include <dt-bindings/interrupt-controller/irq-tango_v4.h> from code that is not in the Linux tree. That's fine for now, but if in the future there are other irq controllers and another header is required, how can the code know which header to #include ?
Are we supposed to #include all of them, and then somehow detect which module is actually active and act accordingly? If so, can we detect which module matched and probed correctly to know which controller version we need to talk to?
----

What the driver does is:
- creates a domain hierarchy attached to its parent domain (the GIC)
- the callbacks for this domain hierarchy will be used to deal with IRQs "directly" routed to the GIC (i.e.: exclusive IRQ lines routed to the GIC and not shared).
In this case the GIC dispatches the interrupts.
- create linear domains attached to this driver's node.
- the callbacks for these linear domains will be used to deal with shared IRQs (they share the routing to one of the GIC inputs).
In this case this driver dispatches the interrupts after reading the flags.

It is such concept, and then its implementation, that I would need some more advise with, because, as stated in the questions above, it still does not feels right, especially question 2.

I will reply to your comments below and will post a v3 later, hopefully after dealing also with the answers to the doubts outlined above.

Quoted 9 lines · Thomas Gleixner

drivers/irqchip/irq-tango_v4.c line 25

Quoted 4 lines · Sebastian Frias
drivers/irqchip/irq-tango_v4.c new file +4 -0
+
+#define DBGERR(__format, ...)	panic("[%s:%d] %s(): " __format,	\
+				      __FILE__, __LINE__,		\
+				      __func__, ##__VA_ARGS__)

Please get rid of this macro mess. Use the functions (panic, ...) directly. There is no value for this file, line, func crappola. Think about proper texts which can be grepped for.

Ok.

Quoted 6 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+
+#define DBGWARN(__format, ...)	pr_err("[%s:%d] %s(): " __format,	\

Very consistent. WARN == err ....

Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 32

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+				       __FILE__, __LINE__,		\
+				       __func__, ##__VA_ARGS__)
+
+
+#if 0

Don't even think about posting code with "#if 0" or such in it.

The idea behind these macros was:
- to easily enable/disable them.
- to be more consistent with other code written at Sigma: this is a Sigma-only driver.

Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 38

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+#define DBGLOG(__format, ...)   pr_info("[%s:%d] %s(): " __format,	\
+					__FILE__, __LINE__,		\
+					__func__, ##__VA_ARGS__)
+#else
+#define DBGLOG(__format, ...) do {} while (0)
+#endif

pr_debug() is there for a reason.

Yes, but doesn't pr_debug() requires changes to the Makefile?

Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 139

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+#if 0
+#define SHORT_OR_FULL_NAME full_name
+#else
+#define SHORT_OR_FULL_NAME name
+#endif

Use one and be done with it. Really.

By making the choice explicit, the person reading/debugging is aware of the possibilities. Picking "full_name" or "name" would likely prevent the person from knowing it has other debug options.

But I can change this if upstreaming depends on it.

Quoted 7 lines

drivers/irqchip/irq-tango_v4.c line 142

Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +3 -0
+
+#define NODE_NAME(__node__) (__node__ ? __node__->SHORT_OR_FULL_NAME :	\
+			     "<no-node>")

Sigh. pr_xxx("%s", NULL) prints <null>. That's really sufficient for your debug/error handling.

The code is checking for __node__ to be non-NULL before dereferencing it.

Quoted 36 lines
Quoted 23 lines
drivers/irqchip/irq-tango_v4.c new file +22 -0
+
+#define BITMASK_VECTOR_SIZE(__count__) (__count__ / 32)
+#define IRQ_TO_OFFSET(__hwirq__) (__hwirq__ * 4)
+
+struct tango_irqrouter;
+
+/*
+ * Maintains the mapping between a Linux virq and a hwirq
+ * on the parent controller.
+ * It is used by tango_irqdomain_map() or tango_irqdomain_hierarchy_alloc()
+ * to setup the route between input IRQ and output IRQ
+ */
+struct tango_irqrouter_output {
+	struct tango_irqrouter *context;
+
+	u32 domain_id;
+
+	u32 hwirq;
+	u32 hwirq_level;
+	u32 virq;
+
+	int shared_count;

drivers/irqchip/irq-tango_v4.c line 174

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+	int *shared_irqs;
+};
+
+/*
+ * Context for the driver
+ */
+struct tango_irqrouter {
+	raw_spinlock_t lock;
+	struct device_node *node;
+	void __iomem *base;

Plase align struct members proper

Quoted 3 lines
	raw_spinlock_t		lock;
	struct device_node	*node;
	void __iomem		*base;

Ok.

Quoted 10 lines

drivers/irqchip/irq-tango_v4.c line 178

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+
+	int input_count;
+	u32 irq_mask[BITMASK_VECTOR_SIZE(ROUTER_INPUTS)];
+	u32 irq_invert_mask[BITMASK_VECTOR_SIZE(ROUTER_INPUTS)];

You only ever use BITMASK_VECTOR_SIZE(ROUTER_INPUTS). Why can't you simply do:

#define ROUTER_INPUTs_MASK_SIZE (ROUTER__INPUTS / 32) ????

I guess I can do that.

Quoted 10 lines

drivers/irqchip/irq-tango_v4.c line 349

Quoted 8 lines
drivers/irqchip/irq-tango_v4.c new file +7 -0
+static inline u32 tango_readl(struct tango_irqrouter *irqrouter,
+			      int reg)
+{
+	u32 val = readl_relaxed(irqrouter->base + reg);
+	/*DBGLOG("r[0x%08x + 0x%08x = 0x%08x] = 0x%08x\n",
+	  irqrouter->base, reg, irqrouter->base + reg, val);*/
+	return val;

Please get rid of this debug nonsense.

Ok, although I can guarantee it was really useful to determine and prove that the HW documentation of the module was wrong...

Quoted 13 lines
Quoted 13 lines
drivers/irqchip/irq-tango_v4.c new file +12 -0
+}
+
+
+static inline void tango_writel(struct tango_irqrouter *irqrouter,
+				int reg,
+				u32 val)
+{
+	/*DBGLOG("w[0x%08x + 0x%08x = 0x%08x] = 0x%08x\n",
+	  irqrouter->base, reg, irqrouter->base + reg, val);*/
+	writel_relaxed(val, irqrouter->base + reg);
+}
+
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 367

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+
+static inline void tango_set_swirq_enable(struct tango_irqrouter *irqrouter,
+					  int swirq,
+					  bool enable)
+{
+	u32 offset = SWIRQ_ENABLE;

If you name that varible 'reg' then it becomes obvious what it does.

Well, it was to add a sort of "consistency" between the code for SW IRQs and HW IRQs.

Quoted 14 lines

drivers/irqchip/irq-tango_v4.c line 378

Quoted 12 lines
drivers/irqchip/irq-tango_v4.c new file +11 -0
+	u32 value = tango_readl(irqrouter, offset);
+	u32 swirq_bit_index = swirq % SWIRQ_COUNT;
+
+#if 1
+	DBGLOG("%smask swirq(in) %d : current regvalue 0x%x\n",
+	       enable ? "un":"",
+	       swirq, value);
+#endif
+
+	if (enable) {
+		/* unmask swirq */

The whole code lacks comments, but here you document the obvious ....

I will remove the comments.

Quoted 46 lines
Quoted 46 lines
drivers/irqchip/irq-tango_v4.c new file +45 -0
+		irqrouter->swirq_mask |= (1 << swirq_bit_index);
+		value |= (1 << swirq_bit_index);
+	} else {
+		/* mask swirq */
+		irqrouter->swirq_mask &= ~(1 << swirq_bit_index);
+		value &= ~(1 << swirq_bit_index);
+	}
+
+	tango_writel(irqrouter, offset, value);
+}
+
+
+static inline void tango_set_hwirq_enable(struct tango_irqrouter *irqrouter,
+					  int hwirq,
+					  bool enable)
+{
+	u32 offset = IRQ_TO_OFFSET(hwirq);
+	u32 value = tango_readl(irqrouter, offset);
+	u32 hwirq_reg_index = hwirq / 32;
+	u32 hwirq_bit_index = hwirq % 32;
+	u32 *enable_mask = &(irqrouter->irq_mask[hwirq_reg_index]);
+
+#if 1
+	DBGLOG("%smask hwirq(in) %d : current regvalue 0x%x\n",
+	       enable ? "un":"",
+	       hwirq, value);
+#endif
+
+	if (enable) {
+		/* unmask irq */
+		*enable_mask |= (1 << hwirq_bit_index);
+		value |= IRQ_ROUTER_ENABLE_MASK;
+	} else {
+		/* mask irq */
+		*enable_mask &= ~(1 << hwirq_bit_index);
+		value &= ~(IRQ_ROUTER_ENABLE_MASK);
+	}
+
+	tango_writel(irqrouter, offset, value);
+}
+
+
+static inline void tango_set_swirq_inversion(struct tango_irqrouter *irqrouter,
+					     int swirq,
+					     bool invert)
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 429

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+{
+
+	DBGLOG("swirq(in) %d %s inverted\n", swirq, invert ? "":"not");
+
+	if (invert)
+		DBGERR("SW IRQs cannot be inverted!\n");

Groan.

I rather keep this to catch typos in code requesting SW IRQs.

Quoted 44 lines
Quoted 44 lines
drivers/irqchip/irq-tango_v4.c new file +43 -0
+}
+
+
+static inline void tango_set_hwirq_inversion(struct tango_irqrouter *irqrouter,
+					     int hwirq,
+					     bool invert)
+{
+	u32 offset = IRQ_TO_OFFSET(hwirq);
+	u32 value = tango_readl(irqrouter, offset);
+	u32 hwirq_reg_index = hwirq / 32;
+	u32 hwirq_bit_index = hwirq % 32;
+	u32 *invert_mask = &(irqrouter->irq_invert_mask[hwirq_reg_index]);
+
+	if (invert) {
+		*invert_mask |= (1 << hwirq_bit_index);
+		value |= IRQ_ROUTER_INVERT_MASK;
+	} else {
+		*invert_mask &= ~(1 << hwirq_bit_index);
+		value &= ~(IRQ_ROUTER_INVERT_MASK);
+	}
+
+	DBGLOG("hwirq(in) %d %s inverted\n", hwirq, invert ? "":"not");
+
+	tango_writel(irqrouter, offset, value);
+}
+
+
+static inline void tango_set_swirq_route(struct tango_irqrouter *irqrouter,
+					 int swirq_in,
+					 int irq_out)
+{
+	u32 swirq_reg_index = swirq_in / 4;
+	u32 swirq_bit_index = (swirq_in % 4) * 8;
+	u32 mask = ~(0x1f << swirq_bit_index);
+	u32 offset = SWIRQ_MAP_GROUP0 + (swirq_reg_index * 4);
+	u32 value = tango_readl(irqrouter, offset);
+
+	DBGLOG("ri %d, bi %d, mask 0x%x, offset 0x%x, val 0x%x\n",
+	       swirq_reg_index,
+	       swirq_bit_index,
+	       mask,
+	       offset,
+	       value);
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 478

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+
+	DBGLOG("route swirq %d => hwirq(out) %d\n", swirq_in, irq_out);
+
+	value &= mask;
+
+	if (irq_out < 0) {

This logic is utterly confusing, really. What's a negative interrupt number?

It is a sort of "magic value" to disable the IRQ and the routing.

Quoted 6 lines

drivers/irqchip/irq-tango_v4.c line 481

Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +3 -0
+		tango_set_irq_enable(irqrouter,
+				     swirq_in + irqrouter->input_count,
+				     0);

Now you write back 'value' with the bit for this irq masked. Is that correct?

Yes, tango_set_irq_enable() is used to setup the mask (in this case disable the IRQ by masking it) to one register, and later we write 'value' (which deals with the routing) to a different register.
Since up to 4 SW IRQ routes can be programmed in one of multiple routing registers, to "disable" the routing for one of them, we need to mask the other 3 and leave them untouched.
'value' is ANDed with 'mask' which is keeps the 3 other routing intact and resetting the routing for the given IRQ.

Quoted 6 lines

Review

Quoted 2 lines
(quoted diff) +1 -0
+	} else
  } else {

please

I think I'm confused, we need to use {} for single statements on "else" blocks, but not on "for" blocks?

Quoted 14 lines
Quoted 14 lines
drivers/irqchip/irq-tango_v4.c new file +13 -0
+		value |= ((irq_out & 0x1f) << swirq_bit_index);
+
+	tango_writel(irqrouter, offset, value);
+}
+
+
+static inline void tango_set_hwirq_route(struct tango_irqrouter *irqrouter,
+					 int irq_in,
+					 int irq_out)
+{
+	u32 offset = IRQ_TO_OFFSET(irq_in);
+	u32 value;
+
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 501

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+	DBGLOG("route hwirq(in) %d => hwirq(out) %d\n", irq_in, irq_out);
+
+	if (irq_out < 0) {
+		tango_set_irq_enable(irqrouter,
+				     irq_in,
+				     0);

This fits in a single line.

Ok.
Actually, I was wondering if for consistency it wouldn't be better if all function calls had one argument per line?

Quoted 4 lines

drivers/irqchip/irq-tango_v4.c line 502

Quoted 2 lines
drivers/irqchip/irq-tango_v4.c new file +1 -0
+		value = 0;

Please document why you are setting the value to 0 here.

Ok.
(it is for the same reason than for SW IRQs, to "disable" the routing, or more precisely, to set disabled IRQs to a known value, in this case 0)

Quoted 16 lines
Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +3 -0
+	} else
+		value = (irq_out & 0x1f);
+

drivers/irqchip/irq-tango_v4.c line 515

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+	tango_writel(irqrouter, offset, value);
+}
+
+
+static inline int tango_set_irq_enable(struct tango_irqrouter *irqrouter,
+				       int irq,
+				       bool enable)
+{
+	if (irq >= (irqrouter->input_count + irqrouter->swirq_count))
+		return -EINVAL;

How can that happen? Paranoia programming?

No, actually it can happen, that's the reason for question 2 of my RFC:

----
2) In order to get a virq mapping for the domains associated with the outputs (the outputs connected to the GIC) I request a sort of "Fake HW IRQ" See irq-tango_v4.c:1400

/* To request a virq we need a HW IRQ, use a "Fake HW IRQ" */ hwirq = index + irqrouter->input_count + irqrouter->swirq_count;

This feels a bit like a hack, so suggestions are welcome.
----

Quoted 4 lines

drivers/irqchip/irq-tango_v4.c line 516

Quoted 2 lines
drivers/irqchip/irq-tango_v4.c new file +1 -0
+	else if (irq >= irqrouter->input_count)

That "else" is pointless. You return above.

Ok.

Quoted 11 lines

drivers/irqchip/irq-tango_v4.c line 523

Quoted 8 lines
drivers/irqchip/irq-tango_v4.c new file +7 -0
+		tango_set_swirq_enable(irqrouter,
+				       irq - irqrouter->input_count,
+				       enable);
+	else
+		tango_set_hwirq_enable(irqrouter,
+				       irq,
+				       enable);

This can be written way simpler.

Quoted 5 lines
     	if (irq >= irqrouter->input_count)
	   	irq -= irqrouter->input_count;
	tango_set_hwirq_enable(irqrouter, irq, enable);

Hmm?

Ok, but is it ok to modify function parameters? I thought it was not recommended.
Indeed, some people may assume they are constants.

Quoted 10 lines
Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +9 -0
+static int tango_set_irq_type(struct tango_irqrouter *irqrouter,
+			      int hwirq_in,
+			      u32 type,
+			      u32 parent_type)
+{
+	int err;
+
+	if (parent_type & (type & IRQ_TYPE_SENSE_MASK))
+		/* same polarity */
Quoted 9 lines

drivers/irqchip/irq-tango_v4.c line 576

Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+		err = tango_set_irq_inversion(irqrouter, hwirq_in, 0);
+	else
+		/* invert polarity */
+		err = tango_set_irq_inversion(irqrouter, hwirq_in, 1);
  	bool invert = parent_type & (type & IRQ_TYPE_SENSE_MASK);

  	err = tango_set_irq_inversion(irqrouter, hwirq_in, invert);	

Ok.

Quoted 5 lines
Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+
+	if (err < 0) {
+		DBGWARN("Failed to setup IRQ %d polarity\n", hwirq_in);
+		return err;
+	}
Quoted 9 lines

drivers/irqchip/irq-tango_v4.c line 586

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+
+	switch (type & IRQ_TYPE_SENSE_MASK) {
+	case IRQ_TYPE_EDGE_RISING:
+	case IRQ_TYPE_EDGE_FALLING:
+		DBGERR("Does not support edge triggers\n");

This really sucks. In fact you panic here while the code suggests that you print a DEBUG error and continue .....

If I use panic() here, do I still have to use 'break' as well?

Quoted 5 lines

drivers/irqchip/irq-tango_v4.c line 589

Quoted 3 lines
drivers/irqchip/irq-tango_v4.c new file +3 -0
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		break;

You can spare that break.

Ok.
(before there were logs so the 'break' was necessary)

Quoted 9 lines

drivers/irqchip/irq-tango_v4.c line 594

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+	case IRQ_TYPE_LEVEL_LOW:
+		break;
+	default:
+		DBGWARN("Invalid trigger mode 0x%x for hwirq(in) %d\n",
+			type, hwirq_in);

So here you continue with an error code, but above for EDGE you panic. I really don't get that logic.

Ok.
Do you suggest I just make the code panic for any error? I'm fine with that.

Quoted 11 lines
Quoted 11 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int tango_get_output_for_hwirq(struct tango_irqrouter *irqrouter,
+				      int hwirq_in,
+				      struct tango_irqrouter_output **out_val)
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 610

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+{
+	struct tango_irqrouter_output *irqrouter_output;
+	int i;
+
+	if (!out_val)
+		return -EINVAL;

This is utter crap. Look at the call site:

I think I'm confused, so it is not recommended to check for NULL pointers before dereferencing them? Regardless of how the current code calls the function?

Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 1075

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+	struct tango_irqrouter_output *irqrouter_output = NULL;
+
+	tango_get_output_for_hwirq(irqrouter, hwirq_in, &irqrouter_output);
+	if (!irqrouter_output)
+		goto handle_parent;

So out_val CANNOT be NULL.

You are right, with current code it can't.
But I thought that it was a good practice to:
"be lenient with your input and strict with your output"

Quoted 2 lines

What's the purpose of your return values if you
ignore them?

I can make the function 'void'.

Quoted 5 lines

drivers/irqchip/irq-tango_v4.c line 612

Quoted 3 lines
drivers/irqchip/irq-tango_v4.c new file +2 -0
+
+	/* Get the irqrouter_output for the hwirq */

This is another really helpful comment.

It is true that now that this is a function, the name of the function speaks for itself, so I can remove it.

Quoted 14 lines

drivers/irqchip/irq-tango_v4.c line 623

Quoted 12 lines
drivers/irqchip/irq-tango_v4.c new file +11 -0
+	for (i = 0; i < irqrouter->output_count; i++) {
+		int j;
+
+		irqrouter_output = &(irqrouter->output[i]);
+
+		for (j = 0; j < irqrouter_output->shared_count; j++) {
+			if (hwirq_in == irqrouter_output->shared_irqs[j])
+				goto found_router_output;
+		}
+	}
+	if (i == irqrouter->output_count) {

What other reason would be to get here than this?

You are right, relic of a refactoring.

Quoted 31 lines

drivers/irqchip/irq-tango_v4.c line 632

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +9 -0
+		DBGWARN("Couldn't find hwirq mapping\n");
+		return -ENODEV;
+	}
+
+found_router_output:
+
+	*out_val = irqrouter_output;
+	return 0;
+}

This whole thing can be condensed to:

static struct tango_irqrouter_output * tango_get_output_for_hwirq(struct tango_irqrouter *irqr, int hwirq_in)

{
	struct tango_irqrouter_output *rout;
	int i, j;

	/* Scan the outputs for a matching hwirq number */
	for (i = 0, rout = irqr->output; i < irqr->output_count; i++, rout++) {
		for (j = 0; j < rout->shared_count; j++) {
			if (rout->shared_irqs[j] == hwirq_in)
			   	return rout;
		}
	}
	return NULL;
}

And the call site would become:

Quoted 7 lines
    	struct tango_irqrouter_output *rout;

	rout = tango_get_output_for_hwirq(irqrouter, hwirq_in);
	if (!rout)
		goto handle_parent;

Hmm?

Ok.

Quoted 9 lines

drivers/irqchip/irq-tango_v4.c line 262

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+/* 'irqchip' handling callbacks
+ * Used for 'shared' IRQs, i.e.: IRQs that share a GIC input
+ * This driver performs the IRQ dispatch based on the flags
+ */
+

Multiline comments have this format:

Quoted 5 lines

/*
* First line
* ....
* Last line
*/

Ok.

Quoted 9 lines

drivers/irqchip/irq-tango_v4.c line 685

Quoted 7 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+static void tango_irqchip_mask_irq(struct irq_data *data)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+	int hwirq_in = (int)data->hwirq;

Huch? What's that silly typecast for? Why can't you use u32 for hwirq_in?

data->hwirq is of type irq_hw_number_t (unsigned long), I don't know if that can change in the future.

So do you think it is safe to use u32 for data->hwirq (and all other "irq" occurrences)?

Quoted 26 lines
Quoted 13 lines
drivers/irqchip/irq-tango_v4.c new file +11 -0
+	tango_set_irq_enable(irqrouter, hwirq_in, 0);
+}
 
+#ifdef CONFIG_SMP
+static int tango_irqchip_set_irq_affinity(struct irq_data *data,
+					  const struct cpumask *mask_val,
+					  bool force)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct irq_chip *parent_chip = irq_get_chip(irqrouter_output->virq);
+	struct irq_data *parent_data = irq_get_irq_data(irqrouter_output->virq);

drivers/irqchip/irq-tango_v4.c line 743

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+
+	DBGLOG("%s:%s(0x%p)\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)), domain->name, domain);
+
+	if (parent_chip && parent_chip->irq_set_affinity)
+		return parent_chip->irq_set_affinity(parent_data,
+						     mask_val,
+						     force);
+	else
+		return -EINVAL;

You really can spare identation levels by writing it a bit more clever:

Quoted 7 lines
    	if (!parent || !parent->irq_set_affinity)
	   	 return -EINVAL;

	return parent->irq_set_affinity(parent, mask, force);

You might notice that I shortened the variable names and it still is entirely clear what the code does.

Ok.

Quoted 2 lines

Aside of that mask_val is a clear misnomer.

Actually, this code comes from exynos-combiner.c and is part of the reason for question 4 of the RFC:

----
4) Do I have to do something more to handle the affinity stuff?
----

Quoted 14 lines

drivers/irqchip/irq-tango_v4.c line 754

Quoted 12 lines
drivers/irqchip/irq-tango_v4.c new file +11 -0
+}
+#endif
+
+
+static inline u32 tango_dispatch_irqs(struct irq_domain *domain,
+				      struct irq_desc *desc,
+				      u32 status,
+				      int base)
+{
+	u32 hwirq;
+	u32 virq;

Please put same types onto a single line

Ok.

Quoted 17 lines
Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +3 -0
+
+	while (status) {
+		hwirq = __ffs(status);

drivers/irqchip/irq-tango_v4.c line 767

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+		virq = irq_find_mapping(domain, base + hwirq);
+		if (unlikely(!virq))
+			handle_bad_irq(desc);
+		else
+			generic_handle_irq(virq);
+
+		status &= ~BIT(hwirq);
+	}
+
+	return status;

Huch? status is guaranteed to be 0 here. So what's the point of this return value.

You are right, relic of a refactoring.
I wanted to do:

+ if (unlikely(!virq))
+ handle_bad_irq(desc);
+ else {
+ generic_handle_irq(virq);
+ status_out &= ~BIT(hwirq);
+ }
+ status &= ~BIT(hwirq);

with status_out=status at the start of the function.

Quoted 19 lines
Quoted 19 lines
drivers/irqchip/irq-tango_v4.c new file +18 -0
+}
+
+static void tango_irqdomain_handle_cascade_irq(struct irq_desc *desc)
+{
+	struct irq_domain *domain = irq_desc_get_handler_data(desc);
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+	struct irq_chip *host_chip = irq_desc_get_chip(desc);
+	u32 i, status;
+	u32 swirq_status, irq_status[BITMASK_VECTOR_SIZE(ROUTER_INPUTS)];
+
+#if 0
+	DBGLOG("%s:%s(0x%p): irqrouter_output 0x%p, hwirq(out) %d\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)), domain->name, domain,
+	       irqrouter_output, irqrouter_output->hwirq);
+#endif
+
+	chained_irq_enter(host_chip, desc);
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 792

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+
+	raw_spin_lock(&(irqrouter->lock));
+	swirq_status = tango_readl(irqrouter, READ_SWIRQ_STATUS);
+	for (i = 0; i < BITMASK_VECTOR_SIZE(ROUTER_INPUTS); i++)
+		irq_status[i] = tango_readl(irqrouter,
+					    READ_SYS_IRQ_GROUP0 + i*4);

i * 4 please

Ok.

Quoted 7 lines

drivers/irqchip/irq-tango_v4.c line 795

Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +3 -0
+	raw_spin_unlock(&(irqrouter->lock));
+
+	/* HW irqs */

And that comment tells us what?

Quoted 14 lines

drivers/irqchip/irq-tango_v4.c line 806

Quoted 11 lines
drivers/irqchip/irq-tango_v4.c new file +11 -0
+	for (i = 0; i < BITMASK_VECTOR_SIZE(ROUTER_INPUTS); i++) {
+#if 0
+		DBGLOG("%d: 0x%08x (en 0x%08x, inv 0x%08x)\n",
+		       i,
+		       irq_status[i],
+		       irqrouter->irq_mask[0],
+		       irqrouter->irq_invert_mask[0]);
+#endif
+
+#define HANDLE_INVERTED_LINES(__irqstatus__, __x__) ((((~__irqstatus__) & irqrouter->irq_invert_mask[__x__]) & irqrouter->irq_mask[__x__]) | __irqstatus__)
+#define HANDLE_EN_AND_INV_MASKS(__irqstatus__, __y__) (HANDLE_INVERTED_LINES(__irqstatus__, __y__) & irqrouter->irq_mask[__y__])

What the hell does this unparseable macro mess? What's so wrong with a proper inline function?

Ok, I'll inline it.

Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 810

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+
+		irq_status[i] = HANDLE_EN_AND_INV_MASKS(irq_status[i], i);
+		status = tango_dispatch_irqs(domain, desc, irq_status[i], i*32);
+		if (status & irq_status[i])

Can you pretty please explain how this can happen? It can't. Because you clear every single bit of status in tango_dispatch_irqs(). See above.

You are right that with the current code of tango_dispatch_irqs() it cannot happen, but that's more of a typo. I wanted to have a way to print something from this driver in the event of unhandled IRQs.

Just to understand something, is leaving some debug or checks somehow not recommended?

Quoted 3 lines

Please clean up that unholy mess of nonsensical checks and debug code.

Ok.

Quoted 11 lines

drivers/irqchip/irq-tango_v4.c line 819

Quoted 9 lines
drivers/irqchip/irq-tango_v4.c new file +9 -0
+			DBGERR("%s: %d unhandled IRQs (as a mask) 0x%x\n",
+			       NODE_NAME(irq_domain_get_of_node(domain)),
+			       i,
+			       status & irq_status[i]);
+	}
+
+	/* SW irqs */
+	swirq_status &= irqrouter->swirq_mask;
+	status = tango_dispatch_irqs(domain, desc, swirq_status, 128);

128 is the magic number pulled out of thin air or what?

I will replace that with irqrouter->input_count.

Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 823

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+	if (status & swirq_status)
+		DBGERR("%s: Unhandled IRQs (as a mask) 0x%x\n",
+		       NODE_NAME(irq_domain_get_of_node(domain)),
+		       status & swirq_status);

See above.

Quoted 11 lines

drivers/irqchip/irq-tango_v4.c line 832

Quoted 9 lines
drivers/irqchip/irq-tango_v4.c new file +9 -0
+
+	chained_irq_exit(host_chip, desc);
+}
+
+
+/**
+ * tango_irqdomain_map - route a hwirq(in) to a hwirq(out).
+ * NOTE: The hwirq(out) must have been already allocated and enabled on
+ * the parent controller.

Please put notes AFTER the argument descriptions

The note refers to the title:
"tango_irqdomain_map - route a hwirq(in) to a hwirq(out)."

Quoted 10 lines
Quoted 6 lines

+ * @hwirq: HW IRQ of the device requesting an IRQ
+ * if hwirq > inputs it is a SW IRQ
+ * @virq: Linux IRQ (associated to the domain) to be given to the device
+ * @domain: IRQ domain (from the domain, we get the irqrouter_output
+ * in order to know to which output we need to route hwirq to)

And if you spend a few seconds to align this proper, then it becomes suddenly readable.

Quoted 7 lines

* @hwirq: HW IRQ of the device requesting an IRQ
* if hwirq > inputs it is a SW IRQ
* @virq: Linux IRQ (associated to the domain) to be given to the device
* @domain: IRQ domain (from the domain, we get the irqrouter_output
* in order to know to which output we need to route hwirq to)

Hmm?

Ok.

Quoted 48 lines
Quoted 34 lines

+ */

drivers/irqchip/irq-tango_v4.c new file +32 -0
+static int tango_irqdomain_map(struct irq_domain *domain,
+			       unsigned int virq,
+			       irq_hw_number_t hwirq)
+{
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+
+	DBGLOG("%s:%s(0x%p): hwirq(in) %d := virq %d, and route "
+	       "hwirq(in) %d => hwirq(out) %d (virq %d)\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),
+	       domain->name,
+	       domain,
+	       (u32)hwirq,
+	       virq,
+	       (u32)hwirq,
+	       irqrouter_output->hwirq,
+	       irqrouter_output->virq);
+
+	if (hwirq >= (irqrouter->input_count + irqrouter->swirq_count))
+		DBGERR("%s: Invalid hwirq(in) %d >= %d + %d\n",
+		       NODE_NAME(irq_domain_get_of_node(domain)),
+		       (u32)hwirq,
+		       irqrouter->input_count,
+		       irqrouter->swirq_count);
+	else if (hwirq >= irqrouter->input_count)
+		DBGLOG("Map swirq %ld\n", hwirq - irqrouter->input_count);
+
+	irq_set_chip_and_handler(virq,
+				 &tango_irq_chip_shared_ops,
+				 handle_level_irq);
+	irq_set_chip_data(virq, domain);
+	irq_set_probe(virq);

drivers/irqchip/irq-tango_v4.c line 880

Quoted 10 lines
drivers/irqchip/irq-tango_v4.c new file +10 -0
+
+	tango_set_irq_route(irqrouter, hwirq, irqrouter_output->hwirq);
+
+	return 0;
+}
+
+
+/**
+ * tango_irqdomain_translate - used to select the domain for a given
+ * irq_fwspec

It hardly selects the domain. @domain is handed in as a argument. And please get rid of that silly 'used to'. That just adds characters and no information.

Quoted 3 lines

- Select the router section for a firmware spec

Hmm?

Ok, maybe I did not express it correctly.
The callback is called from irqdomain.c:irq_find_matching_fwspec() and each domain is tested, if the callback returns non-zero, the current domain is considered a "match" for the fwspec and returned by irq_find_matching_fwspec().

Quoted 6 lines
Quoted 4 lines

+ * @domain: a registered domain
+ * @fwspec: an IRQ specification. This callback is used to translate the
+ * parameters given as irq_fwspec into a HW IRQ and Type values.

fwspec is a callback?

No, the sentence refers to the callback below (tango_irqdomain_translate) that is being described by this comment.
I can reformulate or remove the comment.

Quoted 5 lines
Quoted 3 lines

+ * @out_hwirq:
+ * @out_type:

Missing docs.....

Ok.

Quoted 21 lines
Quoted 21 lines

+ */

drivers/irqchip/irq-tango_v4.c new file +19 -0
+static int tango_irqdomain_translate(struct irq_domain *domain,
+				     struct irq_fwspec *fwspec,
+				     unsigned long *out_hwirq,
+				     unsigned int *out_type)
+{
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+	irq_hw_number_t irq;
+	u32 domain_id, type;
+	int err;
+
+	DBGLOG("%s:%s(0x%p): argc %d for hwirq(out) %d\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),
+	       domain->name,
+	       domain,
+	       fwspec->param_count,
+	       irqrouter_output->hwirq);
+
+	err = tango_parse_fwspec(domain,
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 909

Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+				 fwspec,
+				 &domain_id,
+				 &irq,
+				 &type);

Please use the full 80 characters. Your patch does not become more valuable when you inflate the line count. It's more valuable when it is easy to read and understand.

Ok.

As a side note, does the 80 characters limit still makes sense? I mean, I would imagine that anybody now is using wide screens capable of at least double that amount.

Quoted 14 lines
Quoted 14 lines
drivers/irqchip/irq-tango_v4.c new file +13 -0
+	if (err < 0) {
+		DBGWARN("Failed to parse fwspec\n");
+		return err;
+	}
+
+	switch (domain_id) {
+	case SIGMA_HWIRQ:
+		DBGLOG("Request is for SIGMA_HWIRQ\n");
+		break;
+	case SIGMA_SWIRQ:
+		DBGLOG("Request is for SIGMA_SWIRQ\n");
+		irq += irqrouter->input_count;
+		break;
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 926

Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+	default:
+		DBGLOG("Request is for domain ID 0x%x (we are 0x%x)\n",
+		       domain_id,
+		       irqrouter_output->domain_id);

Huch what? You only ever handle HW and SW irqs and now you happily proceed if the id is something else. Consistent error handling is optional and can be replaced by random debug prints, right?

You are right that this case should never happen as the 'select' callback must have replied correctly.
This is more of a relic when I did not had access to the 'select' callback. (I was working on 4.4)

Quoted 13 lines
Quoted 13 lines
drivers/irqchip/irq-tango_v4.c new file +12 -0
+		break;
+	};
+
+	*out_hwirq = irq;
+	*out_type  = type & IRQ_TYPE_SENSE_MASK;
+
+	DBGLOG("hwirq %d type 0x%x\n", (u32)*out_hwirq, (u32)*out_type);
+
+	return 0;
+}
+
+
Quoted 8 lines
Quoted 6 lines

+/**
+ * tango_irqdomain_select - used to select the domain for a given irq_fwspec
+ * @domain: a registered domain
+ * @fwspec: an IRQ specification. This callback should return zero if the
+ * irq_fwspec does not belong to the given domain. If it does, it should
+ * return non-zero.

Callback????

Ok.

Quoted 40 lines
Quoted 40 lines

+ * In practice it will return non-zero if the irq_fwspec matches one of the
+ * IRQs shared within the given domain.
+ * @bus_token: a bus token
+ */

drivers/irqchip/irq-tango_v4.c new file +35 -0
+static int tango_irqdomain_select(struct irq_domain *domain,
+				  struct irq_fwspec *fwspec,
+				  enum irq_domain_bus_token bus_token)
+{
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+	irq_hw_number_t irq;
+	u32 domain_id, type;
+	int err;
+
+	DBGLOG("%s:%s(0x%p): argc %d, 0x%p, bus 0x%x\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)), domain->name, domain,
+	       fwspec->param_count, fwspec->fwnode, bus_token);
+
+	DBGLOG("router 0x%p, output 0x%p\n", irqrouter, irqrouter_output);
+
+	err = tango_parse_fwspec(domain, fwspec, &domain_id, &irq, &type);
+	if (err < 0)
+		return 0;
+
+	switch (domain_id) {
+	case SIGMA_HWIRQ:
+		DBGLOG("Request is for SIGMA_HWIRQ\n");
+		break;
+	case SIGMA_SWIRQ:
+		DBGLOG("Request is for SIGMA_SWIRQ\n");
+		break;
+	default:
+		DBGLOG("Request is for domain ID 0x%x (we are 0x%x)\n",
+		       domain_id,
+		       irqrouter_output->domain_id);
+		break;
+	};
+
+	if (!irqrouter->implicit_groups) {
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 988

Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+		int i;
+
+		/* Check if the requested IRQ belongs to those listed
+		 * to be sharing the output assigned to this domain

Your using of 'domain' is utterly confusing. Please use something like hwdomain or whatever which makes it clear that this is something else than the irq domain. I tripped over this several times now.

Ok.

Quoted 83 lines
Quoted 83 lines
drivers/irqchip/irq-tango_v4.c new file +82 -0
+		 */
+		if (irqrouter_output->shared_count <= 0) {
+			DBGLOG("Not shared IRQ line?\n");
+			return 0;
+		}
+
+		for (i = 0; i < irqrouter_output->shared_count; i++) {
+			if (irq == irqrouter_output->shared_irqs[i]) {
+				DBGLOG("Match: IRQ %lu\n", irq);
+				return 1;
+			}
+		}
+	} else {
+		/* Otherwise, check if the domain_id given matches
+		 * the one assigned to this output
+		 */
+		if (domain_id == irqrouter_output->domain_id) {
+			DBGLOG("Match: Domain ID %d\n", domain_id);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+/* 'irqrouter' handling callbacks
+ * Used for 'direct' IRQs, i.e.: IRQs that are directly routed to the GIC
+ * This driver does not dispatch the IRQs, the GIC does.
+ */
+
+
+static void tango_irqrouter_mask_irq(struct irq_data *data)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter *irqrouter = domain->host_data;
+	int hwirq_in = (int)data->hwirq;
+
+	DBGLOG("%s:%s(0x%p) hwirq(in) %d\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),
+	       domain->name,
+	       domain,
+	       hwirq_in);
+
+	tango_set_irq_enable(irqrouter, hwirq_in, 0);
+
+	irq_chip_mask_parent(data);
+}
+
+
+static void tango_irqrouter_unmask_irq(struct irq_data *data)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter *irqrouter = domain->host_data;
+	int hwirq_in = (int)data->hwirq;
+
+	DBGLOG("%s:%s(0x%p) hwirq(in) %d\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),
+	       domain->name,
+	       domain,
+	       hwirq_in);
+
+	tango_set_irq_enable(irqrouter, hwirq_in, 1);
+
+	irq_chip_unmask_parent(data);
+}
+
+
+static int tango_irqrouter_set_irq_type(struct irq_data *data,
+					unsigned int type)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter_output *irqrouter_output = NULL;
+	struct tango_irqrouter *irqrouter = domain->host_data;
+	int hwirq_in = (int)data->hwirq;
+	u32 parent_type;
+
+	DBGLOG("%s:%s(0x%p) type 0x%x for hwirq(in) %d\n",
+	       NODE_NAME(irq_domain_get_of_node(domain)),
+	       domain->name,
+	       domain,
+	       type,
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 1075

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+	       hwirq_in);
+
+	tango_get_output_for_hwirq(irqrouter, hwirq_in, &irqrouter_output);
+	if (!irqrouter_output)
+		goto handle_parent;

So if there is no output, then you unconditionally set the type on the parent. If that's correct, this needs a big fat comment at least.

Ok.
This is related to question 2 of my RFC:

----
2) In order to get a virq mapping for the domains associated with the outputs (the outputs connected to the GIC) I request a sort of "Fake HW IRQ" See irq-tango_v4.c:1400

/* To request a virq we need a HW IRQ, use a "Fake HW IRQ" */ hwirq = index + irqrouter->input_count + irqrouter->swirq_count;

This feels a bit like a hack, so suggestions are welcome.
----

Indeed, this callback will be called once when requesting a "fake HW IRQ" so that alloc() callback is called and we get a free output (a GIC input) so that we can later route IRQs to it.
And another time when an actual HW IRQ is requested, in which case the tango_set_irq_type() needs to be called so that we can see if inversion needs to be implemented.

Actually, if I don't deal with inversion and consider there will never be mismatches between the level setup on the GIC input and that one of the device requesting the IRQ to be routed to said GIC input, then I could just use irq_chip_set_type_parent() as callback directly.

Quoted 11 lines

drivers/irqchip/irq-tango_v4.c line 1082

Quoted 7 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+	parent_type = (irqrouter_output->hwirq_level & IRQ_TYPE_SENSE_MASK);
+	tango_set_irq_type(irqrouter, hwirq_in, type, parent_type);
+
+handle_parent:
+	return irq_chip_set_type_parent(data, type);
+}

I'm stopping here. You can apply the above to the rest of the code as well.

Thanks again for your review.
Best regards,

Sebastian

#29 lore raw

Thomas already commented on some aspects of the code, so I'm not going to do another review (I'll do the next round).

Quoted 10 lines · Sebastian Frias

Hi Thomas,

Thanks for your comments.
I appreciate the time you dedicated to the review.
I will take your comments into account, in the meanwhile, and since this was a RFC, would it be possible to also get some feedback/comments from a conceptual point of view?

I'm copy/pasting some of the questions I attached to the RFC email here:

Quoted 7 lines

----
2) In order to get a virq mapping for the domains associated with the outputs (the outputs connected to the GIC) I request a sort of "Fake HW IRQ" See irq-tango_v4.c:1400

	/* To request a virq we need a HW IRQ, use a "Fake HW IRQ" */
	hwirq      = index + irqrouter->input_count + irqrouter->swirq_count;

Why are you even trying to establish a route from a made up interrupt to a GIC line as the driver is just creating domains? Haven't you realized that everything gets created on demand, as DT interrupt specifiers gets parsed?

So the only time where you create a irq_fwspec out of thin air is when you actually allocate *one* interrupt. And that's the only time. You don't pre-populate stuff, you don't pre-allocate stuff.

Quoted 1 line

This feels a bit like a hack, so suggestions are welcome.

Just look at all the existing drivers in the tree that use stacked domains. They are all based on the same template. At least try and follow it.

Quoted 7 lines

3) The file is called 'irq-tango_v4.c' but I think it should match the compatible string, so I was thinking of renaming:
irq-tango_v4.c => irq-sigma_smp_irqrouter.c
irq-tango_v4.h => irq-sigma_smp_irqrouter.h

What do you think?

And why should it match? Am I going to rename the GIC driver to be "arm,gic-400_or_arm,arm11mp-gic_or_arm,arm1176jzf-devchip-gic_or_...c"?

No.

Quoted 5 lines

4) Do I have to do something more to handle the affinity stuff?

6) More of a theoretical question:
I have to #include <dt-bindings/interrupt-controller/irq-tango_v4.h> from

No you don't. This is for DT people to play with, and I don't care about it in the irqchip code.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#30 lore raw
In reply to Sebastian Frias
Quoted 9 lines · Sebastian Frias

----
2) In order to get a virq mapping for the domains associated with the outputs (the outputs connected to the GIC) I request a sort of "Fake HW IRQ" See irq-tango_v4.c:1400

	/* To request a virq we need a HW IRQ, use a "Fake HW IRQ" */
	hwirq      = index + irqrouter->input_count + irqrouter->swirq_count;

This feels a bit like a hack, so suggestions are welcome.

Well, look at it from the hardware level

                  |----------------|
		  |               0|---- Device irqs
	 	  |               1|----
 |----------| 	  |               2|----
 |       0  |-----|               3|----
 |       1  |-----|    Router     .|----
 |   GIC ...|-----|               .|----
 |       N  |-----|               .|----
 |----------|	  |               .|----
 		  |               .|----
		  |               X|----
                  |----------------|

So you have X hardware irqs in your router chip and the GIC has N. When an interrupt is created then we

- allocate the virq number
- associate the hwirq number of the router (input side)
- route it to a hwirq number of the GIC (output side)

So what kind of magic numbers do you need for that? I don't see any.

The only information which is interesting is whether the router output is shared between several router inputs or not because that might short cut interrupt handling. Though you can start with the simple assumption that every output is shared. That's a few cpu cycles overhead in the irq delivery path, but a great simplification of the code in the first place.

Your device tree describes

1) the association of the device irq to the router irq
2) the routing between router input and output

#1 is standard device tree magic

#2 is a property of your router irq chip

There is no requirement to describe all routes, you can limit it to those routes which you want to be exclusive. The rest can be assigned automatically.

Pseuso code:

	#define ROUTE_NONE	0xFFFFFFFF

	struct router {
		u32	routes[NR_INPUTS];
		bool	exclusive[NR_OUTPUTS];
		u32	nextout;
	};

init()

	struct router *router = kzalloc(sizeof(*router));

	/* Clear all routes */
	memset(router->routes, 0xFF, sizeof(router->routes);

	/* Scan device tree entries */
	for (info = node_get_next_route(node); info; ) {
		/* TODO: Sanity check info->in and info->out */
		router->routes[info->in] = info->out;
		router->exclusive[info->out] = true;
		info = node_get_next_route(node);
	}

interrupt setup()

	/*
	 * We get the hwirq of the router input	in the DT/FW descriptor.
	 * Check whether the interrupt is routed by DT or should be
	 * assigned a route dynamically.
	 */
	if (router->routes[hwirq] != ROUTE_NONE) {
		outirq = router->routes[hwirq];		   
	} else {
		/*
		 * Try to find the next non exclusive output
		 */
		outirq = router->nextout;
		while (router->exclusive[outirq]) {
			outirq++;
			if (outirq == NR_OUTPUTS)
				outirq = 0;
			if (outirq == router->nextout)
				return -ENOSPC;
		}
		router->nextout = outirq + 1;
		if (router->nextout == NR_OUTPUTS)
			router->nextout = 0;

}

	/* Do the magic hardware initialization .... */

Hmm?

Quoted 6 lines

3) The file is called 'irq-tango_v4.c' but I think it should match the compatible string, so I was thinking of renaming:
irq-tango_v4.c => irq-sigma_smp_irqrouter.c
irq-tango_v4.h => irq-sigma_smp_irqrouter.h

What do you think?

That's the least of my worries as long as the filename is unique and can be associated to the hardware in a sensible way.

Quoted 1 line

4) Do I have to do something more to handle the affinity stuff?

Well, I have no idea how your hardware works, but I assume that the affinity is solely handled by the GIC. So delegating the affinity setting to the GIC is all you can do.

Quoted 9 lines

6) More of a theoretical question:
I have to #include <dt-bindings/interrupt-controller/irq-tango_v4.h> from code that is not in the Linux tree. That's fine for now, but if in the future there are other irq controllers and another header is required, how can the code know which header to #include ?
Are we supposed to #include all of them, and then somehow detect which module is actually active and act accordingly? If so, can we detect which module matched and probed correctly to know which controller version we need to talk to?

-ENOPARSE

Quoted 11 lines

What the driver does is:
- creates a domain hierarchy attached to its parent domain (the GIC)
- the callbacks for this domain hierarchy will be used to deal with IRQs "directly" routed to the GIC (i.e.: exclusive IRQ lines routed to the GIC and not shared).
In this case the GIC dispatches the interrupts.
- create linear domains attached to this driver's node.
- the callbacks for these linear domains will be used to deal with shared IRQs (they share the routing to one of the GIC inputs).
In this case this driver dispatches the interrupts after reading the flags.

Quoted 3 lines

It is such concept, and then its implementation, that I would need some more advise with, because, as stated in the questions above, it still does not feels right, especially question 2.

The non shared case is merily an optimization of the shared case, but I recommend to omit it for now and just deal with a very straight forward implementation of the recommendation I outlined above. Making the non-shared case special is simple once you got the above right.

Quoted 9 lines
Quoted 4 lines
Quoted 1 line

+#if 0

Don't even think about posting code with "#if 0" or such in it.

The idea behind these macros was:
- to easily enable/disable them.
- to be more consistent with other code written at Sigma: this is a Sigma-only driver.

I don't care about Sigmas coding habits. This is kernel code and not Sigma-only playground.

Quoted 3 lines
Quoted 1 line

pr_debug() is there for a reason.

Yes, but doesn't pr_debug() requires changes to the Makefile?

# git grep pr_debug Documentation/
Quoted 9 lines
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 139

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+#if 0
+#define SHORT_OR_FULL_NAME full_name
+#else
+#define SHORT_OR_FULL_NAME name
+#endif

Use one and be done with it. Really.

Quoted 3 lines

By making the choice explicit, the person reading/debugging is aware of the possibilities. Picking "full_name" or "name" would likely prevent the person from knowing it has other debug options.

This does prevent absolutely nothing. Random #if 0 all over the place is a nightmare and nothing else. And what do you win by printing one or the other name? Absolutely nothing, really. Again, it might be Sigmas way to obfuscate code and at the same time claiming that it makes it better to read/debug, but that choice of coding style/habits have absolutely no place in proper kernel code.

Quoted 8 lines
Quoted 6 lines

drivers/irqchip/irq-tango_v4.c line 142

Quoted 3 lines
drivers/irqchip/irq-tango_v4.c new file +3 -0
+
+#define NODE_NAME(__node__) (__node__ ? __node__->SHORT_OR_FULL_NAME :	\
+			     "<no-node>")

Sigh. pr_xxx("%s", NULL) prints <null>. That's really sufficient for your debug/error handling.

The code is checking for __node__ to be non-NULL before dereferencing it.

pr_xxx("%s", node->name ? node->name: NULL)

What's wrong with explicitely writing stuff into the code where people can see it instead of obfuscating everything with gazillion of macros.

Quoted 10 lines
Quoted 9 lines

drivers/irqchip/irq-tango_v4.c line 349

Quoted 7 lines
drivers/irqchip/irq-tango_v4.c new file +7 -0
+static inline u32 tango_readl(struct tango_irqrouter *irqrouter,
+			      int reg)
+{
+	u32 val = readl_relaxed(irqrouter->base + reg);
+	/*DBGLOG("r[0x%08x + 0x%08x = 0x%08x] = 0x%08x\n",
+	  irqrouter->base, reg, irqrouter->base + reg, val);*/
+	return val;

Please get rid of this debug nonsense.

Quoted 2 lines

Ok, although I can guarantee it was really useful to determine and prove that the HW documentation of the module was wrong...

That's fine. But that commented out stuff has no place in proper code. Use pr_debug() if you really think that this information is valuable for debugging beyond the initial experimentation. If it's of no use for the daily trouble shooting with users, get rid of it.

Quoted 10 lines
Quoted 7 lines

drivers/irqchip/irq-tango_v4.c line 367

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+static inline void tango_set_swirq_enable(struct tango_irqrouter *irqrouter,
+					  int swirq,
+					  bool enable)
+{
+	u32 offset = SWIRQ_ENABLE;

If you name that varible 'reg' then it becomes obvious what it does.

Well, it was to add a sort of "consistency" between the code for SW IRQs and HW IRQs.

You try to force different things into the same implementation, which is always a bad sign.

Quoted 15 lines
Quoted 6 lines
(quoted diff) +1 -0
+	u32 value = tango_readl(irqrouter, offset);
Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+	u32 swirq_bit_index = swirq % SWIRQ_COUNT;
+
+#if 1
+	DBGLOG("%smask swirq(in) %d : current regvalue 0x%x\n",
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 378

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+	       enable ? "un":"",
+	       swirq, value);
+#endif
+
+	if (enable) {
+		/* unmask swirq */

The whole code lacks comments, but here you document the obvious ....

Quoted 1 line

I will remove the comments.

Instead of just removing the comments, please add comments where the stuff is non obvious.

Quoted 12 lines
Quoted 11 lines

drivers/irqchip/irq-tango_v4.c line 429

Quoted 9 lines
drivers/irqchip/irq-tango_v4.c new file +9 -0
+static inline void tango_set_swirq_inversion(struct tango_irqrouter *irqrouter,
+					     int swirq,
+					     bool invert)
+{
+
+	DBGLOG("swirq(in) %d %s inverted\n", swirq, invert ? "":"not");
+
+	if (invert)
+		DBGERR("SW IRQs cannot be inverted!\n");

Groan.

Quoted 1 line

I rather keep this to catch typos in code requesting SW IRQs.

Come on. Is that coding kindergarden or what?

Quoted 5 lines
Quoted 3 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+	if (irq_out < 0) {

This logic is utterly confusing, really. What's a negative interrupt number?

It is a sort of "magic value" to disable the IRQ and the routing.

And of course completely undocumented. Again you try to implement stuff which should be seperate into a single implementation and end up with an unreadable and therefor unmaintainable mess.

Quoted 8 lines
Quoted 5 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+	} else
  } else {

please

I think I'm confused, we need to use {} for single statements on "else" blocks, but not on "for" blocks?

      for (i = 0; i < MAX; i++)
      	  do_stuff(i);

      for (i = 0; i < MAX; i++) {
      	  do_stuff(i);
	  do_more_stuff(i);
      }

      if (bla < MAX)
      	   do_stuff(bla);
      else
	   do_something_else(bla);

      if (bla < MAX) {
      	   do_stuff(bla);
	   do_more_stuff(bla);
      } else {
	   do_something_else(bla);
	   do_more_stuff(bla);
      }

      if (bla < MAX) {
      	   do_stuff(bla);
	   do_more_stuff(bla);
      } else {
	   do_something_else(bla);
      }

      if (bla < MAX) {
      	   do_stuff(bla);
      } else {
	   do_something_else(bla);
	   do_more_stuff(bla);
      }

Now compare that to:

      if (bla < MAX)
      	   do_stuff(bla);
      else {
	   do_something_else(bla);
	   do_more_stuff(bla);
      }

It's harder to parse simply because the 'else {' is assymetric. Ditto for

      if (bla < MAX) {
      	   do_stuff(bla);
	   do_more_stuff(bla);
      } else
	   do_something_else(bla);

Ok?

Quoted 10 lines
Quoted 6 lines

drivers/irqchip/irq-tango_v4.c line 501

Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+	if (irq_out < 0) {
+		tango_set_irq_enable(irqrouter,
+				     irq_in,
+				     0);

This fits in a single line.

Ok.
Actually, I was wondering if for consistency it wouldn't be better if all function calls had one argument per line?

Err no. You waste precious vertical space and therefor context.

Quoted 16 lines
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 515

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+static inline int tango_set_irq_enable(struct tango_irqrouter *irqrouter,
+				       int irq,
+				       bool enable)
+{
+	if (irq >= (irqrouter->input_count + irqrouter->swirq_count))
+		return -EINVAL;

How can that happen? Paranoia programming?

No, actually it can happen, that's the reason for question 2 of my RFC:

----
2) In order to get a virq mapping for the domains associated with the outputs (the outputs connected to the GIC) I request a sort of "Fake HW IRQ" See irq-tango_v4.c:1400

Quoted 4 lines

/* To request a virq we need a HW IRQ, use a "Fake HW IRQ" */ hwirq = index + irqrouter->input_count + irqrouter->swirq_count;

This feels a bit like a hack, so suggestions are welcome.

It is a hack. See above.

Quoted 11 lines
Quoted 7 lines

This can be written way simpler.

     	if (irq >= irqrouter->input_count)
	   	irq -= irqrouter->input_count;
	tango_set_hwirq_enable(irqrouter, irq, enable);

Hmm?

Ok, but is it ok to modify function parameters? I thought it was not recommended.
Indeed, some people may assume they are constants.

They are only constant when they have a const qualifier in the function prototype. Random assumptions of random people are irrelevant. You can use an intermediate local variable and do the above if that makes you feel better. That still will be way better readable and understandable code.

Quoted 15 lines
Quoted 5 lines
Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+
+	if (err < 0) {
+		DBGWARN("Failed to setup IRQ %d polarity\n", hwirq_in);
+		return err;
+	}
Quoted 9 lines

drivers/irqchip/irq-tango_v4.c line 586

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+
+	switch (type & IRQ_TYPE_SENSE_MASK) {
+	case IRQ_TYPE_EDGE_RISING:
+	case IRQ_TYPE_EDGE_FALLING:
+		DBGERR("Does not support edge triggers\n");

This really sucks. In fact you panic here while the code suggests that you print a DEBUG error and continue .....

Quoted 1 line

If I use panic() here, do I still have to use 'break' as well?

It does not matter much.

Quoted 9 lines
Quoted 6 lines

drivers/irqchip/irq-tango_v4.c line 594

Quoted 3 lines
drivers/irqchip/irq-tango_v4.c new file +3 -0
+	default:
+		DBGWARN("Invalid trigger mode 0x%x for hwirq(in) %d\n",
+			type, hwirq_in);

So here you continue with an error code, but above for EDGE you panic. I really don't get that logic.

Ok.
Do you suggest I just make the code panic for any error? I'm fine with that.

I ask for consistent handling. Either you always panic or you try to handle all errors gracefully. I prefer the latter because if it's not a essential interrupt then you still have the chance to retrieve debug info.

panic or BUG() are the last resort when there is no way to keep the machine alive and any action would perhaps cause even more fatal problems. That's hardly the case when an interrupt cannot be set up.

Quoted 8 lines
Quoted 4 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+	if (!out_val)
+		return -EINVAL;

This is utter crap. Look at the call site:

I think I'm confused, so it is not recommended to check for NULL pointers before dereferencing them? Regardless of how the current code calls the function?

There is nothing wrong with defensive programming, but just adding checks to every function bloats the code for no value. If you have a helper with a single callsite, then such a check is just pointless and only there to make you feel good or whatever. Global functions which can be called by random code certainly want to have such checks, but then the callers are also required to check the return values.

Quoted 9 lines
Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 1075

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+	struct tango_irqrouter_output *irqrouter_output = NULL;
+
+	tango_get_output_for_hwirq(irqrouter, hwirq_in, &irqrouter_output);
+	if (!irqrouter_output)
+		goto handle_parent;

So out_val CANNOT be NULL.

Quoted 3 lines

You are right, with current code it can't.
But I thought that it was a good practice to:
"be lenient with your input and strict with your output"

See above.

Quoted 4 lines
Quoted 2 lines

What's the purpose of your return values if you
ignore them?

I can make the function 'void'.

I made you a proposal for a useful replacement of that thing. See below.

Quoted 39 lines
Quoted 20 lines

This whole thing can be condensed to:

static struct tango_irqrouter_output * tango_get_output_for_hwirq(struct tango_irqrouter *irqr, int hwirq_in)

{
	struct tango_irqrouter_output *rout;
	int i, j;

	/* Scan the outputs for a matching hwirq number */
	for (i = 0, rout = irqr->output; i < irqr->output_count; i++, rout++) {
		for (j = 0; j < rout->shared_count; j++) {
			if (rout->shared_irqs[j] == hwirq_in)
			   	return rout;
		}
	}
	return NULL;
}

And the call site would become:

Quoted 7 lines
    	struct tango_irqrouter_output *rout;

	rout = tango_get_output_for_hwirq(irqrouter, hwirq_in);
	if (!rout)
		goto handle_parent;

Hmm?

Ok.

Quoted 8 lines

drivers/irqchip/irq-tango_v4.c line 685

Quoted 6 lines
drivers/irqchip/irq-tango_v4.c new file +6 -0
+static void tango_irqchip_mask_irq(struct irq_data *data)
+{
+	struct irq_domain *domain = irq_data_get_irq_chip_data(data);
+	struct tango_irqrouter_output *irqrouter_output = domain->host_data;
+	struct tango_irqrouter *irqrouter = irqrouter_output->context;
+	int hwirq_in = (int)data->hwirq;

Huch? What's that silly typecast for? Why can't you use u32 for hwirq_in?

Quoted 2 lines

data->hwirq is of type irq_hw_number_t (unsigned long), I don't know if that can change in the future.

And because something might change in the future you slap a type cast on it. Which will nicely prevent a compiler warning when the conversion after the change is crap.

No. We only do type casts when there is a real reason and not something like 'might change in the future'.

Guess what happens if we change data->hwirq to be a pointer? Your typecast still works ....

Quoted 2 lines

So do you think it is safe to use u32 for data->hwirq (and all other "irq" occurrences)?

If your hwirq numbers are not going to exceed 2^32 ....

Quoted 4 lines
Quoted 2 lines

Aside of that mask_val is a clear misnomer.

Actually, this code comes from exynos-combiner.c and is part of the reason for

Copy and paste is not an excuse for bad code.

Quoted 6 lines
Quoted 5 lines
Quoted 4 lines
drivers/irqchip/irq-tango_v4.c new file +4 -0
+
+		irq_status[i] = HANDLE_EN_AND_INV_MASKS(irq_status[i], i);
+		status = tango_dispatch_irqs(domain, desc, irq_status[i], i*32);
+		if (status & irq_status[i])
Quoted 6 lines
Quoted 2 lines

Can you pretty please explain how this can happen? It can't. Because you clear every single bit of status in tango_dispatch_irqs(). See above.

You are right that with the current code of tango_dispatch_irqs() it cannot happen, but that's more of a typo. I wanted to have a way to print something from this driver in the event of unhandled IRQs.

That's the fricking wrong place. If the dispatcher cannot handle an irq then the dispatcher should issue the printout, not some random call site.

Quoted 9 lines
Quoted 6 lines
Quoted 4 lines

+/**
+ * tango_irqdomain_map - route a hwirq(in) to a hwirq(out).
+ * NOTE: The hwirq(out) must have been already allocated and enabled on
+ * the parent controller.

Please put notes AFTER the argument descriptions

The note refers to the title:
"tango_irqdomain_map - route a hwirq(in) to a hwirq(out)."

That does not make the comment a valid kernel doc comment. Format is:

/**
* function_name - Short function description
* @arg1: Description of arg1
* @argument2: Description of argument2
*
* Long description of the function including return values. */

Hint. You can build the kerneldoc stuff. It will tell you what's wrong.

Quoted 9 lines
Quoted 5 lines
Quoted 3 lines

+ * @domain: a registered domain
+ * @fwspec: an IRQ specification. This callback is used to translate the
+ * parameters given as irq_fwspec into a HW IRQ and Type values.

fwspec is a callback?

No, the sentence refers to the callback below (tango_irqdomain_translate) that is being described by this comment.
I can reformulate or remove the comment.

Please do not remove useful comments. Make them proper.

Quoted 10 lines
Quoted 9 lines

drivers/irqchip/irq-tango_v4.c line 909

Quoted 5 lines
drivers/irqchip/irq-tango_v4.c new file +5 -0
+	err = tango_parse_fwspec(domain,
+				 fwspec,
+				 &domain_id,
+				 &irq,
+				 &type);

Please use the full 80 characters. Your patch does not become more valuable when you inflate the line count. It's more valuable when it is easy to read and understand.

Quoted 5 lines

Ok.

As a side note, does the 80 characters limit still makes sense? I mean, I would imagine that anybody now is using wide screens capable of at least double that amount.

That's horrible. Did you ever think about why stuff is printed in columns or the width is restricted?

There is a very simple reason: Your eyes cannot parse wide printed lines fast without moving the focus while you can scan a limited width in one go.

Quoted 2 lines

This is more of a relic when I did not had access to the 'select' callback. (I was working on 4.4)

Please remove relics. They are just a burden for review and they will confuse the hell out of you 3 month from now.

Thanks,

tglx

#31 lore raw
In reply to Sebastian Frias
Quoted 1 line · Sebastian Frias

I don't think there's supposed to be an empty line at the beginning of the patch. I don't know whether 'git am' knows to zap the spurious line.

Quoted 6 lines

3) The file is called 'irq-tango_v4.c' but I think it should match the compatible string, so I was thinking of renaming:
irq-tango_v4.c => irq-sigma_smp_irqrouter.c
irq-tango_v4.h => irq-sigma_smp_irqrouter.h

What do you think?

Why is the file called irq-tango_v4? Why v4?
This is the second incarnation of a tango IRQ controller (that I know of). Why not -v2 then?

(Could you please not mix dash and underscore? Use one or the other consistently.)

Quoted 5 lines

5) checkpatch.pl reports a few warnings:

- WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? I have not changed the file because I would like to be settled on the naming first (see point 2 above)

I now have a regex pattern that matches "tango" in MAINTAINERS. However, checkpatch only checks the current patch, not the existing MAINTAINERS file.

Quoted 1 line
 .../interrupt-controller/sigma,smp,irqrouter.txt   |  135 ++

We've managed to use "tango" everywhere consistently (so far), please let's not introduce the "smp" terminology at this point, it will only confuse matters. (I use "smp87xy" to name specific boards, tango for the architecture/family.)

I found only one occurrence of the "a,b,c" syntax

$ find Documentation/devicetree/bindings -name "*,*,*"
Documentation/devicetree/bindings/net/wireless/ti,wlcore,spi.txt

Maybe we need to discuss this with the devicetree folks.

Note: Mans created Documentation/devicetree/bindings/interrupt-controller/sigma,smp8642-intc.txt for the v1 intc driver.

Quoted 2 lines

+Required properties:
+- compatible: Should be "sigma,smp,irqrouter".

You said in a previous message that you wanted to use a generic name.

AFAIU, the current DT trend is the opposite: to use the name of the first board (chronologically) that used that HW incarnation.
So that would be "sigma,smp87xx-intc"
(We can fill the xx when the weenies in marketing finally decide to announce the chip.)

The generic names you cited, like xhci, are actually naming a protocol, which many controllers implement (because it is standard).

Quoted 2 lines

+/*
+ * Copyright (C) 2014 Sebastian Frias <[email protected]>

Having discussed this topic with Thibaud, I think it is better to use "official" email addresses for kernel submissions.

Regards.