diff --git a/arch/arm/lib/arm.c b/arch/arm/lib/arm.c index c85aae1..80b62e9 100644 --- a/arch/arm/lib/arm.c +++ b/arch/arm/lib/arm.c @@ -7,7 +7,7 @@ static int arm_mem_malloc_init(void) { mem_malloc_init((void *)MALLOC_BASE, - (void *)(MALLOC_BASE + MALLOC_SIZE)); + (void *)(MALLOC_BASE + MALLOC_SIZE - 1)); return 0; } diff --git a/arch/blackfin/lib/board.c b/arch/blackfin/lib/board.c index d1b39fa..bf5c1b6 100644 --- a/arch/blackfin/lib/board.c +++ b/arch/blackfin/lib/board.c @@ -38,7 +38,7 @@ int blackfin_mem_malloc_init(void) { mem_malloc_init((void *)(MALLOC_BASE), - (void *)(MALLOC_BASE + MALLOC_SIZE)); + (void *)(MALLOC_BASE + MALLOC_SIZE - 1)); return 0; } diff --git a/arch/mips/lib/memory.c b/arch/mips/lib/memory.c index ad9f6a6..8d2d51b 100644 --- a/arch/mips/lib/memory.c +++ b/arch/mips/lib/memory.c @@ -26,7 +26,7 @@ static int mips_mem_malloc_init(void) { mem_malloc_init((void *)MALLOC_BASE, - (void *)(MALLOC_BASE + MALLOC_SIZE)); + (void *)(MALLOC_BASE + MALLOC_SIZE - 1)); return 0; } core_initcall(mips_mem_malloc_init); diff --git a/arch/nios2/lib/board.c b/arch/nios2/lib/board.c index d50f05a..ed3af49 100644 --- a/arch/nios2/lib/board.c +++ b/arch/nios2/lib/board.c @@ -31,7 +31,7 @@ { mem_malloc_init((void *)(NIOS_SOPC_TEXT_BASE - MALLOC_SIZE), - (void *)(NIOS_SOPC_TEXT_BASE)); + (void *)(NIOS_SOPC_TEXT_BASE - 1)); return 0; } diff --git a/arch/ppc/lib/board.c b/arch/ppc/lib/board.c index 0b610a5..0e839eb 100644 --- a/arch/ppc/lib/board.c +++ b/arch/ppc/lib/board.c @@ -56,7 +56,7 @@ debug("malloc_end: 0x%08x\n", malloc_end); debug("TEXT_BASE after relocation: 0x%08x\n", _text_base); - mem_malloc_init((void *)(malloc_end - MALLOC_SIZE), (void *)malloc_end); + mem_malloc_init((void *)(malloc_end - MALLOC_SIZE), (void *)(malloc_end - 1)); /* * Setup trap handlers diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c index 1c5ae5d..9258c66 100644 --- a/arch/sandbox/os/common.c +++ b/arch/sandbox/os/common.c @@ -262,7 +262,7 @@ printf("unable to get malloc space\n"); exit(1); } - mem_malloc_init(ram, ram + malloc_size); + mem_malloc_init(ram, ram + malloc_size - 1); while (1) { int option_index = 0; diff --git a/arch/x86/lib/memory.c b/arch/x86/lib/memory.c index fa7bc03..1774ef3 100644 --- a/arch/x86/lib/memory.c +++ b/arch/x86/lib/memory.c @@ -54,12 +54,12 @@ */ if (memory_size >= (15 * 1024 * 1024 + MALLOC_SIZE)) mem_malloc_init((void*)(16 * 1024 * 1024), - (void*)(16 * 1024 * 1024) + MALLOC_SIZE); + (void*)(16 * 1024 * 1024 + MALLOC_SIZE - 1)); else return -1; #else mem_malloc_init((void *)MALLOC_BASE, - (void *)(MALLOC_BASE + MALLOC_SIZE)); + (void *)(MALLOC_BASE + MALLOC_SIZE - 1)); #endif return 0; } diff --git a/commands/Kconfig b/commands/Kconfig index c2492fa..2badea3 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -215,6 +215,13 @@ tristate prompt "meminfo" +config CMD_IOMEM + tristate + prompt "iomem" + help + Show information about iomem usage. Pendant to 'cat /proc/iomem' + under Linux. + config CMD_MEMORY bool default y diff --git a/commands/Makefile b/commands/Makefile index f82dcfa..e95fdc3 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -60,3 +60,4 @@ obj-$(CONFIG_CMD_TIME) += time.o obj-$(CONFIG_CMD_OFTREE) += oftree.o obj-$(CONFIG_CMD_MAGICVAR) += magicvar.o +obj-$(CONFIG_CMD_IOMEM) += iomem.o diff --git a/commands/iomem.c b/commands/iomem.c new file mode 100644 index 0000000..78566c1 --- /dev/null +++ b/commands/iomem.c @@ -0,0 +1,56 @@ +/* + * iomem.c - barebox iomem command + * + * Copyright (c) 2011 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation. + */ +#include +#include + +static void __print_resources(struct resource *res, int indent) +{ + struct resource *r; + int i; + + for (i = 0; i < indent; i++) + printf(" "); + + printf("0x%08x - 0x%08x (size 0x%08x) %s\n", res->start, + res->start + res->size - 1, + res->size, res->name); + + list_for_each_entry(r, &res->children, sibling) + __print_resources(r, indent + 1); +} + +static void print_resources(struct resource *res) +{ + __print_resources(res, 0); +} + +static int do_iomem(struct command *cmdtp, int argc, char *argv[]) +{ + print_resources(&iomem_resource); + + return 0; +} + +BAREBOX_CMD_START(iomem) + .cmd = do_iomem, + .usage = "show iomem usage", +BAREBOX_CMD_END diff --git a/common/Makefile b/common/Makefile index 55d9dbc..9bce479 100644 --- a/common/Makefile +++ b/common/Makefile @@ -27,6 +27,7 @@ obj-y += misc.o obj-y += memsize.o obj-y += filetype.o +obj-y += resource.o obj-$(CONFIG_MENU) += menu.o obj-$(CONFIG_PASSWORD) += password.o obj-$(CONFIG_MODULES) += module.o diff --git a/common/memory.c b/common/memory.c index 0ba9a18..7d0f4ca 100644 --- a/common/memory.c +++ b/common/memory.c @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include /* * Begin and End of memory area for malloc(), and current "brk" @@ -50,6 +53,33 @@ malloc_brk = malloc_start; } +static int mem_malloc_resource(void) +{ + /* + * Normally it's a bug when one of these fails, + * but we have some setups where some of these + * regions are outside of sdram in which case + * the following fails. + */ + request_sdram_region("malloc space", + malloc_start, + malloc_end - malloc_start + 1); + request_sdram_region("barebox", + (unsigned long)&_stext, + (unsigned long)&_etext - + (unsigned long)&_stext + 1); + request_sdram_region("bss", + (unsigned long)&__bss_start, + (unsigned long)&__bss_stop - + (unsigned long)&__bss_start + 1); +#ifdef STACK_BASE + request_sdram_region("stack", STACK_BASE, STACK_SIZE); +#endif + + return 0; +} +coredevice_initcall(mem_malloc_resource); + static void *sbrk_no_zero(ptrdiff_t increment) { unsigned long old = malloc_brk; @@ -82,6 +112,10 @@ struct memory_bank *bank = xzalloc(sizeof(*bank)); struct device_d *dev; + bank->res = request_iomem_region(name, start, size); + + BUG_ON(!bank->res); + dev = add_mem_device(name, start, size, IORESOURCE_MEM_WRITEABLE); bank->dev = dev; @@ -91,6 +125,30 @@ list_add_tail(&bank->list, &memory_banks); } +/* + * Request a region from the registered sdram + */ +struct resource *request_sdram_region(const char *name, resource_size_t start, + resource_size_t size) +{ + struct memory_bank *bank; + + for_each_memory_bank(bank) { + struct resource *res; + + res = request_region(bank->res, name, start, size); + if (res) + return res; + } + + return NULL; +} + +int release_sdram_region(struct resource *res) +{ + return release_region(res); +} + #ifdef CONFIG_OFTREE /* diff --git a/common/resource.c b/common/resource.c new file mode 100644 index 0000000..63e9c49 --- /dev/null +++ b/common/resource.c @@ -0,0 +1,121 @@ +/* + * resource.c - barebox resource management + * + * Copyright (c) 2011 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation. + */ +#include +#include +#include +#include +#include + +static int init_resource(struct resource *res, const char *name) +{ + INIT_LIST_HEAD(&res->children); + res->parent = NULL; + res->name = xstrdup(name); + + return 0; +} + +/* + * request a region. + * This will succedd when the requested region is completely inside + * the parent resource and does not conflict with any of the child + * resources. + */ +struct resource *request_region(struct resource *parent, + const char *name, resource_size_t start, + resource_size_t size) +{ + struct resource *r, *new; + + /* outside parent resource? */ + if (start < parent->start || + start + size > parent->start + parent->size) { + debug("%s: 0x%08x:0x%08x outside parent resource 0x%08x:0x%08x\n", + __func__, start, size, parent->start, + parent->size); + return NULL; + } + + /* + * We keep the list of child resources ordered which helps + * us searching for conflicts here. + */ + list_for_each_entry(r, &parent->children, sibling) { + if (start + size <= r->start) + goto ok; + if (start >= r->start + r->size) + continue; + debug("%s: 0x%08x:0x%08x conflicts with 0x%08x:0x%08x\n", + __func__, start, size, r->start, r->size); + return NULL; + } + +ok: + debug("%s ok: 0x%08x 0x%08x\n", __func__, start, size); + + new = xzalloc(sizeof(*new)); + init_resource(new, name); + new->start = start; + new->size = size; + new->parent = parent; + list_add_tail(&new->sibling, &r->sibling); + + return new; +} + +/* + * release a region previously requested with request_region + */ +int release_region(struct resource *res) +{ + if (!list_empty(&res->children)) + return -EBUSY; + + list_del(&res->sibling); + free((char *)res->name); + free(res); + + return 0; +} + +/* The root resource for the whole io space */ +struct resource iomem_resource = { + .start = 0, + .size = ~0, +}; + +/* + * request a region inside the io space + */ +struct resource *request_iomem_region(const char *name, + resource_size_t start, resource_size_t size) +{ + return request_region(&iomem_resource, name, start, size); +} + +static int iomem_init(void) +{ + init_resource(&iomem_resource, "iomem"); + + return 0; +} +postcore_initcall(iomem_init); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 0b80103..0132e7d 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -214,7 +214,7 @@ } EXPORT_SYMBOL(register_driver); -void __iomem *dev_get_mem_region(struct device_d *dev, int num) +static struct resource *dev_get_resource(struct device_d *dev, int num) { int i, n = 0; @@ -222,15 +222,40 @@ struct resource *res = &dev->resource[i]; if (resource_type(res) == IORESOURCE_MEM) { if (n == num) - return (void __force __iomem *)res->start; + return res; n++; } } return NULL; } + +void __iomem *dev_get_mem_region(struct device_d *dev, int num) +{ + struct resource *res; + + res = dev_get_resource(dev, num); + if (!res) + return res; + + return (void __force __iomem *)res->start; +} EXPORT_SYMBOL(dev_get_mem_region); +void __iomem *dev_request_mem_region(struct device_d *dev, int num) +{ + struct resource *res; + + res = dev_get_resource(dev, num); + if (!res) + return NULL; + + res = request_iomem_region(dev_name(dev), res->start, res->size); + + return (void __force __iomem *)res->start; +} +EXPORT_SYMBOL(dev_request_mem_region); + int dev_protect(struct device_d *dev, size_t count, unsigned long offset, int prot) { printf("%s: currently broken\n", __func__); diff --git a/include/driver.h b/include/driver.h index fe9d37a..bbe7248 100644 --- a/include/driver.h +++ b/include/driver.h @@ -190,11 +190,7 @@ /* * exlusively request register base 'num' for a device */ -static inline void __iomem *dev_request_mem_region(struct device_d *dev, int num) -{ - /* no resource tracking yet */ - return dev_get_mem_region(dev, num); -} +void __iomem *dev_request_mem_region(struct device_d *dev, int num); /* * register a generic device diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 5143115..c837b53 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -20,6 +20,9 @@ resource_size_t size; const char *name; unsigned long flags; + struct resource *parent; + struct list_head children; + struct list_head sibling; }; /* @@ -111,5 +114,16 @@ return res->flags & IORESOURCE_TYPE_BITS; } +struct resource *request_iomem_region(const char *name, + resource_size_t start, resource_size_t size); + +struct resource *request_region(struct resource *parent, + const char *name, resource_size_t start, + resource_size_t size); + +int release_region(struct resource *res); + +extern struct resource iomem_resource; + #endif /* __ASSEMBLY__ */ #endif /* _LINUX_IOPORT_H */ diff --git a/include/memory.h b/include/memory.h index cb185af..4be4340 100644 --- a/include/memory.h +++ b/include/memory.h @@ -13,6 +13,7 @@ struct device_d *dev; unsigned long start; unsigned long size; + struct resource *res; }; extern struct list_head memory_banks; @@ -22,4 +23,8 @@ #define for_each_memory_bank(mem) list_for_each_entry(mem, &memory_banks, list) +struct resource *request_sdram_region(const char *name, resource_size_t start, + resource_size_t size); +int release_sdram_region(struct resource *res); + #endif