16b74ab97SMel Gorman /* 26b74ab97SMel Gorman * mm_init.c - Memory initialisation verification and debugging 36b74ab97SMel Gorman * 46b74ab97SMel Gorman * Copyright 2008 IBM Corporation, 2008 56b74ab97SMel Gorman * Author Mel Gorman <mel@csn.ul.ie> 66b74ab97SMel Gorman * 76b74ab97SMel Gorman */ 86b74ab97SMel Gorman #include <linux/kernel.h> 96b74ab97SMel Gorman #include <linux/init.h> 10ff7ea79cSNishanth Aravamudan #include <linux/kobject.h> 11b95f1b31SPaul Gortmaker #include <linux/export.h> 12917d9290STim Chen #include <linux/memory.h> 13917d9290STim Chen #include <linux/notifier.h> 147e18adb4SMel Gorman #include <linux/sched.h> 15708614e6SMel Gorman #include "internal.h" 166b74ab97SMel Gorman 175e9426abSNishanth Aravamudan #ifdef CONFIG_DEBUG_MEMORY_INIT 18194e8151SRasmus Villemoes int __meminitdata mminit_loglevel; 196b74ab97SMel Gorman 205c9ffc9cSAndrew Morton #ifndef SECTIONS_SHIFT 215c9ffc9cSAndrew Morton #define SECTIONS_SHIFT 0 225c9ffc9cSAndrew Morton #endif 235c9ffc9cSAndrew Morton 2468ad8df4SMel Gorman /* The zonelists are simply reported, validation is manual. */ 250e2342c7SRasmus Villemoes void __init mminit_verify_zonelist(void) 2668ad8df4SMel Gorman { 2768ad8df4SMel Gorman int nid; 2868ad8df4SMel Gorman 2968ad8df4SMel Gorman if (mminit_loglevel < MMINIT_VERIFY) 3068ad8df4SMel Gorman return; 3168ad8df4SMel Gorman 3268ad8df4SMel Gorman for_each_online_node(nid) { 3368ad8df4SMel Gorman pg_data_t *pgdat = NODE_DATA(nid); 3468ad8df4SMel Gorman struct zone *zone; 3568ad8df4SMel Gorman struct zoneref *z; 3668ad8df4SMel Gorman struct zonelist *zonelist; 3768ad8df4SMel Gorman int i, listid, zoneid; 3868ad8df4SMel Gorman 3968ad8df4SMel Gorman BUG_ON(MAX_ZONELISTS > 2); 4068ad8df4SMel Gorman for (i = 0; i < MAX_ZONELISTS * MAX_NR_ZONES; i++) { 4168ad8df4SMel Gorman 4268ad8df4SMel Gorman /* Identify the zone and nodelist */ 4368ad8df4SMel Gorman zoneid = i % MAX_NR_ZONES; 4468ad8df4SMel Gorman listid = i / MAX_NR_ZONES; 4568ad8df4SMel Gorman zonelist = &pgdat->node_zonelists[listid]; 4668ad8df4SMel Gorman zone = &pgdat->node_zones[zoneid]; 4768ad8df4SMel Gorman if (!populated_zone(zone)) 4868ad8df4SMel Gorman continue; 4968ad8df4SMel Gorman 5068ad8df4SMel Gorman /* Print information about the zonelist */ 5168ad8df4SMel Gorman printk(KERN_DEBUG "mminit::zonelist %s %d:%s = ", 5268ad8df4SMel Gorman listid > 0 ? "thisnode" : "general", nid, 5368ad8df4SMel Gorman zone->name); 5468ad8df4SMel Gorman 5568ad8df4SMel Gorman /* Iterate the zonelist */ 5668ad8df4SMel Gorman for_each_zone_zonelist(zone, z, zonelist, zoneid) { 5768ad8df4SMel Gorman #ifdef CONFIG_NUMA 58*1170532bSJoe Perches pr_cont("%d:%s ", zone->node, zone->name); 5968ad8df4SMel Gorman #else 60*1170532bSJoe Perches pr_cont("0:%s ", zone->name); 6168ad8df4SMel Gorman #endif /* CONFIG_NUMA */ 6268ad8df4SMel Gorman } 63*1170532bSJoe Perches pr_cont("\n"); 6468ad8df4SMel Gorman } 6568ad8df4SMel Gorman } 6668ad8df4SMel Gorman } 6768ad8df4SMel Gorman 68708614e6SMel Gorman void __init mminit_verify_pageflags_layout(void) 69708614e6SMel Gorman { 70708614e6SMel Gorman int shift, width; 71708614e6SMel Gorman unsigned long or_mask, add_mask; 72708614e6SMel Gorman 73708614e6SMel Gorman shift = 8 * sizeof(unsigned long); 7490572890SPeter Zijlstra width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH - LAST_CPUPID_SHIFT; 75708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_widths", 7690572890SPeter Zijlstra "Section %d Node %d Zone %d Lastcpupid %d Flags %d\n", 77708614e6SMel Gorman SECTIONS_WIDTH, 78708614e6SMel Gorman NODES_WIDTH, 79708614e6SMel Gorman ZONES_WIDTH, 8090572890SPeter Zijlstra LAST_CPUPID_WIDTH, 81708614e6SMel Gorman NR_PAGEFLAGS); 82708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts", 8390572890SPeter Zijlstra "Section %d Node %d Zone %d Lastcpupid %d\n", 84708614e6SMel Gorman SECTIONS_SHIFT, 85708614e6SMel Gorman NODES_SHIFT, 86a4e1b4c6SMel Gorman ZONES_SHIFT, 8790572890SPeter Zijlstra LAST_CPUPID_SHIFT); 88a4e1b4c6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_pgshifts", 8990572890SPeter Zijlstra "Section %lu Node %lu Zone %lu Lastcpupid %lu\n", 90708614e6SMel Gorman (unsigned long)SECTIONS_PGSHIFT, 91708614e6SMel Gorman (unsigned long)NODES_PGSHIFT, 92a4e1b4c6SMel Gorman (unsigned long)ZONES_PGSHIFT, 9390572890SPeter Zijlstra (unsigned long)LAST_CPUPID_PGSHIFT); 94a4e1b4c6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_nodezoneid", 95a4e1b4c6SMel Gorman "Node/Zone ID: %lu -> %lu\n", 96a4e1b4c6SMel Gorman (unsigned long)(ZONEID_PGOFF + ZONEID_SHIFT), 97a4e1b4c6SMel Gorman (unsigned long)ZONEID_PGOFF); 98708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_usage", 99a4e1b4c6SMel Gorman "location: %d -> %d layout %d -> %d unused %d -> %d page-flags\n", 100708614e6SMel Gorman shift, width, width, NR_PAGEFLAGS, NR_PAGEFLAGS, 0); 101708614e6SMel Gorman #ifdef NODE_NOT_IN_PAGE_FLAGS 102708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_nodeflags", 103708614e6SMel Gorman "Node not in page flags"); 104708614e6SMel Gorman #endif 10590572890SPeter Zijlstra #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS 106a4e1b4c6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_nodeflags", 10790572890SPeter Zijlstra "Last cpupid not in page flags"); 108a4e1b4c6SMel Gorman #endif 109708614e6SMel Gorman 110708614e6SMel Gorman if (SECTIONS_WIDTH) { 111708614e6SMel Gorman shift -= SECTIONS_WIDTH; 112708614e6SMel Gorman BUG_ON(shift != SECTIONS_PGSHIFT); 113708614e6SMel Gorman } 114708614e6SMel Gorman if (NODES_WIDTH) { 115708614e6SMel Gorman shift -= NODES_WIDTH; 116708614e6SMel Gorman BUG_ON(shift != NODES_PGSHIFT); 117708614e6SMel Gorman } 118708614e6SMel Gorman if (ZONES_WIDTH) { 119708614e6SMel Gorman shift -= ZONES_WIDTH; 120708614e6SMel Gorman BUG_ON(shift != ZONES_PGSHIFT); 121708614e6SMel Gorman } 122708614e6SMel Gorman 123708614e6SMel Gorman /* Check for bitmask overlaps */ 124708614e6SMel Gorman or_mask = (ZONES_MASK << ZONES_PGSHIFT) | 125708614e6SMel Gorman (NODES_MASK << NODES_PGSHIFT) | 126708614e6SMel Gorman (SECTIONS_MASK << SECTIONS_PGSHIFT); 127708614e6SMel Gorman add_mask = (ZONES_MASK << ZONES_PGSHIFT) + 128708614e6SMel Gorman (NODES_MASK << NODES_PGSHIFT) + 129708614e6SMel Gorman (SECTIONS_MASK << SECTIONS_PGSHIFT); 130708614e6SMel Gorman BUG_ON(or_mask != add_mask); 131708614e6SMel Gorman } 132708614e6SMel Gorman 1336b74ab97SMel Gorman static __init int set_mminit_loglevel(char *str) 1346b74ab97SMel Gorman { 1356b74ab97SMel Gorman get_option(&str, &mminit_loglevel); 1366b74ab97SMel Gorman return 0; 1376b74ab97SMel Gorman } 1386b74ab97SMel Gorman early_param("mminit_loglevel", set_mminit_loglevel); 1395e9426abSNishanth Aravamudan #endif /* CONFIG_DEBUG_MEMORY_INIT */ 140ff7ea79cSNishanth Aravamudan 141ff7ea79cSNishanth Aravamudan struct kobject *mm_kobj; 142ff7ea79cSNishanth Aravamudan EXPORT_SYMBOL_GPL(mm_kobj); 143ff7ea79cSNishanth Aravamudan 144917d9290STim Chen #ifdef CONFIG_SMP 145917d9290STim Chen s32 vm_committed_as_batch = 32; 146917d9290STim Chen 147917d9290STim Chen static void __meminit mm_compute_batch(void) 148917d9290STim Chen { 149917d9290STim Chen u64 memsized_batch; 150917d9290STim Chen s32 nr = num_present_cpus(); 151917d9290STim Chen s32 batch = max_t(s32, nr*2, 32); 152917d9290STim Chen 153917d9290STim Chen /* batch size set to 0.4% of (total memory/#cpus), or max int32 */ 154917d9290STim Chen memsized_batch = min_t(u64, (totalram_pages/nr)/256, 0x7fffffff); 155917d9290STim Chen 156917d9290STim Chen vm_committed_as_batch = max_t(s32, memsized_batch, batch); 157917d9290STim Chen } 158917d9290STim Chen 159917d9290STim Chen static int __meminit mm_compute_batch_notifier(struct notifier_block *self, 160917d9290STim Chen unsigned long action, void *arg) 161917d9290STim Chen { 162917d9290STim Chen switch (action) { 163917d9290STim Chen case MEM_ONLINE: 164917d9290STim Chen case MEM_OFFLINE: 165917d9290STim Chen mm_compute_batch(); 166917d9290STim Chen default: 167917d9290STim Chen break; 168917d9290STim Chen } 169917d9290STim Chen return NOTIFY_OK; 170917d9290STim Chen } 171917d9290STim Chen 172917d9290STim Chen static struct notifier_block compute_batch_nb __meminitdata = { 173917d9290STim Chen .notifier_call = mm_compute_batch_notifier, 174917d9290STim Chen .priority = IPC_CALLBACK_PRI, /* use lowest priority */ 175917d9290STim Chen }; 176917d9290STim Chen 177917d9290STim Chen static int __init mm_compute_batch_init(void) 178917d9290STim Chen { 179917d9290STim Chen mm_compute_batch(); 180917d9290STim Chen register_hotmemory_notifier(&compute_batch_nb); 181917d9290STim Chen 182917d9290STim Chen return 0; 183917d9290STim Chen } 184917d9290STim Chen 185917d9290STim Chen __initcall(mm_compute_batch_init); 186917d9290STim Chen 187917d9290STim Chen #endif 188917d9290STim Chen 189ff7ea79cSNishanth Aravamudan static int __init mm_sysfs_init(void) 190ff7ea79cSNishanth Aravamudan { 191ff7ea79cSNishanth Aravamudan mm_kobj = kobject_create_and_add("mm", kernel_kobj); 192ff7ea79cSNishanth Aravamudan if (!mm_kobj) 193ff7ea79cSNishanth Aravamudan return -ENOMEM; 194ff7ea79cSNishanth Aravamudan 195ff7ea79cSNishanth Aravamudan return 0; 196ff7ea79cSNishanth Aravamudan } 197e82cb95dSHugh Dickins postcore_initcall(mm_sysfs_init); 198