Skip to content

Commit

Permalink
of/irq: create interrupts-extended property
Browse files Browse the repository at this point in the history
The standard interrupts property in device tree can only handle
interrupts coming from a single interrupt parent. If a device is wired
to multiple interrupt controllers, then it needs to be attached to a
node with an interrupt-map property to demux the interrupt specifiers
which is confusing. It would be a lot easier if there was a form of the
interrupts property that allows for a separate interrupt phandle for
each interrupt specifier.

This patch does exactly that by creating a new interrupts-extended
property which reuses the phandle+arguments pattern used by GPIOs and
other core bindings.

Signed-off-by: Grant Likely <[email protected]>
Acked-by: Tony Lindgren <[email protected]>
Acked-by: Kumar Gala <[email protected]>
[grant.likely: removed versatile platform hunks into separate patch]
Cc: Rob Herring <[email protected]>
  • Loading branch information
glikely committed Oct 28, 2013
1 parent f27446c commit 79d9701
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,33 @@ Specifying interrupt information for devices
1) Interrupt client nodes
-------------------------

Nodes that describe devices which generate interrupts must contain an
"interrupts" property. This property must contain a list of interrupt
specifiers, one per output interrupt. The format of the interrupt specifier is
determined by the interrupt controller to which the interrupts are routed; see
section 2 below for details.
Nodes that describe devices which generate interrupts must contain an either an
"interrupts" property or an "interrupts-extended" property. These properties
contain a list of interrupt specifiers, one per output interrupt. The format of
the interrupt specifier is determined by the interrupt controller to which the
interrupts are routed; see section 2 below for details.

Example:
interrupt-parent = <&intc1>;
interrupts = <5 0>, <6 0>;

The "interrupt-parent" property is used to specify the controller to which
interrupts are routed and contains a single phandle referring to the interrupt
controller node. This property is inherited, so it may be specified in an
interrupt client node or in any of its parent nodes.
interrupt client node or in any of its parent nodes. Interrupts listed in the
"interrupts" property are always in reference to the node's interrupt parent.

The "interrupts-extended" property is a special form for use when a node needs
to reference multiple interrupt parents. Each entry in this property contains
both the parent phandle and the interrupt specifier. "interrupts-extended"
should only be used when a device has multiple interrupt parents.

Example:
interrupts-extended = <&intc1 5 1>, <&intc2 1 0>;

A device node may contain either "interrupts" or "interrupts-extended", but not
both. If both properties are present, then the operating system should log an
error and use only the data in "interrupts".

2) Interrupt controller nodes
-----------------------------
Expand Down
16 changes: 16 additions & 0 deletions arch/arm/boot/dts/testcases/tests-interrupts.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
<4 &test_intc2 15 16>;
};

test_intmap1: intmap1 {
#interrupt-cells = <2>;
#address-cells = <0>;
interrupt-map = <1 2 &test_intc0 15>;
};

interrupts0 {
interrupt-parent = <&test_intc0>;
interrupts = <1>, <2>, <3>, <4>;
Expand All @@ -36,6 +42,16 @@
interrupt-parent = <&test_intmap0>;
interrupts = <1>, <2>, <3>, <4>;
};

interrupts-extended0 {
interrupts-extended = <&test_intc0 1>,
<&test_intc1 2 3 4>,
<&test_intc2 5 6>,
<&test_intmap0 1>,
<&test_intmap0 2>,
<&test_intmap0 3>,
<&test_intmap1 1 2>;
};
};
};
};
16 changes: 11 additions & 5 deletions drivers/of/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,17 +292,23 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
return of_irq_parse_oldworld(device, index, out_irq);

/* Get the reg property (if any) */
addr = of_get_property(device, "reg", NULL);

/* Get the interrupts property */
intspec = of_get_property(device, "interrupts", &intlen);
if (intspec == NULL)
return -EINVAL;
if (intspec == NULL) {
/* Try the new-style interrupts-extended */
res = of_parse_phandle_with_args(device, "interrupts-extended",
"#interrupt-cells", index, out_irq);
if (res)
return -EINVAL;
return of_irq_parse_raw(addr, out_irq);
}
intlen /= sizeof(*intspec);

pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);

/* Get the reg property (if any) */
addr = of_get_property(device, "reg", NULL);

/* Look for the interrupt parent. */
p = of_irq_find_parent(device);
if (p == NULL)
Expand Down
70 changes: 70 additions & 0 deletions drivers/of/selftest.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,75 @@ static void __init of_selftest_parse_interrupts(void)
of_node_put(np);
}

static void __init of_selftest_parse_interrupts_extended(void)
{
struct device_node *np;
struct of_phandle_args args;
int i, rc;

np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0");
if (!np) {
pr_err("missing testcase data\n");
return;
}

for (i = 0; i < 7; i++) {
bool passed = true;
rc = of_irq_parse_one(np, i, &args);

/* Test the values from tests-phandle.dtsi */
switch (i) {
case 0:
passed &= !rc;
passed &= (args.args_count == 1);
passed &= (args.args[0] == 1);
break;
case 1:
passed &= !rc;
passed &= (args.args_count == 3);
passed &= (args.args[0] == 2);
passed &= (args.args[1] == 3);
passed &= (args.args[2] == 4);
break;
case 2:
passed &= !rc;
passed &= (args.args_count == 2);
passed &= (args.args[0] == 5);
passed &= (args.args[1] == 6);
break;
case 3:
passed &= !rc;
passed &= (args.args_count == 1);
passed &= (args.args[0] == 9);
break;
case 4:
passed &= !rc;
passed &= (args.args_count == 3);
passed &= (args.args[0] == 10);
passed &= (args.args[1] == 11);
passed &= (args.args[2] == 12);
break;
case 5:
passed &= !rc;
passed &= (args.args_count == 2);
passed &= (args.args[0] == 13);
passed &= (args.args[1] == 14);
break;
case 6:
passed &= !rc;
passed &= (args.args_count == 1);
passed &= (args.args[0] == 15);
break;
default:
passed = false;
}

selftest(passed, "index %i - data error on node %s rc=%i\n",
i, args.np->full_name, rc);
}
of_node_put(np);
}

static int __init of_selftest(void)
{
struct device_node *np;
Expand All @@ -246,6 +315,7 @@ static int __init of_selftest(void)
of_selftest_parse_phandle_with_args();
of_selftest_property_match_string();
of_selftest_parse_interrupts();
of_selftest_parse_interrupts_extended();
pr_info("end of selftest - %i passed, %i failed\n",
selftest_results.passed, selftest_results.failed);
return 0;
Expand Down

0 comments on commit 79d9701

Please sign in to comment.