diff --git a/arch/mips/generic/board-sead3.c b/arch/mips/generic/board-sead3.c index 63fdc98738ba..97186a3a5d21 100644 --- a/arch/mips/generic/board-sead3.c +++ b/arch/mips/generic/board-sead3.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,15 @@ #define MIPS_REVISION_MACHINE (0xf << 4) #define MIPS_REVISION_MACHINE_SEAD3 (0x4 << 4) +/* + * Maximum 384MB RAM at physical address 0, preceding any I/O. + */ +static struct yamon_mem_region mem_regions[] __initdata = { + /* start size */ + { 0, SZ_256M + SZ_128M }, + {} +}; + static __init bool sead3_detect(void) { uint32_t rev; @@ -34,6 +44,11 @@ static __init bool sead3_detect(void) return (rev & MIPS_REVISION_MACHINE) == MIPS_REVISION_MACHINE_SEAD3; } +static __init int append_memory(void *fdt) +{ + return yamon_dt_append_memory(fdt, mem_regions); +} + static __init int remove_gic(void *fdt) { const unsigned int cpu_ehci_int = 2; @@ -145,7 +160,7 @@ static __init const void *sead3_fixup_fdt(const void *fdt, if (err) panic("Unable to patch FDT: %d", err); - err = yamon_dt_append_memory(fdt_buf); + err = append_memory(fdt_buf); if (err) panic("Unable to patch FDT: %d", err); diff --git a/arch/mips/generic/yamon-dt.c b/arch/mips/generic/yamon-dt.c index 9a0c8da5a796..8e36a5baaa7e 100644 --- a/arch/mips/generic/yamon-dt.c +++ b/arch/mips/generic/yamon-dt.c @@ -17,6 +17,9 @@ #include #include +#include + +#define MAX_MEM_ARRAY_ENTRIES 2 __init int yamon_dt_append_cmdline(void *fdt) { @@ -43,23 +46,64 @@ __init int yamon_dt_append_cmdline(void *fdt) return 0; } -__init int yamon_dt_append_memory(void *fdt) +static unsigned int __init gen_fdt_mem_array( + const struct yamon_mem_region *regions, + __be32 *mem_array, + unsigned int max_entries, + unsigned long memsize) +{ + const struct yamon_mem_region *mr; + unsigned long size; + unsigned int entries = 0; + + for (mr = regions; mr->size && memsize; ++mr) { + if (entries >= max_entries) { + pr_warn("Number of regions exceeds max %u\n", + max_entries); + break; + } + + /* How much of the remaining RAM fits in the next region? */ + size = min_t(unsigned long, memsize, mr->size); + memsize -= size; + + /* Emit a memory region */ + *(mem_array++) = cpu_to_be32(mr->start); + *(mem_array++) = cpu_to_be32(size); + ++entries; + + /* Discard the next mr->discard bytes */ + memsize -= min_t(unsigned long, memsize, mr->discard); + } + return entries; +} + +__init int yamon_dt_append_memory(void *fdt, + const struct yamon_mem_region *regions) { unsigned long phys_memsize, memsize; - __be32 mem_array[2]; - int err, mem_off; - char *var; + __be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES]; + unsigned int mem_entries; + int i, err, mem_off; + char *var, param_name[10], *var_names[] = { + "ememsize", "memsize", + }; /* find memory size from the bootloader environment */ - var = fw_getenv("memsize"); - if (var) { + for (i = 0; i < ARRAY_SIZE(var_names); i++) { + var = fw_getenv(var_names[i]); + if (!var) + continue; + err = kstrtoul(var, 0, &phys_memsize); - if (err) { - pr_err("Failed to read memsize env variable '%s'\n", - var); - return -EINVAL; - } - } else { + if (!err) + break; + + pr_warn("Failed to read the '%s' env variable '%s'\n", + var_names[i], var); + } + + if (!phys_memsize) { pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n"); phys_memsize = 32 << 20; } @@ -68,9 +112,14 @@ __init int yamon_dt_append_memory(void *fdt) memsize = phys_memsize; /* allow the user to override the usable memory */ - var = strstr(arcs_cmdline, "memsize="); - if (var) - memsize = memparse(var + strlen("memsize="), NULL); + for (i = 0; i < ARRAY_SIZE(var_names); i++) { + snprintf(param_name, sizeof(param_name), "%s=", var_names[i]); + var = strstr(arcs_cmdline, param_name); + if (!var) + continue; + + memsize = memparse(var + strlen(param_name), NULL); + } /* if the user says there's more RAM than we thought, believe them */ phys_memsize = max_t(unsigned long, phys_memsize, memsize); @@ -90,18 +139,19 @@ __init int yamon_dt_append_memory(void *fdt) return err; } - mem_array[0] = 0; - mem_array[1] = cpu_to_be32(phys_memsize); - err = fdt_setprop(fdt, mem_off, "reg", mem_array, sizeof(mem_array)); + mem_entries = gen_fdt_mem_array(regions, mem_array, + MAX_MEM_ARRAY_ENTRIES, phys_memsize); + err = fdt_setprop(fdt, mem_off, "reg", + mem_array, mem_entries * 2 * sizeof(mem_array[0])); if (err) { pr_err("Unable to set memory regs property: %d\n", err); return err; } - mem_array[0] = 0; - mem_array[1] = cpu_to_be32(memsize); + mem_entries = gen_fdt_mem_array(regions, mem_array, + MAX_MEM_ARRAY_ENTRIES, memsize); err = fdt_setprop(fdt, mem_off, "linux,usable-memory", - mem_array, sizeof(mem_array)); + mem_array, mem_entries * 2 * sizeof(mem_array[0])); if (err) { pr_err("Unable to set linux,usable-memory property: %d\n", err); return err; diff --git a/arch/mips/include/asm/yamon-dt.h b/arch/mips/include/asm/yamon-dt.h index 3f3367de4836..485cfe3e45e1 100644 --- a/arch/mips/include/asm/yamon-dt.h +++ b/arch/mips/include/asm/yamon-dt.h @@ -11,6 +11,20 @@ #ifndef __MIPS_ASM_YAMON_DT_H__ #define __MIPS_ASM_YAMON_DT_H__ +#include + +/** + * struct yamon_mem_region - Represents a contiguous range of physical RAM. + * @start: Start physical address. + * @size: Maximum size of region. + * @discard: Length of additional memory to discard after the region. + */ +struct yamon_mem_region { + phys_addr_t start; + phys_addr_t size; + phys_addr_t discard; +}; + /** * yamon_dt_append_cmdline() - Append YAMON-provided command line to /chosen * @fdt: the FDT blob @@ -24,14 +38,16 @@ extern __init int yamon_dt_append_cmdline(void *fdt); /** * yamon_dt_append_memory() - Append YAMON-provided memory info to /memory - * @fdt: the FDT blob + * @fdt: the FDT blob + * @regions: zero size terminated array of physical memory regions * * Generate a /memory node in @fdt based upon memory size information provided - * by YAMON in its environment. + * by YAMON in its environment and the @regions array. * * Return: 0 on success, else -errno */ -extern __init int yamon_dt_append_memory(void *fdt); +extern __init int yamon_dt_append_memory(void *fdt, + const struct yamon_mem_region *regions); /** * yamon_dt_serial_config() - Append YAMON-provided serial config to /chosen