Hello, [Sending this for the third time -- if others don't care then at least my MS02-NV driver depends on proper memory resource reservation.] I discovered /proc/iomem is broken for system memory resources. Apparently since highmem support went in. Here are fixes and a few updates as follows: 1. Resource areas are measured in bytes and not pages (that's the problem metioned above). Includes fixes for off-by-one errors for upper limits. 2. Moved mips bootmem allocation and resource reservation to bootmem_init similarly to mips64. 3. Added resource reservation for mips64. Maciej -- + Maciej W. Rozycki, Technical University of Gdansk, Poland + +--------------------------------------------------------------+ + e-mail: macro@ds2.pg.gda.pl, PGP key available + patch-mips-2.4.19-rc1-20020904-mem-regions-7 diff -up --recursive --new-file linux-mips-2.4.19-rc1-20020904.macro/arch/mips/kernel/setup.c linux-mips-2.4.19-rc1-20020904/arch/mips/kernel/setup.c --- linux-mips-2.4.19-rc1-20020904.macro/arch/mips/kernel/setup.c 2002-09-03 02:56:40.000000000 +0000 +++ linux-mips-2.4.19-rc1-20020904/arch/mips/kernel/setup.c 2002-09-09 09:51:38.000000000 +0000 @@ -7,7 +7,7 @@ * Copyright (C) 1995 Waldorf Electronics * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001 Ralf Baechle * Copyright (C) 1996 Stoned Elipot - * Copyright (C) 2000, 2001 Maciej W. Rozycki + * Copyright (C) 2000, 2001, 2002 Maciej W. Rozycki */ #include <linux/config.h> #include <linux/errno.h> @@ -236,6 +236,235 @@ static inline void parse_mem_cmdline(voi } } + +#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + +#define MAXMEM HIGHMEM_START +#define MAXMEM_PFN PFN_DOWN(MAXMEM) + +static inline void bootmem_init(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + unsigned long tmp; + unsigned long *initrd_header; +#endif + unsigned long bootmap_size; + unsigned long start_pfn, max_pfn, max_low_pfn, first_usable_pfn; + int i; + +#ifdef CONFIG_BLK_DEV_INITRD + tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; + if (tmp < (unsigned long)&_end) + tmp += PAGE_SIZE; + initrd_header = (unsigned long *)tmp; + if (initrd_header[0] == 0x494E5244) { + initrd_start = (unsigned long)&initrd_header[2]; + initrd_end = initrd_start + initrd_header[1]; + } + start_pfn = PFN_UP(__pa((&_end)+(initrd_end - initrd_start) + PAGE_SIZE)); +#else + /* + * Partially used pages are not usable - thus + * we are rounding upwards. + */ + start_pfn = PFN_UP(__pa(&_end)); +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Find the highest page frame number we have available. */ + max_pfn = 0; + first_usable_pfn = -1UL; + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long start, end; + + if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + continue; + + start = PFN_UP(boot_mem_map.map[i].addr); + end = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + + if (start >= end) + continue; + if (end > max_pfn) + max_pfn = end; + if (start < first_usable_pfn) { + if (start > start_pfn) { + first_usable_pfn = start; + } else if (end > start_pfn) { + first_usable_pfn = start_pfn; + } + } + } + + /* + * Determine low and high memory ranges + */ + max_low_pfn = max_pfn; + if (max_low_pfn > MAXMEM_PFN) { + max_low_pfn = MAXMEM_PFN; +#ifndef CONFIG_HIGHMEM + /* Maximum memory usable is what is directly addressable */ + printk(KERN_WARNING "Warning only %ldMB will be used.\n", + MAXMEM>>20); + printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); +#endif + } + +#ifdef CONFIG_HIGHMEM + /* + * Crude, we really should make a better attempt at detecting + * highstart_pfn + */ + highstart_pfn = highend_pfn = max_pfn; + if (max_pfn > MAXMEM_PFN) { + highstart_pfn = MAXMEM_PFN; + printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", + (highend_pfn - highstart_pfn) >> (20 - PAGE_SHIFT)); + } +#endif + + /* Initialize the boot-time allocator with low memory only. */ + bootmap_size = init_bootmem(first_usable_pfn, max_low_pfn); + + /* + * Register fully available low RAM pages with the bootmem allocator. + */ + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long curr_pfn, last_pfn, size; + + /* + * Reserve usable memory. + */ + if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + continue; + + /* + * We are rounding up the start address of usable memory: + */ + curr_pfn = PFN_UP(boot_mem_map.map[i].addr); + if (curr_pfn >= max_low_pfn) + continue; + if (curr_pfn < start_pfn) + curr_pfn = start_pfn; + + /* + * ... and at the end of the usable range downwards: + */ + last_pfn = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + + if (last_pfn > max_low_pfn) + last_pfn = max_low_pfn; + + /* + * Only register lowmem part of lowmem segment with bootmem. + */ + size = last_pfn - curr_pfn; + if (curr_pfn > PFN_DOWN(HIGHMEM_START)) + continue; + if (curr_pfn + size - 1 > PFN_DOWN(HIGHMEM_START)) + size = PFN_DOWN(HIGHMEM_START) - curr_pfn; + if (!size) + continue; + + /* + * ... finally, did all the rounding and playing + * around just make the area go away? + */ + if (last_pfn <= curr_pfn) + continue; + + /* Register lowmem ranges */ + free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); + } + + /* Reserve the bootmap memory. */ + reserve_bootmem(PFN_PHYS(first_usable_pfn), bootmap_size); + +#ifdef CONFIG_BLK_DEV_INITRD + /* Board specific code should have set up initrd_start and initrd_end */ + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + if (&__rd_start != &__rd_end) { + initrd_start = (unsigned long)&__rd_start; + initrd_end = (unsigned long)&__rd_end; + } + initrd_below_start_ok = 1; + if (initrd_start) { + unsigned long initrd_size = ((unsigned char *)initrd_end) - ((unsigned char *)initrd_start); + printk("Initial ramdisk at: 0x%p (%lu bytes)\n", + (void *)initrd_start, + initrd_size); + if (PHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + PHYSADDR(initrd_end), + PFN_PHYS(max_low_pfn)); + initrd_start = initrd_end = 0; + } + } +#endif /* CONFIG_BLK_DEV_INITRD */ +} + +static inline void resource_init(void) +{ + int i; + + code_resource.start = virt_to_bus(&_ftext); + code_resource.end = virt_to_bus(&_etext) - 1; + data_resource.start = virt_to_bus(&_fdata); + data_resource.end = virt_to_bus(&_edata) - 1; + + /* + * Request address space for all standard RAM. + */ + for (i = 0; i < boot_mem_map.nr_map; i++) { + struct resource *res; + unsigned long start, end; + + start = boot_mem_map.map[i].addr; + end = boot_mem_map.map[i].addr + boot_mem_map.map[i].size - 1; + if (start >= MAXMEM) + continue; + if (end >= MAXMEM) + end = MAXMEM - 1; + + res = alloc_bootmem(sizeof(struct resource)); + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + case BOOT_MEM_ROM_DATA: + res->name = "System RAM"; + break; + case BOOT_MEM_RESERVED: + default: + res->name = "reserved"; + } + + res->start = start; + res->end = end; + + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + request_resource(&iomem_resource, res); + + /* + * We dont't know which RAM region contains kernel data, + * so we try it repeatedly and let the resource manager + * test it. + */ + request_resource(res, &code_resource); + request_resource(res, &data_resource); + } +} + +#undef PFN_UP +#undef PFN_DOWN +#undef PFN_PHYS + +#undef MAXMEM +#undef MAXMEM_PFN + + void __init setup_arch(char **cmdline_p) { void atlas_setup(void); @@ -247,7 +476,7 @@ void __init setup_arch(char **cmdline_p) void jazz_setup(void); void sni_rm200_pci_setup(void); void ip22_setup(void); - void ev96100_setup(void); + void ev96100_setup(void); void malta_setup(void); void sead_setup(void); void ikos_setup(void); @@ -262,15 +491,6 @@ void __init setup_arch(char **cmdline_p) void swarm_setup(void); void hp_setup(void); - unsigned long bootmap_size; - unsigned long start_pfn, max_pfn, max_low_pfn, first_usable_pfn; -#ifdef CONFIG_BLK_DEV_INITRD - unsigned long tmp; - unsigned long* initrd_header; -#endif - - int i; - #ifdef CONFIG_BLK_DEV_FD fd_ops = &no_fd_ops; #endif @@ -441,210 +661,11 @@ void __init setup_arch(char **cmdline_p) parse_mem_cmdline(); -#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) -#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) -#define PFN_PHYS(x) ((x) << PAGE_SHIFT) - -#define MAXMEM HIGHMEM_START -#define MAXMEM_PFN PFN_DOWN(MAXMEM) - -#ifdef CONFIG_BLK_DEV_INITRD - tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; - if (tmp < (unsigned long)&_end) - tmp += PAGE_SIZE; - initrd_header = (unsigned long *)tmp; - if (initrd_header[0] == 0x494E5244) { - initrd_start = (unsigned long)&initrd_header[2]; - initrd_end = initrd_start + initrd_header[1]; - } - start_pfn = PFN_UP(__pa((&_end)+(initrd_end - initrd_start) + PAGE_SIZE)); -#else - /* - * Partially used pages are not usable - thus - * we are rounding upwards. - */ - start_pfn = PFN_UP(__pa(&_end)); -#endif /* CONFIG_BLK_DEV_INITRD */ - - /* Find the highest page frame number we have available. */ - max_pfn = 0; - first_usable_pfn = -1UL; - for (i = 0; i < boot_mem_map.nr_map; i++) { - unsigned long start, end; - - if (boot_mem_map.map[i].type != BOOT_MEM_RAM) - continue; - - start = PFN_UP(boot_mem_map.map[i].addr); - end = PFN_DOWN(boot_mem_map.map[i].addr - + boot_mem_map.map[i].size); - - if (start >= end) - continue; - if (end > max_pfn) - max_pfn = end; - if (start < first_usable_pfn) { - if (start > start_pfn) { - first_usable_pfn = start; - } else if (end > start_pfn) { - first_usable_pfn = start_pfn; - } - } - } - - /* - * Determine low and high memory ranges - */ - max_low_pfn = max_pfn; - if (max_low_pfn > MAXMEM_PFN) { - max_low_pfn = MAXMEM_PFN; -#ifndef CONFIG_HIGHMEM - /* Maximum memory usable is what is directly addressable */ - printk(KERN_WARNING "Warning only %ldMB will be used.\n", - MAXMEM>>20); - printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); -#endif - } - -#ifdef CONFIG_HIGHMEM - /* - * Crude, we really should make a better attempt at detecting - * highstart_pfn - */ - highstart_pfn = highend_pfn = max_pfn; - if (max_pfn > MAXMEM_PFN) { - highstart_pfn = MAXMEM_PFN; - printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", - (highend_pfn - highstart_pfn) >> (20 - PAGE_SHIFT)); - } -#endif - - /* Initialize the boot-time allocator with low memory only. */ - bootmap_size = init_bootmem(first_usable_pfn, max_low_pfn); - - /* - * Register fully available low RAM pages with the bootmem allocator. - */ - for (i = 0; i < boot_mem_map.nr_map; i++) { - unsigned long curr_pfn, last_pfn, size; - - /* - * Reserve usable memory. - */ - if (boot_mem_map.map[i].type != BOOT_MEM_RAM) - continue; - - /* - * We are rounding up the start address of usable memory: - */ - curr_pfn = PFN_UP(boot_mem_map.map[i].addr); - if (curr_pfn >= max_low_pfn) - continue; - if (curr_pfn < start_pfn) - curr_pfn = start_pfn; - - /* - * ... and at the end of the usable range downwards: - */ - last_pfn = PFN_DOWN(boot_mem_map.map[i].addr - + boot_mem_map.map[i].size); - - if (last_pfn > max_low_pfn) - last_pfn = max_low_pfn; - - /* - * Only register lowmem part of lowmem segment with bootmem. - */ - size = last_pfn - curr_pfn; - if (curr_pfn > PFN_DOWN(HIGHMEM_START)) - continue; - if (curr_pfn + size - 1 > PFN_DOWN(HIGHMEM_START)) - size = PFN_DOWN(HIGHMEM_START) - curr_pfn; - if (!size) - continue; - - /* - * ... finally, did all the rounding and playing - * around just make the area go away? - */ - if (last_pfn <= curr_pfn) - continue; - - /* Register lowmem ranges */ - free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); - } - - /* Reserve the bootmap memory. */ - reserve_bootmem(PFN_PHYS(first_usable_pfn), bootmap_size); - -#ifdef CONFIG_BLK_DEV_INITRD - /* Board specific code should have set up initrd_start and initrd_end */ - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); - if (&__rd_start != &__rd_end) { - initrd_start = (unsigned long)&__rd_start; - initrd_end = (unsigned long)&__rd_end; - } - initrd_below_start_ok = 1; - if (initrd_start) { - unsigned long initrd_size = ((unsigned char *)initrd_end) - ((unsigned char *)initrd_start); - printk("Initial ramdisk at: 0x%p (%lu bytes)\n", - (void *)initrd_start, - initrd_size); - if (PHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) { - printk("initrd extends beyond end of memory " - "(0x%lx > 0x%p)\ndisabling initrd\n", - PHYSADDR(initrd_end), - PFN_PHYS(max_low_pfn)); - initrd_start = initrd_end = 0; - } - } -#endif /* CONFIG_BLK_DEV_INITRD */ + bootmem_init(); paging_init(); - code_resource.start = virt_to_bus(&_ftext); - code_resource.end = virt_to_bus(&_etext) - 1; - data_resource.start = virt_to_bus(&_fdata); - data_resource.end = virt_to_bus(&_edata) - 1; - - /* - * Request address space for all standard RAM. - */ - for (i = 0; i < boot_mem_map.nr_map; i++) { - struct resource *res; - unsigned long addr_pfn, end_pfn; - - res = alloc_bootmem(sizeof(struct resource)); - switch (boot_mem_map.map[i].type) { - case BOOT_MEM_RAM: - case BOOT_MEM_ROM_DATA: - res->name = "System RAM"; - break; - case BOOT_MEM_RESERVED: - default: - res->name = "reserved"; - } - addr_pfn = PFN_UP(boot_mem_map.map[i].addr); - end_pfn = PFN_UP(boot_mem_map.map[i].addr+boot_mem_map.map[i].size); - if (addr_pfn > max_low_pfn) - continue; - res->start = boot_mem_map.map[i].addr; - if (end_pfn < max_low_pfn) { - res->end = res->start + boot_mem_map.map[i].size - 1; - } else { - res->end = max_low_pfn - 1; - } - res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; - request_resource(&iomem_resource, res); - - /* - * We dont't know which RAM region contains kernel data, - * so we try it repeatedly and let the resource manager - * test it. - */ - request_resource(res, &code_resource); - request_resource(res, &data_resource); - } + resource_init(); } static int __init fpu_disable(char *s) diff -up --recursive --new-file linux-mips-2.4.19-rc1-20020904.macro/arch/mips64/kernel/setup.c linux-mips-2.4.19-rc1-20020904/arch/mips64/kernel/setup.c --- linux-mips-2.4.19-rc1-20020904.macro/arch/mips64/kernel/setup.c 2002-09-03 02:58:10.000000000 +0000 +++ linux-mips-2.4.19-rc1-20020904/arch/mips64/kernel/setup.c 2002-09-08 23:28:19.000000000 +0000 @@ -13,6 +13,7 @@ #include <linux/config.h> #include <linux/errno.h> #include <linux/init.h> +#include <linux/ioport.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> @@ -88,8 +89,7 @@ unsigned long mips_machgroup = MACH_GROU struct boot_mem_map boot_mem_map; unsigned char aux_device_present; - -extern void load_mmu(void); +extern char _ftext, _etext, _fdata, _edata, _end; static char command_line[CL_SIZE] = { 0, }; char saved_command_line[CL_SIZE]; @@ -119,6 +119,9 @@ extern void load_mmu(void); extern ATTRIB_NORET asmlinkage void start_kernel(void); extern void prom_init(int, char **, char **, int *); +static struct resource code_resource = { "Kernel code" }; +static struct resource data_resource = { "Kernel data" }; + asmlinkage void __init init_arch(int argc, char **argv, char **envp, int *prom_vec) { @@ -243,7 +246,12 @@ static inline void parse_mem_cmdline(voi } } -void bootmem_init(void) + +#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + +static inline void bootmem_init(void) { #ifdef CONFIG_BLK_DEV_INITRD unsigned long tmp; @@ -252,11 +260,6 @@ void bootmem_init(void) unsigned long bootmap_size; unsigned long start_pfn, max_pfn; int i; - extern int _end; - -#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) -#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) -#define PFN_PHYS(x) ((x) << PAGE_SHIFT) /* * Partially used pages are not usable - thus @@ -349,12 +352,55 @@ void bootmem_init(void) *memory_start_p = initrd_end; } #endif +} + +static inline void resource_init(void) +{ + int i; + + code_resource.start = virt_to_bus(&_ftext); + code_resource.end = virt_to_bus(&_etext) - 1; + data_resource.start = virt_to_bus(&_fdata); + data_resource.end = virt_to_bus(&_edata) - 1; + + /* + * Request address space for all standard RAM. + */ + for (i = 0; i < boot_mem_map.nr_map; i++) { + struct resource *res; + + res = alloc_bootmem(sizeof(struct resource)); + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + case BOOT_MEM_ROM_DATA: + res->name = "System RAM"; + break; + case BOOT_MEM_RESERVED: + default: + res->name = "reserved"; + } + + res->start = boot_mem_map.map[i].addr; + res->end = boot_mem_map.map[i].addr + + boot_mem_map.map[i].size - 1; + + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + request_resource(&iomem_resource, res); + + /* + * We dont't know which RAM region contains kernel data, + * so we try it repeatedly and let the resource manager + * test it. + */ + request_resource(res, &code_resource); + request_resource(res, &data_resource); + } +} #undef PFN_UP #undef PFN_DOWN #undef PFN_PHYS -} void __init setup_arch(char **cmdline_p) { @@ -385,6 +431,8 @@ void __init setup_arch(char **cmdline_p) bootmem_init(); paging_init(); + + resource_init(); } int __init fpu_disable(char *s)