Commit 51214520 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'devicetree-fixes-for-6.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux

Pull devicetree fixes from Rob Herring:

 - Fix regression in 'interrupt-map' handling affecting Apple M1 mini
   (at least)

 - Fix binding example warning in stm32 st,mlahb binding

 - Fix schema error in Allwinner platform binding causing lots of
   spurious warnings

 - Add missing MODULE_DESCRIPTION() to DT kunit tests

* tag 'devicetree-fixes-for-6.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux:
  of: property: Fix fw_devlink handling of interrupt-map
  of/irq: Factor out parsing of interrupt-map parent phandle+args from of_irq_parse_raw()
  dt-bindings: arm: stm32: st,mlahb: Drop spurious "reg" property from example
  dt-bindings: arm: sunxi: Fix incorrect '-' usage
  of: of_test: add MODULE_DESCRIPTION()
parents 32f88d65 e7985f43
...@@ -54,11 +54,10 @@ unevaluatedProperties: false ...@@ -54,11 +54,10 @@ unevaluatedProperties: false
examples: examples:
- | - |
mlahb: ahb@38000000 { ahb {
compatible = "st,mlahb", "simple-bus"; compatible = "st,mlahb", "simple-bus";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
reg = <0x10000000 0x40000>;
ranges; ranges;
dma-ranges = <0x00000000 0x38000000 0x10000>, dma-ranges = <0x00000000 0x38000000 0x10000>,
<0x10000000 0x10000000 0x60000>, <0x10000000 0x10000000 0x60000>,
......
...@@ -57,17 +57,17 @@ properties: ...@@ -57,17 +57,17 @@ properties:
- const: allwinner,sun8i-v3s - const: allwinner,sun8i-v3s
- description: Anbernic RG35XX (2024) - description: Anbernic RG35XX (2024)
- items: items:
- const: anbernic,rg35xx-2024 - const: anbernic,rg35xx-2024
- const: allwinner,sun50i-h700 - const: allwinner,sun50i-h700
- description: Anbernic RG35XX Plus - description: Anbernic RG35XX Plus
- items: items:
- const: anbernic,rg35xx-plus - const: anbernic,rg35xx-plus
- const: allwinner,sun50i-h700 - const: allwinner,sun50i-h700
- description: Anbernic RG35XX H - description: Anbernic RG35XX H
- items: items:
- const: anbernic,rg35xx-h - const: anbernic,rg35xx-h
- const: allwinner,sun50i-h700 - const: allwinner,sun50i-h700
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "of_private.h"
/** /**
* irq_of_parse_and_map - Parse and map an interrupt into linux virq space * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
* @dev: Device node of the device whose interrupt is to be mapped * @dev: Device node of the device whose interrupt is to be mapped
...@@ -96,6 +98,57 @@ static const char * const of_irq_imap_abusers[] = { ...@@ -96,6 +98,57 @@ static const char * const of_irq_imap_abusers[] = {
NULL, NULL,
}; };
const __be32 *of_irq_parse_imap_parent(const __be32 *imap, int len, struct of_phandle_args *out_irq)
{
u32 intsize, addrsize;
struct device_node *np;
/* Get the interrupt parent */
if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
np = of_node_get(of_irq_dflt_pic);
else
np = of_find_node_by_phandle(be32_to_cpup(imap));
imap++;
/* Check if not found */
if (!np) {
pr_debug(" -> imap parent not found !\n");
return NULL;
}
/* Get #interrupt-cells and #address-cells of new parent */
if (of_property_read_u32(np, "#interrupt-cells",
&intsize)) {
pr_debug(" -> parent lacks #interrupt-cells!\n");
of_node_put(np);
return NULL;
}
if (of_property_read_u32(np, "#address-cells",
&addrsize))
addrsize = 0;
pr_debug(" -> intsize=%d, addrsize=%d\n",
intsize, addrsize);
/* Check for malformed properties */
if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS)
|| (len < (addrsize + intsize))) {
of_node_put(np);
return NULL;
}
pr_debug(" -> imaplen=%d\n", len);
imap += addrsize + intsize;
out_irq->np = np;
for (int i = 0; i < intsize; i++)
out_irq->args[i] = be32_to_cpup(imap - intsize + i);
out_irq->args_count = intsize;
return imap;
}
/** /**
* of_irq_parse_raw - Low level interrupt tree parsing * of_irq_parse_raw - Low level interrupt tree parsing
* @addr: address specifier (start of "reg" property of the device) in be32 format * @addr: address specifier (start of "reg" property of the device) in be32 format
...@@ -112,12 +165,12 @@ static const char * const of_irq_imap_abusers[] = { ...@@ -112,12 +165,12 @@ static const char * const of_irq_imap_abusers[] = {
*/ */
int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
{ {
struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; struct device_node *ipar, *tnode, *old = NULL;
__be32 initial_match_array[MAX_PHANDLE_ARGS]; __be32 initial_match_array[MAX_PHANDLE_ARGS];
const __be32 *match_array = initial_match_array; const __be32 *match_array = initial_match_array;
const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) }; const __be32 *tmp, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; u32 intsize = 1, addrsize;
int imaplen, match, i, rc = -EINVAL; int i, rc = -EINVAL;
#ifdef DEBUG #ifdef DEBUG
of_print_phandle_args("of_irq_parse_raw: ", out_irq); of_print_phandle_args("of_irq_parse_raw: ", out_irq);
...@@ -176,6 +229,9 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) ...@@ -176,6 +229,9 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
/* Now start the actual "proper" walk of the interrupt tree */ /* Now start the actual "proper" walk of the interrupt tree */
while (ipar != NULL) { while (ipar != NULL) {
int imaplen, match;
const __be32 *imap, *oldimap, *imask;
struct device_node *newpar;
/* /*
* Now check if cursor is an interrupt-controller and * Now check if cursor is an interrupt-controller and
* if it is then we are done, unless there is an * if it is then we are done, unless there is an
...@@ -216,7 +272,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) ...@@ -216,7 +272,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
/* Parse interrupt-map */ /* Parse interrupt-map */
match = 0; match = 0;
while (imaplen > (addrsize + intsize + 1) && !match) { while (imaplen > (addrsize + intsize + 1)) {
/* Compare specifiers */ /* Compare specifiers */
match = 1; match = 1;
for (i = 0; i < (addrsize + intsize); i++, imaplen--) for (i = 0; i < (addrsize + intsize); i++, imaplen--)
...@@ -224,48 +280,17 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) ...@@ -224,48 +280,17 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen); pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
/* Get the interrupt parent */ oldimap = imap;
if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) imap = of_irq_parse_imap_parent(oldimap, imaplen, out_irq);
newpar = of_node_get(of_irq_dflt_pic); if (!imap)
else
newpar = of_find_node_by_phandle(be32_to_cpup(imap));
imap++;
--imaplen;
/* Check if not found */
if (newpar == NULL) {
pr_debug(" -> imap parent not found !\n");
goto fail;
}
if (!of_device_is_available(newpar))
match = 0;
/* Get #interrupt-cells and #address-cells of new
* parent
*/
if (of_property_read_u32(newpar, "#interrupt-cells",
&newintsize)) {
pr_debug(" -> parent lacks #interrupt-cells!\n");
goto fail;
}
if (of_property_read_u32(newpar, "#address-cells",
&newaddrsize))
newaddrsize = 0;
pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
newintsize, newaddrsize);
/* Check for malformed properties */
if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS)
|| (imaplen < (newaddrsize + newintsize))) {
rc = -EFAULT;
goto fail; goto fail;
}
imap += newaddrsize + newintsize; match &= of_device_is_available(out_irq->np);
imaplen -= newaddrsize + newintsize; if (match)
break;
of_node_put(out_irq->np);
imaplen -= imap - oldimap;
pr_debug(" -> imaplen=%d\n", imaplen); pr_debug(" -> imaplen=%d\n", imaplen);
} }
if (!match) { if (!match) {
...@@ -287,11 +312,11 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) ...@@ -287,11 +312,11 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
* Successfully parsed an interrupt-map translation; copy new * Successfully parsed an interrupt-map translation; copy new
* interrupt specifier into the out_irq structure * interrupt specifier into the out_irq structure
*/ */
match_array = imap - newaddrsize - newintsize; match_array = oldimap + 1;
for (i = 0; i < newintsize; i++)
out_irq->args[i] = be32_to_cpup(imap - newintsize + i); newpar = out_irq->np;
out_irq->args_count = intsize = newintsize; intsize = out_irq->args_count;
addrsize = newaddrsize; addrsize = (imap - match_array) - intsize;
if (ipar == newpar) { if (ipar == newpar) {
pr_debug("%pOF interrupt-map entry to self\n", ipar); pr_debug("%pOF interrupt-map entry to self\n", ipar);
...@@ -300,7 +325,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) ...@@ -300,7 +325,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
skiplevel: skiplevel:
/* Iterate again with new parent */ /* Iterate again with new parent */
out_irq->np = newpar;
pr_debug(" -> new parent: %pOF\n", newpar); pr_debug(" -> new parent: %pOF\n", newpar);
of_node_put(ipar); of_node_put(ipar);
ipar = newpar; ipar = newpar;
...@@ -310,7 +334,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) ...@@ -310,7 +334,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
fail: fail:
of_node_put(ipar); of_node_put(ipar);
of_node_put(newpar);
return rc; return rc;
} }
......
...@@ -159,6 +159,9 @@ extern void __of_sysfs_remove_bin_file(struct device_node *np, ...@@ -159,6 +159,9 @@ extern void __of_sysfs_remove_bin_file(struct device_node *np,
extern int of_bus_n_addr_cells(struct device_node *np); extern int of_bus_n_addr_cells(struct device_node *np);
extern int of_bus_n_size_cells(struct device_node *np); extern int of_bus_n_size_cells(struct device_node *np);
const __be32 *of_irq_parse_imap_parent(const __be32 *imap, int len,
struct of_phandle_args *out_irq);
struct bus_dma_region; struct bus_dma_region;
#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_HAS_DMA) #if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_HAS_DMA)
int of_dma_get_range(struct device_node *np, int of_dma_get_range(struct device_node *np,
......
...@@ -54,4 +54,5 @@ static struct kunit_suite of_dtb_suite = { ...@@ -54,4 +54,5 @@ static struct kunit_suite of_dtb_suite = {
kunit_test_suites( kunit_test_suites(
&of_dtb_suite, &of_dtb_suite,
); );
MODULE_DESCRIPTION("KUnit tests for OF APIs");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -1306,10 +1306,10 @@ static struct device_node *parse_interrupts(struct device_node *np, ...@@ -1306,10 +1306,10 @@ static struct device_node *parse_interrupts(struct device_node *np,
static struct device_node *parse_interrupt_map(struct device_node *np, static struct device_node *parse_interrupt_map(struct device_node *np,
const char *prop_name, int index) const char *prop_name, int index)
{ {
const __be32 *imap, *imap_end, *addr; const __be32 *imap, *imap_end;
struct of_phandle_args sup_args; struct of_phandle_args sup_args;
u32 addrcells, intcells; u32 addrcells, intcells;
int i, imaplen; int imaplen;
if (!IS_ENABLED(CONFIG_OF_IRQ)) if (!IS_ENABLED(CONFIG_OF_IRQ))
return NULL; return NULL;
...@@ -1322,33 +1322,23 @@ static struct device_node *parse_interrupt_map(struct device_node *np, ...@@ -1322,33 +1322,23 @@ static struct device_node *parse_interrupt_map(struct device_node *np,
addrcells = of_bus_n_addr_cells(np); addrcells = of_bus_n_addr_cells(np);
imap = of_get_property(np, "interrupt-map", &imaplen); imap = of_get_property(np, "interrupt-map", &imaplen);
if (!imap || imaplen <= (addrcells + intcells)) imaplen /= sizeof(*imap);
if (!imap)
return NULL; return NULL;
imap_end = imap + imaplen;
while (imap < imap_end) { imap_end = imap + imaplen;
addr = imap;
imap += addrcells;
sup_args.np = np; for (int i = 0; imap + addrcells + intcells + 1 < imap_end; i++) {
sup_args.args_count = intcells; imap += addrcells + intcells;
for (i = 0; i < intcells; i++)
sup_args.args[i] = be32_to_cpu(imap[i]);
imap += intcells;
/* imap = of_irq_parse_imap_parent(imap, imap_end - imap, &sup_args);
* Upon success, the function of_irq_parse_raw() returns if (!imap)
* interrupt controller DT node pointer in sup_args.np.
*/
if (of_irq_parse_raw(addr, &sup_args))
return NULL; return NULL;
if (!index) if (i == index)
return sup_args.np; return sup_args.np;
of_node_put(sup_args.np); of_node_put(sup_args.np);
imap += sup_args.args_count + 1;
index--;
} }
return NULL; return NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment