mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 14:12:06 +00:00
Devicetree fixes for v6.10, part 1:
- 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 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEktVUI4SxYhzZyEuo+vtdtY28YcMFAmZfehAACgkQ+vtdtY28 YcP87Q/8CAai+aoYKnnth5iiOvP9wuCMS02sVK0/0zHy9LqYJhhmlgHf9q2rsapu oe0ETA1ukuQwW5PXw595NOi99yH3N9B0FaFvlN1U1evwNaWIhNQCFMBToAvDeqaR sl0TGOd13xLp8qhDMgdbFkIBMKDi5xqbATGFYQfMjTDVYtlvHWWCMk2jR83Lvi+r eL6VZXtlwyr4cvREUlGMxu0hgC3dWXf4r/bBWVifI/UgCBqtrz4ImhTF8WKpdWuG tAjEeOA88yyUWKv5BPLG4sqceMKi4PnNFy2KKQ0ETBsExaXmLRDk+MFXn2MyaUEp cHUTsYiu1SgUR5sbU7SwLmx90rbFOY6Lo7Xr9nqm3n6l8B3wkj6rJFu+4nCShFGb ksPK1n4f1T04Cs2ZmOUaO2feFfvUxyVOaQD9bPTXutzI2N8RJ59OYbTmUFNvwmUO m3exSf+AOuaRYJ5ZaSpQGztJjcLe5G3Vdpe6AWYQGyBqxTnVSvgKybDNEWeZyAAX AZ92VZmCKX517I4XhygQvaVor91RkJrDvr1mWM1y0oDlyUEfmKRr89pFk36SsJQE Md7K9vcZK4xqHhm9CpF78quQuLmX/gl7f4WKnhOtd3ELaDiwCCylmOfoR8CKdeVB sovM3US5MqSMrDPgawVTxI03Alc4pgCR8ZfzUbpxcCqN73COyYQ= =cIUy -----END PGP SIGNATURE----- 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()
This commit is contained in:
commit
51214520ad
@ -54,11 +54,10 @@ unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
mlahb: ahb@38000000 {
|
||||
ahb {
|
||||
compatible = "st,mlahb", "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x10000000 0x40000>;
|
||||
ranges;
|
||||
dma-ranges = <0x00000000 0x38000000 0x10000>,
|
||||
<0x10000000 0x10000000 0x60000>,
|
||||
|
@ -57,17 +57,17 @@ properties:
|
||||
- const: allwinner,sun8i-v3s
|
||||
|
||||
- description: Anbernic RG35XX (2024)
|
||||
- items:
|
||||
items:
|
||||
- const: anbernic,rg35xx-2024
|
||||
- const: allwinner,sun50i-h700
|
||||
|
||||
- description: Anbernic RG35XX Plus
|
||||
- items:
|
||||
items:
|
||||
- const: anbernic,rg35xx-plus
|
||||
- const: allwinner,sun50i-h700
|
||||
|
||||
- description: Anbernic RG35XX H
|
||||
- items:
|
||||
items:
|
||||
- const: anbernic,rg35xx-h
|
||||
- const: allwinner,sun50i-h700
|
||||
|
||||
|
125
drivers/of/irq.c
125
drivers/of/irq.c
@ -25,6 +25,8 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "of_private.h"
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -96,6 +98,57 @@ static const char * const of_irq_imap_abusers[] = {
|
||||
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
|
||||
* @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[] = {
|
||||
*/
|
||||
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];
|
||||
const __be32 *match_array = initial_match_array;
|
||||
const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
|
||||
u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
|
||||
int imaplen, match, i, rc = -EINVAL;
|
||||
const __be32 *tmp, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
|
||||
u32 intsize = 1, addrsize;
|
||||
int i, rc = -EINVAL;
|
||||
|
||||
#ifdef DEBUG
|
||||
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)
|
||||
|
||||
/* Now start the actual "proper" walk of the interrupt tree */
|
||||
while (ipar != NULL) {
|
||||
int imaplen, match;
|
||||
const __be32 *imap, *oldimap, *imask;
|
||||
struct device_node *newpar;
|
||||
/*
|
||||
* Now check if cursor is an interrupt-controller and
|
||||
* 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)
|
||||
|
||||
/* Parse interrupt-map */
|
||||
match = 0;
|
||||
while (imaplen > (addrsize + intsize + 1) && !match) {
|
||||
while (imaplen > (addrsize + intsize + 1)) {
|
||||
/* Compare specifiers */
|
||||
match = 1;
|
||||
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)
|
||||
|
||||
pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
|
||||
|
||||
/* Get the interrupt parent */
|
||||
if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
|
||||
newpar = of_node_get(of_irq_dflt_pic);
|
||||
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");
|
||||
oldimap = imap;
|
||||
imap = of_irq_parse_imap_parent(oldimap, imaplen, out_irq);
|
||||
if (!imap)
|
||||
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;
|
||||
}
|
||||
|
||||
imap += newaddrsize + newintsize;
|
||||
imaplen -= newaddrsize + newintsize;
|
||||
match &= of_device_is_available(out_irq->np);
|
||||
if (match)
|
||||
break;
|
||||
|
||||
of_node_put(out_irq->np);
|
||||
imaplen -= imap - oldimap;
|
||||
pr_debug(" -> imaplen=%d\n", imaplen);
|
||||
}
|
||||
if (!match) {
|
||||
@ -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
|
||||
* interrupt specifier into the out_irq structure
|
||||
*/
|
||||
match_array = imap - newaddrsize - newintsize;
|
||||
for (i = 0; i < newintsize; i++)
|
||||
out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
|
||||
out_irq->args_count = intsize = newintsize;
|
||||
addrsize = newaddrsize;
|
||||
match_array = oldimap + 1;
|
||||
|
||||
newpar = out_irq->np;
|
||||
intsize = out_irq->args_count;
|
||||
addrsize = (imap - match_array) - intsize;
|
||||
|
||||
if (ipar == newpar) {
|
||||
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)
|
||||
|
||||
skiplevel:
|
||||
/* Iterate again with new parent */
|
||||
out_irq->np = newpar;
|
||||
pr_debug(" -> new parent: %pOF\n", newpar);
|
||||
of_node_put(ipar);
|
||||
ipar = newpar;
|
||||
@ -310,7 +334,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
|
||||
|
||||
fail:
|
||||
of_node_put(ipar);
|
||||
of_node_put(newpar);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -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_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;
|
||||
#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_HAS_DMA)
|
||||
int of_dma_get_range(struct device_node *np,
|
||||
|
@ -54,4 +54,5 @@ static struct kunit_suite of_dtb_suite = {
|
||||
kunit_test_suites(
|
||||
&of_dtb_suite,
|
||||
);
|
||||
MODULE_DESCRIPTION("KUnit tests for OF APIs");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -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,
|
||||
const char *prop_name, int index)
|
||||
{
|
||||
const __be32 *imap, *imap_end, *addr;
|
||||
const __be32 *imap, *imap_end;
|
||||
struct of_phandle_args sup_args;
|
||||
u32 addrcells, intcells;
|
||||
int i, imaplen;
|
||||
int imaplen;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF_IRQ))
|
||||
return NULL;
|
||||
@ -1322,33 +1322,23 @@ static struct device_node *parse_interrupt_map(struct device_node *np,
|
||||
addrcells = of_bus_n_addr_cells(np);
|
||||
|
||||
imap = of_get_property(np, "interrupt-map", &imaplen);
|
||||
if (!imap || imaplen <= (addrcells + intcells))
|
||||
imaplen /= sizeof(*imap);
|
||||
if (!imap)
|
||||
return NULL;
|
||||
|
||||
imap_end = imap + imaplen;
|
||||
|
||||
while (imap < imap_end) {
|
||||
addr = imap;
|
||||
imap += addrcells;
|
||||
for (int i = 0; imap + addrcells + intcells + 1 < imap_end; i++) {
|
||||
imap += addrcells + intcells;
|
||||
|
||||
sup_args.np = np;
|
||||
sup_args.args_count = intcells;
|
||||
for (i = 0; i < intcells; i++)
|
||||
sup_args.args[i] = be32_to_cpu(imap[i]);
|
||||
imap += intcells;
|
||||
|
||||
/*
|
||||
* Upon success, the function of_irq_parse_raw() returns
|
||||
* interrupt controller DT node pointer in sup_args.np.
|
||||
*/
|
||||
if (of_irq_parse_raw(addr, &sup_args))
|
||||
imap = of_irq_parse_imap_parent(imap, imap_end - imap, &sup_args);
|
||||
if (!imap)
|
||||
return NULL;
|
||||
|
||||
if (!index)
|
||||
if (i == index)
|
||||
return sup_args.np;
|
||||
|
||||
of_node_put(sup_args.np);
|
||||
imap += sup_args.args_count + 1;
|
||||
index--;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user