[PATCH] arm: mvebu: mbus: Fix mbus driver to work also after U-Boot relocation
Pali Rohár
pali at kernel.org
Wed Aug 10 14:46:09 CEST 2022
mbus driver is initialized from arch_cpu_init() callback which is called
before relocation. This driver stores lot of functions and structure
pointers into global variables, so it is data position dependent.
Therefore after relocations all pointers are invalid and driver does not
work anymore as all pointers referes to the old memory, which overlaps with
CONFIG_SYS_LOAD_ADDR and ${loadaddr}.
For example U-Boot fuse command crashes if loadaddr memory is cleared or
rewritten by some image loaded by U-Boot load command.
mw.w ${loadaddr} 0x0 10000
fuse read 0 1 2
Fix this issue by removing of all mbus global variables in which are stored
pointers to structures or functions which changes during relocation. And
replace it by direct function calls (not via pointers). With this change
fuse command finally works.
Signed-off-by: Pali Rohár <pali at kernel.org>
---
arch/arm/mach-kirkwood/include/mach/cpu.h | 3 -
arch/arm/mach-mvebu/include/mach/cpu.h | 3 -
arch/arm/mach-mvebu/mbus.c | 167 +++++++++-------------
board/alliedtelesis/x530/x530.c | 2 +-
board/maxbcm/maxbcm.c | 8 +-
board/theadorable/theadorable.c | 4 +-
include/linux/mbus.h | 13 +-
7 files changed, 75 insertions(+), 125 deletions(-)
diff --git a/arch/arm/mach-kirkwood/include/mach/cpu.h b/arch/arm/mach-kirkwood/include/mach/cpu.h
index 71c546f9acf6..d8639c60352b 100644
--- a/arch/arm/mach-kirkwood/include/mach/cpu.h
+++ b/arch/arm/mach-kirkwood/include/mach/cpu.h
@@ -144,9 +144,6 @@ struct kwgpio_registers {
u32 irq_level;
};
-/* Needed for dynamic (board-specific) mbus configuration */
-extern struct mvebu_mbus_state mbus_state;
-
/*
* functions
*/
diff --git a/arch/arm/mach-mvebu/include/mach/cpu.h b/arch/arm/mach-mvebu/include/mach/cpu.h
index 689c96bd4eac..d9fa1f32aa52 100644
--- a/arch/arm/mach-mvebu/include/mach/cpu.h
+++ b/arch/arm/mach-mvebu/include/mach/cpu.h
@@ -122,9 +122,6 @@ struct sar_freq_modes {
u32 d_clk;
};
-/* Needed for dynamic (board-specific) mbus configuration */
-extern struct mvebu_mbus_state mbus_state;
-
/*
* functions
*/
diff --git a/arch/arm/mach-mvebu/mbus.c b/arch/arm/mach-mvebu/mbus.c
index 3b1b9f73ebf6..7092f6cc10c2 100644
--- a/arch/arm/mach-mvebu/mbus.c
+++ b/arch/arm/mach-mvebu/mbus.c
@@ -88,31 +88,34 @@
#define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4)
-struct mvebu_mbus_state;
-
-struct mvebu_mbus_soc_data {
- unsigned int num_wins;
- unsigned int num_remappable_wins;
- unsigned int (*win_cfg_offset)(const int win);
- void (*setup_cpu_target)(struct mvebu_mbus_state *s);
-};
-
-struct mvebu_mbus_state mbus_state
- __section(".data");
static struct mbus_dram_target_info mbus_dram_info
__section(".data");
+#if defined(CONFIG_ARCH_MVEBU)
+ #define MVEBU_MBUS_NUM_WINS 20
+ #define MVEBU_MBUS_NUM_REMAPPABLE_WINS 8
+ #define MVEBU_MBUS_WIN_CFG_OFFSET(win) armada_370_xp_mbus_win_offset(win)
+#elif defined(CONFIG_ARCH_KIRKWOOD)
+ #define MVEBU_MBUS_NUM_WINS 8
+ #define MVEBU_MBUS_NUM_REMAPPABLE_WINS 4
+ #define MVEBU_MBUS_WIN_CFG_OFFSET(win) orion5x_mbus_win_offset(win)
+#else
+ #error "No supported architecture"
+#endif
+
+static unsigned int armada_370_xp_mbus_win_offset(int win);
+static unsigned int orion5x_mbus_win_offset(int win);
+
/*
* Functions to manipulate the address decoding windows
*/
-static void mvebu_mbus_read_window(struct mvebu_mbus_state *mbus,
- int win, int *enabled, u64 *base,
+static void mvebu_mbus_read_window(int win, int *enabled, u64 *base,
u32 *size, u8 *target, u8 *attr,
u64 *remap)
{
- void __iomem *addr = mbus->mbuswins_base +
- mbus->soc->win_cfg_offset(win);
+ void __iomem *addr = (void __iomem *)MVEBU_CPU_WIN_BASE +
+ MVEBU_MBUS_WIN_CFG_OFFSET(win);
u32 basereg = readl(addr + WIN_BASE_OFF);
u32 ctrlreg = readl(addr + WIN_CTRL_OFF);
@@ -133,7 +136,7 @@ static void mvebu_mbus_read_window(struct mvebu_mbus_state *mbus,
*attr = (ctrlreg & WIN_CTRL_ATTR_MASK) >> WIN_CTRL_ATTR_SHIFT;
if (remap) {
- if (win < mbus->soc->num_remappable_wins) {
+ if (win < MVEBU_MBUS_NUM_REMAPPABLE_WINS) {
u32 remap_low = readl(addr + WIN_REMAP_LO_OFF);
u32 remap_hi = readl(addr + WIN_REMAP_HI_OFF);
*remap = ((u64)remap_hi << 32) | remap_low;
@@ -143,27 +146,25 @@ static void mvebu_mbus_read_window(struct mvebu_mbus_state *mbus,
}
}
-static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus,
- int win)
+static void mvebu_mbus_disable_window(int win)
{
void __iomem *addr;
- addr = mbus->mbuswins_base + mbus->soc->win_cfg_offset(win);
+ addr = (void __iomem *)MVEBU_CPU_WIN_BASE + MVEBU_MBUS_WIN_CFG_OFFSET(win);
writel(0, addr + WIN_BASE_OFF);
writel(0, addr + WIN_CTRL_OFF);
- if (win < mbus->soc->num_remappable_wins) {
+ if (win < MVEBU_MBUS_NUM_REMAPPABLE_WINS) {
writel(0, addr + WIN_REMAP_LO_OFF);
writel(0, addr + WIN_REMAP_HI_OFF);
}
}
/* Checks whether the given window number is available */
-static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus,
- const int win)
+static int mvebu_mbus_window_is_free(const int win)
{
- void __iomem *addr = mbus->mbuswins_base +
- mbus->soc->win_cfg_offset(win);
+ void __iomem *addr = (void __iomem *)MVEBU_CPU_WIN_BASE +
+ MVEBU_MBUS_WIN_CFG_OFFSET(win);
u32 ctrl = readl(addr + WIN_CTRL_OFF);
return !(ctrl & WIN_CTRL_ENABLE);
}
@@ -172,20 +173,19 @@ static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus,
* Checks whether the given (base, base+size) area doesn't overlap an
* existing region
*/
-static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus,
- phys_addr_t base, size_t size,
+static int mvebu_mbus_window_conflicts(phys_addr_t base, size_t size,
u8 target, u8 attr)
{
u64 end = (u64)base + size;
int win;
- for (win = 0; win < mbus->soc->num_wins; win++) {
+ for (win = 0; win < MVEBU_MBUS_NUM_WINS; win++) {
u64 wbase, wend;
u32 wsize;
u8 wtarget, wattr;
int enabled;
- mvebu_mbus_read_window(mbus, win,
+ mvebu_mbus_read_window(win,
&enabled, &wbase, &wsize,
&wtarget, &wattr, NULL);
@@ -211,17 +211,16 @@ static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus,
return 1;
}
-static int mvebu_mbus_find_window(struct mvebu_mbus_state *mbus,
- phys_addr_t base, size_t size)
+static int mvebu_mbus_find_window(phys_addr_t base, size_t size)
{
int win;
- for (win = 0; win < mbus->soc->num_wins; win++) {
+ for (win = 0; win < MVEBU_MBUS_NUM_WINS; win++) {
u64 wbase;
u32 wsize;
int enabled;
- mvebu_mbus_read_window(mbus, win,
+ mvebu_mbus_read_window(win,
&enabled, &wbase, &wsize,
NULL, NULL, NULL);
@@ -235,13 +234,12 @@ static int mvebu_mbus_find_window(struct mvebu_mbus_state *mbus,
return -ENODEV;
}
-static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus,
- int win, phys_addr_t base, size_t size,
+static int mvebu_mbus_setup_window(int win, phys_addr_t base, size_t size,
phys_addr_t remap, u8 target,
u8 attr)
{
- void __iomem *addr = mbus->mbuswins_base +
- mbus->soc->win_cfg_offset(win);
+ void __iomem *addr = (void __iomem *)MVEBU_CPU_WIN_BASE +
+ MVEBU_MBUS_WIN_CFG_OFFSET(win);
u32 ctrl, remap_addr;
ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) |
@@ -251,7 +249,7 @@ static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus,
writel(base & WIN_BASE_LOW, addr + WIN_BASE_OFF);
writel(ctrl, addr + WIN_CTRL_OFF);
- if (win < mbus->soc->num_remappable_wins) {
+ if (win < MVEBU_MBUS_NUM_REMAPPABLE_WINS) {
if (remap == MVEBU_MBUS_NO_REMAP)
remap_addr = base;
else
@@ -263,26 +261,25 @@ static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus,
return 0;
}
-static int mvebu_mbus_alloc_window(struct mvebu_mbus_state *mbus,
- phys_addr_t base, size_t size,
+static int mvebu_mbus_alloc_window(phys_addr_t base, size_t size,
phys_addr_t remap, u8 target,
u8 attr)
{
int win;
if (remap == MVEBU_MBUS_NO_REMAP) {
- for (win = mbus->soc->num_remappable_wins;
- win < mbus->soc->num_wins; win++)
- if (mvebu_mbus_window_is_free(mbus, win))
- return mvebu_mbus_setup_window(mbus, win, base,
+ for (win = MVEBU_MBUS_NUM_REMAPPABLE_WINS;
+ win < MVEBU_MBUS_NUM_WINS; win++)
+ if (mvebu_mbus_window_is_free(win))
+ return mvebu_mbus_setup_window(win, base,
size, remap,
target, attr);
}
- for (win = 0; win < mbus->soc->num_wins; win++)
- if (mvebu_mbus_window_is_free(mbus, win))
- return mvebu_mbus_setup_window(mbus, win, base, size,
+ for (win = 0; win < MVEBU_MBUS_NUM_WINS; win++)
+ if (mvebu_mbus_window_is_free(win))
+ return mvebu_mbus_setup_window(win, base, size,
remap, target, attr);
return -ENOMEM;
@@ -292,7 +289,7 @@ static int mvebu_mbus_alloc_window(struct mvebu_mbus_state *mbus,
* SoC-specific functions and definitions
*/
-static unsigned int armada_370_xp_mbus_win_offset(int win)
+static unsigned int __maybe_unused armada_370_xp_mbus_win_offset(int win)
{
/* The register layout is a bit annoying and the below code
* tries to cope with it.
@@ -312,12 +309,12 @@ static unsigned int armada_370_xp_mbus_win_offset(int win)
return 0x90 + ((win - 8) << 3);
}
-static unsigned int orion5x_mbus_win_offset(int win)
+static unsigned int __maybe_unused orion5x_mbus_win_offset(int win)
{
return win << 4;
}
-static void mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
+static void mvebu_mbus_default_setup_cpu_target(void)
{
int i;
int cs;
@@ -325,8 +322,8 @@ static void mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
for (i = 0, cs = 0; i < 4; i++) {
- u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
- u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
+ u32 base = readl((void __iomem *)MVEBU_SDRAM_BASE + DDR_BASE_CS_OFF(i));
+ u32 size = readl((void __iomem *)MVEBU_SDRAM_BASE + DDR_SIZE_CS_OFF(i));
/*
* We only take care of entries for which the chip
@@ -349,26 +346,10 @@ static void mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
#if defined(CONFIG_ARMADA_MSYS)
/* Disable MBUS Err Prop - in order to avoid data aborts */
- clrbits_le32(mbus->mbuswins_base + 0x200, BIT(8));
+ clrbits_le32((void __iomem *)MVEBU_CPU_WIN_BASE + 0x200, BIT(8));
#endif
}
-static const struct mvebu_mbus_soc_data
-armada_370_xp_mbus_data __maybe_unused = {
- .num_wins = 20,
- .num_remappable_wins = 8,
- .win_cfg_offset = armada_370_xp_mbus_win_offset,
- .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
-};
-
-static const struct mvebu_mbus_soc_data
-kirkwood_mbus_data __maybe_unused = {
- .num_wins = 8,
- .num_remappable_wins = 4,
- .win_cfg_offset = orion5x_mbus_win_offset,
- .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
-};
-
/*
* Public API of the driver
*/
@@ -382,15 +363,13 @@ int mvebu_mbus_add_window_remap_by_id(unsigned int target,
phys_addr_t base, size_t size,
phys_addr_t remap)
{
- struct mvebu_mbus_state *s = &mbus_state;
-
- if (!mvebu_mbus_window_conflicts(s, base, size, target, attribute)) {
+ if (!mvebu_mbus_window_conflicts(base, size, target, attribute)) {
printf("Cannot add window '%x:%x', conflicts with another window\n",
target, attribute);
return -EINVAL;
}
- return mvebu_mbus_alloc_window(s, base, size, remap, target, attribute);
+ return mvebu_mbus_alloc_window(base, size, remap, target, attribute);
}
int mvebu_mbus_add_window_by_id(unsigned int target, unsigned int attribute,
@@ -404,28 +383,27 @@ int mvebu_mbus_del_window(phys_addr_t base, size_t size)
{
int win;
- win = mvebu_mbus_find_window(&mbus_state, base, size);
+ win = mvebu_mbus_find_window(base, size);
if (win < 0)
return win;
- mvebu_mbus_disable_window(&mbus_state, win);
+ mvebu_mbus_disable_window(win);
return 0;
}
#ifndef CONFIG_ARCH_KIRKWOOD
-static void mvebu_mbus_get_lowest_base(struct mvebu_mbus_state *mbus,
- phys_addr_t *base)
+static void mvebu_mbus_get_lowest_base(phys_addr_t *base)
{
int win;
*base = 0xffffffff;
- for (win = 0; win < mbus->soc->num_wins; win++) {
+ for (win = 0; win < MVEBU_MBUS_NUM_WINS; win++) {
u64 wbase;
u32 wsize;
u8 wtarget, wattr;
int enabled;
- mvebu_mbus_read_window(mbus, win,
+ mvebu_mbus_read_window(win,
&enabled, &wbase, &wsize,
&wtarget, &wattr, NULL);
@@ -437,14 +415,14 @@ static void mvebu_mbus_get_lowest_base(struct mvebu_mbus_state *mbus,
}
}
-static void mvebu_config_mbus_bridge(struct mvebu_mbus_state *mbus)
+static void mvebu_config_mbus_bridge(void)
{
phys_addr_t base;
u32 val;
u32 size;
/* Set MBUS bridge base/ctrl */
- mvebu_mbus_get_lowest_base(&mbus_state, &base);
+ mvebu_mbus_get_lowest_base(&base);
size = 0xffffffff - base + 1;
if (!is_power_of_2(size)) {
@@ -461,10 +439,9 @@ static void mvebu_config_mbus_bridge(struct mvebu_mbus_state *mbus)
}
#endif
-int mbus_dt_setup_win(struct mvebu_mbus_state *mbus,
- u32 base, u32 size, u8 target, u8 attr)
+int mbus_dt_setup_win(u32 base, u32 size, u8 target, u8 attr)
{
- if (!mvebu_mbus_window_conflicts(mbus, base, size, target, attr)) {
+ if (!mvebu_mbus_window_conflicts(base, size, target, attr)) {
printf("Cannot add window '%04x:%04x', conflicts with another window\n",
target, attr);
return -EBUSY;
@@ -474,8 +451,8 @@ int mbus_dt_setup_win(struct mvebu_mbus_state *mbus,
* In U-Boot we first try to add the mbus window to the remap windows.
* If this fails, lets try to add the windows to the non-remap windows.
*/
- if (mvebu_mbus_alloc_window(mbus, base, size, base, target, attr)) {
- if (mvebu_mbus_alloc_window(mbus, base, size,
+ if (mvebu_mbus_alloc_window(base, size, base, target, attr)) {
+ if (mvebu_mbus_alloc_window(base, size,
MVEBU_MBUS_NO_REMAP, target, attr))
return -ENOMEM;
}
@@ -486,7 +463,7 @@ int mbus_dt_setup_win(struct mvebu_mbus_state *mbus,
* is called. Since it may get called from the board code in
* later boot stages as well.
*/
- mvebu_config_mbus_bridge(mbus);
+ mvebu_config_mbus_bridge();
#endif
return 0;
@@ -498,20 +475,10 @@ int mvebu_mbus_probe(struct mbus_win windows[], int count)
int ret;
int i;
-#if defined(CONFIG_ARCH_KIRKWOOD)
- mbus_state.soc = &kirkwood_mbus_data;
-#endif
-#if defined(CONFIG_ARCH_MVEBU)
- mbus_state.soc = &armada_370_xp_mbus_data;
-#endif
-
- mbus_state.mbuswins_base = (void __iomem *)MVEBU_CPU_WIN_BASE;
- mbus_state.sdramwins_base = (void __iomem *)MVEBU_SDRAM_BASE;
-
- for (win = 0; win < mbus_state.soc->num_wins; win++)
- mvebu_mbus_disable_window(&mbus_state, win);
+ for (win = 0; win < MVEBU_MBUS_NUM_WINS; win++)
+ mvebu_mbus_disable_window(win);
- mbus_state.soc->setup_cpu_target(&mbus_state);
+ mvebu_mbus_default_setup_cpu_target();
/* Setup statically declared windows in the DT */
for (i = 0; i < count; i++) {
@@ -522,7 +489,7 @@ int mvebu_mbus_probe(struct mbus_win windows[], int count)
attr = windows[i].attr;
base = windows[i].base;
size = windows[i].size;
- ret = mbus_dt_setup_win(&mbus_state, base, size, target, attr);
+ ret = mbus_dt_setup_win(base, size, target, attr);
if (ret < 0)
return ret;
}
diff --git a/board/alliedtelesis/x530/x530.c b/board/alliedtelesis/x530/x530.c
index cbf4533e78de..0cfb7c522f67 100644
--- a/board/alliedtelesis/x530/x530.c
+++ b/board/alliedtelesis/x530/x530.c
@@ -109,7 +109,7 @@ int board_init(void)
gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
/* window for NVS */
- mbus_dt_setup_win(&mbus_state, CONFIG_NVS_LOCATION, CONFIG_NVS_SIZE,
+ mbus_dt_setup_win(CONFIG_NVS_LOCATION, CONFIG_NVS_SIZE,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_DEV_CS1);
/* DEV_READYn is not needed for NVS, ignore it when accessing CS1 */
diff --git a/board/maxbcm/maxbcm.c b/board/maxbcm/maxbcm.c
index e92132ad19a1..aad3dc864295 100644
--- a/board/maxbcm/maxbcm.c
+++ b/board/maxbcm/maxbcm.c
@@ -112,13 +112,13 @@ int board_early_init_f(void)
/*
* Setup some board specific mbus address windows
*/
- mbus_dt_setup_win(&mbus_state, DEV_CS0_BASE, 16 << 20,
+ mbus_dt_setup_win(DEV_CS0_BASE, 16 << 20,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_DEV_CS0);
- mbus_dt_setup_win(&mbus_state, DEV_CS1_BASE, 16 << 20,
+ mbus_dt_setup_win(DEV_CS1_BASE, 16 << 20,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_DEV_CS1);
- mbus_dt_setup_win(&mbus_state, DEV_CS2_BASE, 16 << 20,
+ mbus_dt_setup_win(DEV_CS2_BASE, 16 << 20,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_DEV_CS2);
- mbus_dt_setup_win(&mbus_state, DEV_CS3_BASE, 16 << 20,
+ mbus_dt_setup_win(DEV_CS3_BASE, 16 << 20,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_DEV_CS3);
return 0;
diff --git a/board/theadorable/theadorable.c b/board/theadorable/theadorable.c
index 6e41ca239919..144f122bb206 100644
--- a/board/theadorable/theadorable.c
+++ b/board/theadorable/theadorable.c
@@ -208,9 +208,9 @@ int board_init(void)
* Map SPI devices via MBUS so that they can be accessed via
* the SPI direct access mode
*/
- mbus_dt_setup_win(&mbus_state, SPI_BUS0_DEV1_BASE, SPI_BUS0_DEV1_SIZE,
+ mbus_dt_setup_win(SPI_BUS0_DEV1_BASE, SPI_BUS0_DEV1_SIZE,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_SPI0_CS1);
- mbus_dt_setup_win(&mbus_state, SPI_BUS1_DEV2_BASE, SPI_BUS0_DEV1_SIZE,
+ mbus_dt_setup_win(SPI_BUS1_DEV2_BASE, SPI_BUS0_DEV1_SIZE,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_SPI1_CS2);
/*
diff --git a/include/linux/mbus.h b/include/linux/mbus.h
index 717cbeab37f5..04112eabe1c2 100644
--- a/include/linux/mbus.h
+++ b/include/linux/mbus.h
@@ -33,16 +33,6 @@ struct mbus_dram_target_info {
} cs[4];
};
-struct mvebu_mbus_state {
- void __iomem *mbuswins_base;
- void __iomem *sdramwins_base;
- struct dentry *debugfs_root;
- struct dentry *debugfs_sdram;
- struct dentry *debugfs_devs;
- const struct mvebu_mbus_soc_data *soc;
- int hw_io_coherency;
-};
-
/* Flags for PCI/PCIe address decoding regions */
#define MVEBU_MBUS_PCI_IO 0x1
#define MVEBU_MBUS_PCI_MEM 0x2
@@ -67,7 +57,6 @@ int mvebu_mbus_add_window_remap_by_id(unsigned int target,
int mvebu_mbus_add_window_by_id(unsigned int target, unsigned int attribute,
phys_addr_t base, size_t size);
int mvebu_mbus_del_window(phys_addr_t base, size_t size);
-int mbus_dt_setup_win(struct mvebu_mbus_state *mbus,
- u32 base, u32 size, u8 target, u8 attr);
+int mbus_dt_setup_win(u32 base, u32 size, u8 target, u8 attr);
#endif /* __LINUX_MBUS_H */
--
2.20.1
More information about the U-Boot
mailing list