Intel I350 mini-PCIe card (igb) on Mirabox (mvebu / Armada 370)
Jason Gunthorpe
jgunthorpe at obsidianresearch.com
Tue Apr 8 10:14:17 PDT 2014
On Tue, Apr 08, 2014 at 05:55:45PM +0200, Thomas Petazzoni wrote:
> mvebu-mbus/devices output:
>
> # cat /sys/kernel/debug/mvebu-mbus/devices
> [10] 00000000e0000000 - 00000000e0900000 : 0004:00e8
> I'm not sure why I don't have the non-power-of-two problem for the MBus
> windows.
Well, you do, 0x900000 is not aligned. It converts to size=0b10001111,
which is undefined behavior for mbus.
It looks like you are lucky, for your system the undefined behavior
creates a window that hits all the BARs, but the others were not so
lucky.
What do you think about this:
>From 235b0bf637242a50ec45c8766d18a942bff601cf Mon Sep 17 00:00:00 2001
From: Jason Gunthorpe <jgunthorpe at obsidianresearch.com>
Date: Tue, 8 Apr 2014 11:12:41 -0600
Subject: [PATCH] bus: mvebu-mbus: Avoid setting an undefined window size
The mbus hardware requires a power of two size, if a non-power
of two is passed in to the low level routines they configure the
register in a way that results in undefined behaviour.
- WARN_ON to make this invalid usage really obvious
- Round down to the nearest power of two so we only stuff a valid
size into the HW
- When reading interpret undefined values in a conservative way,
the value is assumed to be the lowest power of two. This avoids
the debugfs output showing a value that looks 'correct'
All together this makes the recent problems with silent failure
of PCI very obvious, noisy and debuggable.
Signed-off-by: Jason Gunthorpe <jgunthorpe at obsidianresearch.com>
---
drivers/bus/mvebu-mbus.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 2ac754e..d26f63c 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -56,6 +56,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/debugfs.h>
+#include <linux/log2.h>
/*
* DDR target is the same on all platforms.
@@ -147,7 +148,7 @@ static void mvebu_mbus_read_window(struct mvebu_mbus_state *mbus,
*enabled = 1;
*base = ((u64)basereg & WIN_BASE_HIGH) << 32;
*base |= (basereg & WIN_BASE_LOW);
- *size = (ctrlreg | ~WIN_CTRL_SIZE_MASK) + 1;
+ *size = 1 << (ffs(~(ctrlreg | ~WIN_CTRL_SIZE_MASK)) - 1);
if (target)
*target = (ctrlreg & WIN_CTRL_TGT_MASK) >> WIN_CTRL_TGT_SHIFT;
@@ -266,6 +267,9 @@ static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus,
mbus->soc->win_cfg_offset(win);
u32 ctrl, remap_addr;
+ WARN_ON(!is_power_of_2(size));
+ size = rounddown_pow_of_two(size);
+
ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) |
(attr << WIN_CTRL_ATTR_SHIFT) |
(target << WIN_CTRL_TGT_SHIFT) |
--
1.8.1.2
More information about the linux-arm-kernel
mailing list