ppc64: Add mem=X option, updated NUMA support
PATCH 1/1 ppc64: Add mem=X option, updated NUMA support
Hi Mike,
Here's an updated version of my mem=X patch with new NUMA code. Sorry it took so long I've been a bit crook.
Can you test this on your 720 or whatever it was? And if anyone else has an interesting NUMA machine they can test it on I'd love to hear about it!
This also includes a fix for the bug Maneesh found last week with GCC 3.3 generating a switch table in prom_init.c, which doesn't work.
I've boot tested this on pSeries LPAR and I'll get it going on a G5, and Power3 tomorrow. Hopefully that'll go well and it'll boot on the 720, and then we can merge it, fingers x'ed!
NB. This applies on top of the other two NUMA fixes I just sent. If they're no good let me know and I'll roll this doobie again without them.
cheers
arch/ppc64/kernel/iSeries_setup.c | 38 +++++++--- arch/ppc64/kernel/lmb.c | 33 +++++++++ arch/ppc64/kernel/prom.c | 15 ++++ arch/ppc64/kernel/prom_init.c | 137 +++++++++++++++++++++++++++++++++++--- arch/ppc64/kernel/setup.c | 20 ++++- arch/ppc64/mm/hash_utils.c | 23 +++++- arch/ppc64/mm/numa.c | 55 ++++++++++++--- include/asm-ppc64/lmb.h | 1 8 files changed, 284 insertions(+), 38 deletions(-)
arch/ppc64/kernel/setup.c +15 -5
@@ -642,12 +642,11 @@ void __init setup_system(void) early_console_initialized =1 ;register_console (&udbg_console); -#endif /* !CONFIG_PPC_ISERIES */ -/* Save unparsed command line copy for /proc/cmdline */ strlcpy (saved_command_line, cmd_line,COMMAND_LINE_SIZE );parse_early_param (); +#endif /* !CONFIG_PPC_ISERIES */ #if defined(CONFIG_SMP ) && !defined(CONFIG_PPC_ISERIES )/*
@@ -806,20 +805,31 @@ struct seq_operations cpuinfo_op = { .show = show_cpuinfo, }; -#if 0 /* XXX not currently used */ +/* +* These three variables are used to save values passed to us by prom_init() +* via the device tree. The TCE variables are needed because with a memory_limit +* in force we may need to explicitly map the TCE are at the top of RAM. +*/ unsigned long memory_limit; +unsigned long tce_alloc_start; +unsigned long tce_alloc_end; +#ifdef CONFIG_PPC_ISERIES +/* +* On iSeries we just parse the mem=X option from the command line. +* On pSeries it's a bit more complicated, see prom_init_mem() +*/ static int __init early_parsemem (char *p) {if (!p)return 0 ; - memory_limit =memparse (p, &p); + memory_limit =ALIGN (memparse (p, &p),PAGE_SIZE );return 0 ; }early_param ("mem" , early_parsemem); -#endif +#endif /* CONFIG_PPC_ISERIES */ #ifdef CONFIG_PPC_MULTIPLATFORM static int __init set_preferred_console (void )
arch/ppc64/kernel/lmb.c +33 -0
@@ -344,3 +344,36 @@ lmb_abs_to_phys(unsigned long aa)return pa; } + +/* +* Truncate the lmb list to memory_limit if it's set +* You must call lmb_analyze() after this. +*/ +void __init lmb_apply_memory_limit (void ) +{ +extern unsigned long memory_limit; +unsigned long i, limit; +struct lmb_region *mem = &(lmb.memory); + +if (! memory_limit) +return ; + + limit = memory_limit; +for (i =0 ; i < mem->cnt; i++) { +if (limit > mem->region[i].size) { + limit -= mem->region[i].size; +continue ; + } + +#ifdef DEBUG +udbg_printf ("lmb_truncate(): truncating at region %x\n" , i); +udbg_printf ("lmb_truncate(): total = %x\n" , total); +udbg_printf ("lmb_truncate(): size = %x\n" , mem->region[i].size); +udbg_printf ("lmb_truncate(): crop = %x\n" , crop); +#endif + + mem->region[i].size = limit; + mem->cnt = i +1 ; +break ; + } +}
include/asm-ppc64/lmb.h +1 -0
@@ -51,6 +51,7 @@ extern unsigned long __init lmb_alloc_baextern unsigned long __init lmb_phys_mem_size (void );extern unsigned long __init lmb_end_of_DRAM (void );extern unsigned long __init lmb_abs_to_phys (unsigned long ); +extern void __init lmb_apply_memory_limit (void );extern void lmb_dump_all (void );
arch/ppc64/kernel/iSeries_setup.c +26 -12
@@ -284,7 +284,7 @@ unsigned long iSeries_process_mainstore_return mem_blocks; } -static void __init iSeries_parse_cmdline (void ) +static void __init iSeries_get_cmdline (void ) {char *p, *q;
@@ -304,6 +304,8 @@ static void __init iSeries_parse_cmdline /*static*/ void __init iSeries_init_early(void) { +extern unsigned long memory_limit; +DBG (" -> iSeries_init_early()\n" );ppcdbg_initialize ();
@@ -351,6 +353,29 @@ static void __init iSeries_parse_cmdline*/ build_iSeries_Memory_Map (); +iSeries_get_cmdline (); + +/* Save unparsed command line copy for /proc/cmdline */ +strlcpy (saved_command_line, cmd_line,COMMAND_LINE_SIZE ); + +/* Parse early parameters, in particular mem=x */ +parse_early_param (); + +if (memory_limit) { +if (memory_limit > systemcfg->physicalMemorySize) +printk ("Ignoring 'mem' option, value %lu is too large.\n" , memory_limit); +else + systemcfg->physicalMemorySize = memory_limit; + } + +/* Bolt kernel mappings for all of memory (or just a bit if we've got a limit) */ +iSeries_bolt_kernel (0 , systemcfg->physicalMemorySize); + +lmb_init (); +lmb_add (0 , systemcfg->physicalMemorySize); +lmb_analyze ();/* ?? */ +lmb_reserve (0 ,__pa (klimit)); +/* Initialize machine-dependency vectors */ #ifdef CONFIG_SMP smp_init_iSeries ();
@@ -376,9 +401,6 @@ static void __init iSeries_parse_cmdline initrd_start = initrd_end =0 ;#endif /* CONFIG_BLK_DEV_INITRD */ - -iSeries_parse_cmdline (); -DBG (" <- iSeries_init_early()\n" ); }
@@ -539,14 +561,6 @@ static void __init build_iSeries_Memory_* nextPhysChunk */ systemcfg->physicalMemorySize =chunk_to_addr (nextPhysChunk); - -/* Bolt kernel mappings for all of memory */ -iSeries_bolt_kernel (0 , systemcfg->physicalMemorySize); - -lmb_init (); -lmb_add (0 , systemcfg->physicalMemorySize); -lmb_analyze ();/* ?? */ -lmb_reserve (0 ,__pa (klimit)); }/*
arch/ppc64/kernel/prom.c +15 -0
@@ -878,6 +878,8 @@ static int __init early_init_dt_scan_cho const char *full_path, void *data) { u32 *prop; +u64 *prop64; +extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end;if (strcmp (full_path,"/chosen" ) !=0 )return 0 ;
@@ -894,6 +896,18 @@ static int __init early_init_dt_scan_choif (get_flat_dt_prop (node,"linux,iommu-force-on" ,NULL ) !=NULL ) iommu_force_on =1 ; + prop64 = (u64 *)get_flat_dt_prop (node,"linux,memory-limit" ,NULL ); +if (prop64) + memory_limit = *prop64; + + prop64 = (u64 *)get_flat_dt_prop (node,"linux,tce-alloc-start" ,NULL ); +if (prop64) + tce_alloc_start = *prop64; + + prop64 = (u64 *)get_flat_dt_prop (node,"linux,tce-alloc-end" ,NULL ); +if (prop64) + tce_alloc_end = *prop64; +#ifdef CONFIG_PPC_PSERIES /* To help early debugging via the front panel, we retreive a minimal * set of RTAS infos now if available
@@ -1033,6 +1047,7 @@ void __init early_init_devtree(void *parlmb_init ();scan_flat_dt (early_init_dt_scan_root,NULL );scan_flat_dt (early_init_dt_scan_memory,NULL ); +lmb_apply_memory_limit ();lmb_analyze (); systemcfg->physicalMemorySize =lmb_phys_mem_size ();lmb_reserve (0 ,__pa (klimit));
arch/ppc64/mm/hash_utils.c +21 -2
@@ -149,6 +149,8 @@ void __init htab_initialize(void)unsigned long pteg_count;unsigned long mode_rw;int i, use_largepages =0 ; +unsigned long base =0 , size =0 ; +extern unsigned long tce_alloc_start, tce_alloc_end;DBG (" -> htab_initialize()\n" );
@@ -204,8 +206,6 @@ void __init htab_initialize(void)/* create bolted the linear mapping in the hash table */ for (i=0 ; i < lmb.memory.cnt; i++) { -unsigned long base, size; - base = lmb.memory.region[i].physbase +KERNELBASE ; size = lmb.memory.region[i].size;
@@ -234,6 +234,25 @@ void __init htab_initialize(void)#endif /* CONFIG_U3_DART */ create_pte_mapping (base, base + size, mode_rw, use_largepages); } + +/* +* If we have a memory_limit and we've allocated TCEs then we need to +* explicitly map the TCE area at the top of RAM. We also cope with the +* case that the TCEs start below memory_limit. +* tce_alloc_start/end are 16MB aligned so the mapping should work +* for either 4K or 16MB pages. +*/ +if (tce_alloc_start) { + tce_alloc_start +=KERNELBASE ; + tce_alloc_end +=KERNELBASE ; + +if (base + size >= tce_alloc_start) + tce_alloc_start = base + size +1 ; + +create_pte_mapping (tce_alloc_start, tce_alloc_end, + mode_rw, use_largepages); + } +DBG (" <- htab_initialize()\n" ); }#undef KB
arch/ppc64/mm/numa.c +50 -10
84 lines not on this page · raw message
arch/ppc64/kernel/prom_init.c +128 -9
188 lines not on this page · raw message
Quoted 5 lines · Michael Ellerman
Can you test this on your 720 or whatever it was? And if anyone else has an interesting NUMA machine they can test it on I'd love to hear about it!
I've tested this with various config options on my 720. Appears to work well on all that I tested.
Signature · 1 line
Mike
Quoted 5 lines · Michael Ellerman
Hi Mike,
Here's an updated version of my mem=X patch with new NUMA code. Sorry it took so long I've been a bit crook.
Quoted 8 lines
Can you test this on your 720 or whatever it was? And if anyone else has an interesting NUMA machine they can test it on I'd love to hear about it!
This also includes a fix for the bug Maneesh found last week with GCC 3.3 generating a switch table in
prom_init.c, which doesn't work.
I tried the patch and it works fine in my setup also.
Thanks
Maneesh
Signature · 6 lines
Maneesh Soni Linux Technology Center, IBM India Software Labs, Bangalore, India email: [email protected] Phone: 91-80-25044990