New kernels

AmigaOne X1000 platform specific issues related to Linux only.
User avatar
xeno74
Posts: 10712
Joined: Fri Mar 23, 2012 7:58 am
Contact:

Re: New kernels

Post by xeno74 »

Please add libata.force=noncq to the boot arguments.

setenv bootargs "root=/dev/<partition or disk> libata.force=noncq"
User avatar
Hypex
Beta Tester
Beta Tester
Posts: 913
Joined: Mon Dec 20, 2010 2:23 pm
Location: Vic. Australia.

Re: New kernels

Post by Hypex »

Okay I tried that. I saw no change. It got stuck on sata as long as usual and failed to identify devices.

With device it ends up with kernel panic. With ramdisk it fails to locate depmod file then fails assign MAC for dummy0. Then it stalls.

It also messes up the sata registers as on reboot to a working kernel, like 5.12.0 here with Xenial, it gets delayed on sata for a short while but finally gets over it.
User avatar
xeno74
Posts: 10712
Joined: Fri Mar 23, 2012 7:58 am
Contact:

Re: New kernels

Post by xeno74 »

Hypex wrote: Fri Jun 28, 2024 8:19 pm Okay I tried that. I saw no change. It got stuck on sata as long as usual and failed to identify devices.

With device it ends up with kernel panic. With ramdisk it fails to locate depmod file then fails assign MAC for dummy0. Then it stalls.

It also messes up the sata registers as on reboot to a working kernel, like 5.12.0 here with Xenial, it gets delayed on sata for a short while but finally gets over it.
Thank you for testing!
User avatar
xeno74
Posts: 10712
Joined: Fri Mar 23, 2012 7:58 am
Contact:

Re: New kernels

Post by xeno74 »

Hypex wrote: Thu Jun 27, 2024 7:20 pm I retested vmlinux-6.10-10 again. Twice. Got a kernel panic.

I then tested vmlinux-6.10-14. Acted exactly the same. Has trouble with sata.

Also the 5.10.288 LTS kernel has issues. It cannot reset. When it resets machine it just sits there.
Do you mean the latest stable longterm kernel 5.10.218 for our X1000 and X5000?

The 5.10.288 doesn't exist.

I tested the kernel 5.10.218 today and the reboot (reset) works.
User avatar
xeno74
Posts: 10712
Joined: Fri Mar 23, 2012 7:58 am
Contact:

Re: New kernels

Post by xeno74 »

I'll try bisecting again ...

About bisecting:
Git bisect is like a little wizard that walks you through recent commits, asks you if they are good or bad, and narrows down the broken commit.
Git bisect starts with the midpoint commit. The midpoint commit is between the initial good commit and the initial bad commit.
If the midpoint commit was good, you know the commit that introduced the change is between your midpoint and the initial bad commit.
If the midpoint commit was bad, you know the commit that introduced the change is between your midpoint and the initial good commit.
After that git bisect selects a new midpoint in the area where the commit was bad. And this is repeated over and over again till the bad commit has been found.
  1. Code: Select all

    git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git b
  2. Code: Select all

    git bisect start
  3. Code: Select all

    git bisect good c3f38fa61af77b49866b006939479069cd451173
    (Good: Linux 6.10-rc2)
  4. Code: Select all

    git bisect bad 83a7eefedc9b56fe7bfeff13b6c7356688ffa670
    (Bad: Linux 6.10-rc3)
    Output:

    Code: Select all

    [d30d0e49da71de8df10bf3ff1b3de880653af562] Merge tag 'net-6.10-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
  5. git bisect bad
    Output:

    Code: Select all

    [411c0ea696cc4fcd14a32f2093c909e0c59c5dd7] Merge branch 'af_unix-fix-lockless-access-of-sk-sk_state-and-others-fields'
    
  6. git bisect good
    Output:

    Code: Select all

    Bisecting: 46 revisions left to test after this (roughly 6 steps)
    [71d7b52cc33bc3b6697cce8a0a5ac9032f372e47] Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
    
  7. git bisect bad
    Output:

    Code: Select all

    [45ce0314bf258bd387d92782d5393e7b84b0121f] Merge tag 'kvmarm-fixes-6.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
    
  8. git bisect good
    Output:

    Code: Select all

    Bisecting: 18 revisions left to test after this (roughly 4 steps)
    [4bf15b1c657d22d1d70173e43264e4606dfe75ff] selftests/futex: don't pass a const char* to asprintf(3)
    
  9. git bisect good
    Output:

    Code: Select all

    Bisecting: 8 revisions left to test after this (roughly 3 steps)
    [2ab79514109578fc4b6df90633d500cf281eb689] Merge tag 'cxl-fixes-6.10-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
    
  10. git bisect good
    Output:

    Code: Select all

    Bisecting: 4 revisions left to test after this (roughly 2 steps)
    [935df1bd40d43c4ee91838c42a20e9af751885cc] of/irq: Factor out parsing of interrupt-map parent phandle+args from of_irq_parse_raw()
    
  11. git bisect bad
    Output:

    Code: Select all

    Bisecting: 1 revision left to test after this (roughly 1 step)
    [84081a885394fc94055c24c727c99c321df6abac] dt-bindings: arm: sunxi: Fix incorrect '-' usage
    
  12. git bisect good
    Output:

    Code: Select all

    Bisecting: 0 revisions left to test after this (roughly 0 steps)
    [321e4fa68ce15660ec578bdec5cc9607635087cf] dt-bindings: arm: stm32: st,mlahb: Drop spurious "reg" property from example
    
  13. git bisect good
    Output:

    Code: Select all

    935df1bd40d43c4ee91838c42a20e9af751885cc is the first bad commit
    commit 935df1bd40d43c4ee91838c42a20e9af751885cc
    Author: Rob Herring (Arm) <[email protected]>
    Date:   Wed May 29 14:59:20 2024 -0500
    
        of/irq: Factor out parsing of interrupt-map parent phandle+args from of_irq_parse_raw()
    
        Factor out the parsing of interrupt-map interrupt parent phandle and its
        arg cells to a separate function, of_irq_parse_imap_parent(), so that it
        can be used in other parsing scenarios (e.g. fw_devlink).
    
        There was a refcount leak on non-matching entries when iterating thru
        "interrupt-map" which is fixed.
    
        Tested-by: Marc Zyngier <[email protected]>
        Tested-by: Anup Patel <[email protected]>
        Link: https://lore.kernel.org/r/[email protected]
        Signed-off-by: Rob Herring (Arm) <[email protected]>
    
     drivers/of/irq.c        | 125 ++++++++++++++++++++++++++++--------------------
     drivers/of/of_private.h |   3 ++
     2 files changed, 77 insertions(+), 51 deletions(-)
    
    We have another bad commit.

    of/irq: Factor out parsing of interrupt-map parent phandle+args from of_irq_parse_raw() (935df1bd40d43c4ee91838c42a20e9af751885cc) is the first bad commit.


    Cheers,
    Christian
Last edited by xeno74 on Sat Jun 29, 2024 2:00 pm, edited 11 times in total.
User avatar
Hypex
Beta Tester
Beta Tester
Posts: 913
Joined: Mon Dec 20, 2010 2:23 pm
Location: Vic. Australia.

Re: New kernels

Post by Hypex »

xeno74 wrote: Sat Jun 29, 2024 9:30 amDo you mean the latest stable longterm kernel 5.10.218 for our X1000 and X5000?
Oh sorry yes, I misspelt 218. :-)
The 5.10.288 doesn't exist.
Oops.
I tested the kernel 5.10.218 today and the reboot (reset) works.
I tested it from Xenial. I selected to reboot from menu. It shuts down, the kernel closes itself and the machine resets. Then shortly after the monitor goes into standby and nothing else happens. It's similar to other issues I've seen on the X1000 where CFE stalls in reset routine for some reason.
User avatar
xeno74
Posts: 10712
Joined: Fri Mar 23, 2012 7:58 am
Contact:

Re: New kernels

Post by xeno74 »

We have another bad commit.

of/irq: Factor out parsing of interrupt-map parent phandle+args from of_irq_parse_raw() (935df1bd40d43c4ee91838c42a20e9af751885cc) is the first bad commit.

Code: Select all

935df1bd40d43c4ee91838c42a20e9af751885cc is the first bad commit
commit 935df1bd40d43c4ee91838c42a20e9af751885cc
Author: Rob Herring (Arm) <[email protected]>
Date:   Wed May 29 14:59:20 2024 -0500

    of/irq: Factor out parsing of interrupt-map parent phandle+args from of_irq_parse_raw()

    Factor out the parsing of interrupt-map interrupt parent phandle and its
    arg cells to a separate function, of_irq_parse_imap_parent(), so that it
    can be used in other parsing scenarios (e.g. fw_devlink).

    There was a refcount leak on non-matching entries when iterating thru
    "interrupt-map" which is fixed.

    Tested-by: Marc Zyngier <[email protected]>
    Tested-by: Anup Patel <[email protected]>
    Link: https://lore.kernel.org/r/[email protected]
    Signed-off-by: Rob Herring (Arm) <[email protected]>

 drivers/of/irq.c        | 125 ++++++++++++++++++++++++++++--------------------
 drivers/of/of_private.h |   3 ++
 2 files changed, 77 insertions(+), 51 deletions(-)
We have to check, if this commit is really the first bad commit.

Code: Select all

git checkout 935df1bd40d43c4ee91838c42a20e9af751885cc

Code: Select all

Note: switching to '935df1bd40d43c4ee91838c42a20e9af751885cc'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 935df1bd40d4 of/irq: Factor out parsing of interrupt-map parent phandle+args from of_irq_parse_raw()
Compiling the kernel with the first bad commit ...

Result: ATA failed to IDENTIFY (I/O error) -> Correct result

Next step reverting the first bad commit and compiling again ...

Code: Select all

git checkout 935df1bd40d43c4ee91838c42a20e9af751885cc

Code: Select all

git revert 935df1bd40d43c4ee91838c42a20e9af751885cc
Output:

Code: Select all

[detached HEAD 24ee1d8b315c] Revert "of/irq: Factor out parsing of interrupt-map parent phandle+args from of_irq_parse_raw()"
 2 files changed, 51 insertions(+), 77 deletions(-)
Compiling the kernel with the reverted first bad commit ... Result: Kernel boots
Last edited by xeno74 on Mon Jul 01, 2024 8:42 am, edited 1 time in total.
User avatar
xeno74
Posts: 10712
Joined: Fri Mar 23, 2012 7:58 am
Contact:

Re: New kernels

Post by xeno74 »

I was able to revert the first bad commit in the latest git kernel. :-)

Code: Select all

$ git revert 935df1bd40d43c4ee91838c42a20e9af751885cc
[master fddf986bbc8c] Revert "of/irq: Factor out parsing of interrupt-map parent phandle+args from of_irq_parse_raw()"
 2 files changed, 51 insertions(+), 77 deletions(-)
User avatar
xeno74
Posts: 10712
Joined: Fri Mar 23, 2012 7:58 am
Contact:

Re: New kernels

Post by xeno74 »

I created a patch.

of_irq.patch:

Code: Select all

diff -rupN a/drivers/of/irq.c b/drivers/of/irq.c
--- a/drivers/of/irq.c	2024-06-29 15:01:01.012144747 +0200
+++ b/drivers/of/irq.c	2024-06-29 15:00:33.514501761 +0200
@@ -25,8 +25,6 @@
 #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
@@ -98,57 +96,6 @@ static const char * const of_irq_imap_ab
 	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
@@ -165,12 +112,12 @@ const __be32 *of_irq_parse_imap_parent(c
  */
 int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 {
-	struct device_node *ipar, *tnode, *old = NULL;
+	struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
 	__be32 initial_match_array[MAX_PHANDLE_ARGS];
 	const __be32 *match_array = initial_match_array;
-	const __be32 *tmp, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
-	u32 intsize = 1, addrsize;
-	int i, rc = -EINVAL;
+	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;
 
 #ifdef DEBUG
 	of_print_phandle_args("of_irq_parse_raw: ", out_irq);
@@ -229,9 +176,6 @@ int of_irq_parse_raw(const __be32 *addr,
 
 	/* 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
@@ -272,7 +216,7 @@ int of_irq_parse_raw(const __be32 *addr,
 
 		/* Parse interrupt-map */
 		match = 0;
-		while (imaplen > (addrsize + intsize + 1)) {
+		while (imaplen > (addrsize + intsize + 1) && !match) {
 			/* Compare specifiers */
 			match = 1;
 			for (i = 0; i < (addrsize + intsize); i++, imaplen--)
@@ -280,17 +224,48 @@ int of_irq_parse_raw(const __be32 *addr,
 
 			pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
 
-			oldimap = imap;
-			imap = of_irq_parse_imap_parent(oldimap, imaplen, out_irq);
-			if (!imap)
+			/* 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");
 				goto fail;
+			}
 
-			match &= of_device_is_available(out_irq->np);
-			if (match)
-				break;
+			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;
 
-			of_node_put(out_irq->np);
-			imaplen -= imap - oldimap;
 			pr_debug(" -> imaplen=%d\n", imaplen);
 		}
 		if (!match) {
@@ -312,11 +287,11 @@ int of_irq_parse_raw(const __be32 *addr,
 		 * Successfully parsed an interrupt-map translation; copy new
 		 * interrupt specifier into the out_irq structure
 		 */
-		match_array = oldimap + 1;
-
-		newpar = out_irq->np;
-		intsize = out_irq->args_count;
-		addrsize = (imap - match_array) - intsize;
+		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;
 
 		if (ipar == newpar) {
 			pr_debug("%pOF interrupt-map entry to self\n", ipar);
@@ -325,6 +300,7 @@ int of_irq_parse_raw(const __be32 *addr,
 
 	skiplevel:
 		/* Iterate again with new parent */
+		out_irq->np = newpar;
 		pr_debug(" -> new parent: %pOF\n", newpar);
 		of_node_put(ipar);
 		ipar = newpar;
@@ -334,6 +310,7 @@ int of_irq_parse_raw(const __be32 *addr,
 
  fail:
 	of_node_put(ipar);
+	of_node_put(newpar);
 
 	return rc;
 }
diff -rupN a/drivers/of/of_private.h b/drivers/of/of_private.h
--- a/drivers/of/of_private.h	2024-06-29 15:01:01.012144747 +0200
+++ b/drivers/of/of_private.h	2024-06-29 15:00:33.514501761 +0200
@@ -159,9 +159,6 @@ extern void __of_sysfs_remove_bin_file(s
 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,
Unfortunately it doesn't compile with this patch.

Error message:

Code: Select all

drivers/of/property.c: In function 'parse_interrupt_map':
drivers/of/property.c:1334:10: error: implicit declaration of function 'of_irq_parse_imap_parent' [-Werror=implicit-function-declaration]
 1334 |   imap = of_irq_parse_imap_parent(imap, imap_end - imap, &sup_args);
User avatar
xeno74
Posts: 10712
Joined: Fri Mar 23, 2012 7:58 am
Contact:

Re: New kernels

Post by xeno74 »

I created a new patch.

of_irq_v2.patch:

Code: Select all

diff -rupN a/drivers/of/irq.c b/drivers/of/irq.c
--- a/drivers/of/irq.c	2024-06-23 23:08:54.000000000 +0200
+++ b/drivers/of/irq.c	2024-06-29 16:01:29.161973980 +0200
@@ -25,8 +25,6 @@
 #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
@@ -98,57 +96,6 @@ static const char * const of_irq_imap_ab
 	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
@@ -165,12 +112,12 @@ const __be32 *of_irq_parse_imap_parent(c
  */
 int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
 {
-	struct device_node *ipar, *tnode, *old = NULL;
+	struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
 	__be32 initial_match_array[MAX_PHANDLE_ARGS];
 	const __be32 *match_array = initial_match_array;
-	const __be32 *tmp, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
-	u32 intsize = 1, addrsize;
-	int i, rc = -EINVAL;
+	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;
 
 #ifdef DEBUG
 	of_print_phandle_args("of_irq_parse_raw: ", out_irq);
@@ -229,9 +176,6 @@ int of_irq_parse_raw(const __be32 *addr,
 
 	/* 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
@@ -272,7 +216,7 @@ int of_irq_parse_raw(const __be32 *addr,
 
 		/* Parse interrupt-map */
 		match = 0;
-		while (imaplen > (addrsize + intsize + 1)) {
+		while (imaplen > (addrsize + intsize + 1) && !match) {
 			/* Compare specifiers */
 			match = 1;
 			for (i = 0; i < (addrsize + intsize); i++, imaplen--)
@@ -280,17 +224,48 @@ int of_irq_parse_raw(const __be32 *addr,
 
 			pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
 
-			oldimap = imap;
-			imap = of_irq_parse_imap_parent(oldimap, imaplen, out_irq);
-			if (!imap)
+			/* 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");
 				goto fail;
+			}
 
-			match &= of_device_is_available(out_irq->np);
-			if (match)
-				break;
+			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;
 
-			of_node_put(out_irq->np);
-			imaplen -= imap - oldimap;
 			pr_debug(" -> imaplen=%d\n", imaplen);
 		}
 		if (!match) {
@@ -312,11 +287,11 @@ int of_irq_parse_raw(const __be32 *addr,
 		 * Successfully parsed an interrupt-map translation; copy new
 		 * interrupt specifier into the out_irq structure
 		 */
-		match_array = oldimap + 1;
-
-		newpar = out_irq->np;
-		intsize = out_irq->args_count;
-		addrsize = (imap - match_array) - intsize;
+		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;
 
 		if (ipar == newpar) {
 			pr_debug("%pOF interrupt-map entry to self\n", ipar);
@@ -325,6 +300,7 @@ int of_irq_parse_raw(const __be32 *addr,
 
 	skiplevel:
 		/* Iterate again with new parent */
+		out_irq->np = newpar;
 		pr_debug(" -> new parent: %pOF\n", newpar);
 		of_node_put(ipar);
 		ipar = newpar;
@@ -334,6 +310,7 @@ int of_irq_parse_raw(const __be32 *addr,
 
  fail:
 	of_node_put(ipar);
+	of_node_put(newpar);
 
 	return rc;
 }
diff -rupN a/drivers/of/of_private.h b/drivers/of/of_private.h
--- a/drivers/of/of_private.h	2024-06-23 23:08:54.000000000 +0200
+++ b/drivers/of/of_private.h	2024-06-29 16:01:29.166973915 +0200
@@ -159,9 +159,6 @@ extern void __of_sysfs_remove_bin_file(s
 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,
diff -rupN a/drivers/of/property.c b/drivers/of/property.c
--- a/drivers/of/property.c	2024-06-23 23:08:54.000000000 +0200
+++ b/drivers/of/property.c	2024-06-29 16:02:54.141867362 +0200
@@ -1306,10 +1306,10 @@ static struct device_node *parse_interru
 static struct device_node *parse_interrupt_map(struct device_node *np,
 					       const char *prop_name, int index)
 {
-	const __be32 *imap, *imap_end;
+	const __be32 *imap, *imap_end, *addr;
 	struct of_phandle_args sup_args;
 	u32 addrcells, intcells;
-	int imaplen;
+	int i, imaplen;
 
 	if (!IS_ENABLED(CONFIG_OF_IRQ))
 		return NULL;
@@ -1322,23 +1322,33 @@ static struct device_node *parse_interru
 	addrcells = of_bus_n_addr_cells(np);
 
 	imap = of_get_property(np, "interrupt-map", &imaplen);
-	imaplen /= sizeof(*imap);
-	if (!imap)
+	if (!imap || imaplen <= (addrcells + intcells))
 		return NULL;
-
 	imap_end = imap + imaplen;
 
-	for (int i = 0; imap + addrcells + intcells + 1 < imap_end; i++) {
-		imap += addrcells + intcells;
-
-		imap = of_irq_parse_imap_parent(imap, imap_end - imap, &sup_args);
-		if (!imap)
+	while (imap < imap_end) {
+		addr = imap;
+		imap += addrcells;
+
+		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))
 			return NULL;
 
-		if (i == index)
+		if (!index)
 			return sup_args.np;
 
 		of_node_put(sup_args.np);
+		imap += sup_args.args_count + 1;
+		index--;
 	}
 
 	return NULL;
Post Reply