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> 11*b95f1b31SPaul Gortmaker #include <linux/export.h> 12708614e6SMel Gorman #include "internal.h" 136b74ab97SMel Gorman 145e9426abSNishanth Aravamudan #ifdef CONFIG_DEBUG_MEMORY_INIT 15759f9a2dSMarcin Slusarz int mminit_loglevel; 166b74ab97SMel Gorman 175c9ffc9cSAndrew Morton #ifndef SECTIONS_SHIFT 185c9ffc9cSAndrew Morton #define SECTIONS_SHIFT 0 195c9ffc9cSAndrew Morton #endif 205c9ffc9cSAndrew Morton 2168ad8df4SMel Gorman /* The zonelists are simply reported, validation is manual. */ 2268ad8df4SMel Gorman void mminit_verify_zonelist(void) 2368ad8df4SMel Gorman { 2468ad8df4SMel Gorman int nid; 2568ad8df4SMel Gorman 2668ad8df4SMel Gorman if (mminit_loglevel < MMINIT_VERIFY) 2768ad8df4SMel Gorman return; 2868ad8df4SMel Gorman 2968ad8df4SMel Gorman for_each_online_node(nid) { 3068ad8df4SMel Gorman pg_data_t *pgdat = NODE_DATA(nid); 3168ad8df4SMel Gorman struct zone *zone; 3268ad8df4SMel Gorman struct zoneref *z; 3368ad8df4SMel Gorman struct zonelist *zonelist; 3468ad8df4SMel Gorman int i, listid, zoneid; 3568ad8df4SMel Gorman 3668ad8df4SMel Gorman BUG_ON(MAX_ZONELISTS > 2); 3768ad8df4SMel Gorman for (i = 0; i < MAX_ZONELISTS * MAX_NR_ZONES; i++) { 3868ad8df4SMel Gorman 3968ad8df4SMel Gorman /* Identify the zone and nodelist */ 4068ad8df4SMel Gorman zoneid = i % MAX_NR_ZONES; 4168ad8df4SMel Gorman listid = i / MAX_NR_ZONES; 4268ad8df4SMel Gorman zonelist = &pgdat->node_zonelists[listid]; 4368ad8df4SMel Gorman zone = &pgdat->node_zones[zoneid]; 4468ad8df4SMel Gorman if (!populated_zone(zone)) 4568ad8df4SMel Gorman continue; 4668ad8df4SMel Gorman 4768ad8df4SMel Gorman /* Print information about the zonelist */ 4868ad8df4SMel Gorman printk(KERN_DEBUG "mminit::zonelist %s %d:%s = ", 4968ad8df4SMel Gorman listid > 0 ? "thisnode" : "general", nid, 5068ad8df4SMel Gorman zone->name); 5168ad8df4SMel Gorman 5268ad8df4SMel Gorman /* Iterate the zonelist */ 5368ad8df4SMel Gorman for_each_zone_zonelist(zone, z, zonelist, zoneid) { 5468ad8df4SMel Gorman #ifdef CONFIG_NUMA 5568ad8df4SMel Gorman printk(KERN_CONT "%d:%s ", 5668ad8df4SMel Gorman zone->node, zone->name); 5768ad8df4SMel Gorman #else 5868ad8df4SMel Gorman printk(KERN_CONT "0:%s ", zone->name); 5968ad8df4SMel Gorman #endif /* CONFIG_NUMA */ 6068ad8df4SMel Gorman } 6168ad8df4SMel Gorman printk(KERN_CONT "\n"); 6268ad8df4SMel Gorman } 6368ad8df4SMel Gorman } 6468ad8df4SMel Gorman } 6568ad8df4SMel Gorman 66708614e6SMel Gorman void __init mminit_verify_pageflags_layout(void) 67708614e6SMel Gorman { 68708614e6SMel Gorman int shift, width; 69708614e6SMel Gorman unsigned long or_mask, add_mask; 70708614e6SMel Gorman 71708614e6SMel Gorman shift = 8 * sizeof(unsigned long); 72708614e6SMel Gorman width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH; 73708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_widths", 74708614e6SMel Gorman "Section %d Node %d Zone %d Flags %d\n", 75708614e6SMel Gorman SECTIONS_WIDTH, 76708614e6SMel Gorman NODES_WIDTH, 77708614e6SMel Gorman ZONES_WIDTH, 78708614e6SMel Gorman NR_PAGEFLAGS); 79708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts", 80708614e6SMel Gorman "Section %d Node %d Zone %d\n", 81708614e6SMel Gorman SECTIONS_SHIFT, 82708614e6SMel Gorman NODES_SHIFT, 83708614e6SMel Gorman ZONES_SHIFT); 84708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_offsets", 85708614e6SMel Gorman "Section %lu Node %lu Zone %lu\n", 86708614e6SMel Gorman (unsigned long)SECTIONS_PGSHIFT, 87708614e6SMel Gorman (unsigned long)NODES_PGSHIFT, 88708614e6SMel Gorman (unsigned long)ZONES_PGSHIFT); 89708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_zoneid", 90708614e6SMel Gorman "Zone ID: %lu -> %lu\n", 91708614e6SMel Gorman (unsigned long)ZONEID_PGOFF, 92708614e6SMel Gorman (unsigned long)(ZONEID_PGOFF + ZONEID_SHIFT)); 93708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_usage", 94708614e6SMel Gorman "location: %d -> %d unused %d -> %d flags %d -> %d\n", 95708614e6SMel Gorman shift, width, width, NR_PAGEFLAGS, NR_PAGEFLAGS, 0); 96708614e6SMel Gorman #ifdef NODE_NOT_IN_PAGE_FLAGS 97708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_nodeflags", 98708614e6SMel Gorman "Node not in page flags"); 99708614e6SMel Gorman #endif 100708614e6SMel Gorman 101708614e6SMel Gorman if (SECTIONS_WIDTH) { 102708614e6SMel Gorman shift -= SECTIONS_WIDTH; 103708614e6SMel Gorman BUG_ON(shift != SECTIONS_PGSHIFT); 104708614e6SMel Gorman } 105708614e6SMel Gorman if (NODES_WIDTH) { 106708614e6SMel Gorman shift -= NODES_WIDTH; 107708614e6SMel Gorman BUG_ON(shift != NODES_PGSHIFT); 108708614e6SMel Gorman } 109708614e6SMel Gorman if (ZONES_WIDTH) { 110708614e6SMel Gorman shift -= ZONES_WIDTH; 111708614e6SMel Gorman BUG_ON(shift != ZONES_PGSHIFT); 112708614e6SMel Gorman } 113708614e6SMel Gorman 114708614e6SMel Gorman /* Check for bitmask overlaps */ 115708614e6SMel Gorman or_mask = (ZONES_MASK << ZONES_PGSHIFT) | 116708614e6SMel Gorman (NODES_MASK << NODES_PGSHIFT) | 117708614e6SMel Gorman (SECTIONS_MASK << SECTIONS_PGSHIFT); 118708614e6SMel Gorman add_mask = (ZONES_MASK << ZONES_PGSHIFT) + 119708614e6SMel Gorman (NODES_MASK << NODES_PGSHIFT) + 120708614e6SMel Gorman (SECTIONS_MASK << SECTIONS_PGSHIFT); 121708614e6SMel Gorman BUG_ON(or_mask != add_mask); 122708614e6SMel Gorman } 123708614e6SMel Gorman 124708614e6SMel Gorman void __meminit mminit_verify_page_links(struct page *page, enum zone_type zone, 125708614e6SMel Gorman unsigned long nid, unsigned long pfn) 126708614e6SMel Gorman { 127708614e6SMel Gorman BUG_ON(page_to_nid(page) != nid); 128708614e6SMel Gorman BUG_ON(page_zonenum(page) != zone); 129708614e6SMel Gorman BUG_ON(page_to_pfn(page) != pfn); 130708614e6SMel Gorman } 131708614e6SMel Gorman 1326b74ab97SMel Gorman static __init int set_mminit_loglevel(char *str) 1336b74ab97SMel Gorman { 1346b74ab97SMel Gorman get_option(&str, &mminit_loglevel); 1356b74ab97SMel Gorman return 0; 1366b74ab97SMel Gorman } 1376b74ab97SMel Gorman early_param("mminit_loglevel", set_mminit_loglevel); 1385e9426abSNishanth Aravamudan #endif /* CONFIG_DEBUG_MEMORY_INIT */ 139ff7ea79cSNishanth Aravamudan 140ff7ea79cSNishanth Aravamudan struct kobject *mm_kobj; 141ff7ea79cSNishanth Aravamudan EXPORT_SYMBOL_GPL(mm_kobj); 142ff7ea79cSNishanth Aravamudan 143ff7ea79cSNishanth Aravamudan static int __init mm_sysfs_init(void) 144ff7ea79cSNishanth Aravamudan { 145ff7ea79cSNishanth Aravamudan mm_kobj = kobject_create_and_add("mm", kernel_kobj); 146ff7ea79cSNishanth Aravamudan if (!mm_kobj) 147ff7ea79cSNishanth Aravamudan return -ENOMEM; 148ff7ea79cSNishanth Aravamudan 149ff7ea79cSNishanth Aravamudan return 0; 150ff7ea79cSNishanth Aravamudan } 151ff7ea79cSNishanth Aravamudan 152ff7ea79cSNishanth Aravamudan __initcall(mm_sysfs_init); 153