Thread (13 messages) flat view 13 messages, 7 authors, 2016-02-12

[PATCH] of/irq: Fix msi-map calculation for nonzero rid-base

From: Stuart Yoder <hidden>
Date: 2016-02-09 16:54:06
Also in: linux-devicetree, lkml, stable

-----Original Message-----
From: Mark Rutland [mailto:mark.rutland at arm.com]
Sent: Tuesday, February 09, 2016 10:08 AM
To: Stuart Yoder <redacted>
Cc: Marc Zyngier <redacted>; Robin Murphy <robin.murphy@arm.com>;
robh+dt at kernel.org; frowand.list at gmail.com; grant.likely at linaro.org;
devicetree at vger.kernel.org; david.daney at cavium.com; linux-arm-
kernel at lists.infradead.org; linux-kernel at vger.kernel.org; stable at vger.kernel.org
Subject: Re: [PATCH] of/irq: Fix msi-map calculation for nonzero rid-base

On Tue, Feb 09, 2016 at 03:56:55PM +0000, Stuart Yoder wrote:
quoted
quoted
-----Original Message-----
From: Marc Zyngier [mailto:marc.zyngier at arm.com]
Sent: Tuesday, February 09, 2016 6:06 AM
To: Robin Murphy <robin.murphy@arm.com>; robh+dt at kernel.org; frowand.list at gmail.com;
grant.likely at linaro.org; devicetree at vger.kernel.org
Cc: mark.rutland at arm.com; david.daney at cavium.com; Stuart Yoder
[off-list ref];
quoted
quoted
linux-arm-kernel at lists.infradead.org; linux-kernel at vger.kernel.org;
stable at vger.kernel.org
Subject: Re: [PATCH] of/irq: Fix msi-map calculation for nonzero rid-base

Hi Robin,

On 09/02/16 11:04, Robin Murphy wrote:
quoted
The existing msi-map code is fine for shifting the entire RID space
upwards, but attempting finer-grained remapping reveals a bug. It turns
out that we are mistakenly treating the msi-base part as an offset, not
as a new base to remap onto, so things get squiffy when rid-base is
nonzero. Fix this, and at the same time add a sanity check against
having msi-map-mask clash with a nonzero rid-base, as that's another
thing one can easily get wrong.

CC: <redacted>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Looks like Stuart and you both found the same bug at the same time:
https://lkml.org/lkml/2016/2/8/1066

but yours seem more correct to me (the rid_base masking in Stuart's
version seems odd).
quoted
---
 drivers/of/irq.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 7ee21ae..e7bfc17 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -635,6 +635,13 @@ static u32 __of_msi_map_rid(struct device *dev, struct
device_node **np,
quoted
 		msi_base = be32_to_cpup(msi_map + 2);
 		rid_len = be32_to_cpup(msi_map + 3);

+		if (rid_base & ~map_mask) {
+			dev_err(parent_dev,
+				"Invalid msi-map translation - msi-map-mask (0x%x) ignores
rid-
quoted
quoted
base (0x%x)\n",
quoted
+				map_mask, rid_base);
+			return rid_out;
+		}
+
 		msi_controller_node = of_find_node_by_phandle(phandle);

 		matched = (masked_rid >= rid_base &&
@@ -654,7 +661,7 @@ static u32 __of_msi_map_rid(struct device *dev, struct
device_node
quoted
quoted
**np,
quoted
 	if (!matched)
 		return rid_out;

-	rid_out = masked_rid + msi_base;
+	rid_out = masked_rid - rid_base + msi_base;
 	dev_dbg(dev,
 		"msi-map at: %s, using mask %08x, rid-base: %08x, msi-base: %08x,
length:
quoted
quoted
%08x, rid: %08x -> %08x\n",
quoted
 		dev_name(parent_dev), map_mask, rid_base, msi_base,
This computation:  masked_rid - rid_base

...doesn't seem right to me.  We are taking a rid that
has been already masked and subtracting a rid base that has
not been masked.
The binding only mentions that the input RID is masked, not the base, so
that seems correct to me.
quoted
I don't see how you can combine masked and unmasked values in the same
calculation.

Say I have this msi mapping:

                   msi-map = <0x0100 &its 0x11 0x1>;
                   msi-map-mask = <0xff>;
I'd say that this is an inconsistent set of properties, and it's
probably worth warning if we encounter this. There is no possible way
that rid-base can be encountered.
quoted
masked_rid = 0x0
rid_base = 0x0100
msi_base = 0x11

masked_rid - rid_base is 0x0 - 0x0100...which does not
give the msi index/offset we want.

Correct final answer should be 0x11.
You can unambiguously describe this with:

	msi-map = <0x00 &its 0x11 0x1>;
	msi-map-mask = <0xff>;

This is exactly the pattern we follow in example 2 in the binding
document.
quoted
In my patch I masked the rid_base so it can be subtracted
from the masked_rid.

masked_rid_base = 0x00

   msi_base + (masked_rid - masked_rid_base) = 0x11
As above, I think that this is an inconsistent DT, and we should
warn/fail in that case.
Thanks...understand now.  I'll test Robin's patch and confirm
that it works as is for me.

Thanks,
Stuart
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help