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> 10708614e6SMel Gorman #include "internal.h" 116b74ab97SMel Gorman 12*5e9426abSNishanth Aravamudan #ifdef CONFIG_DEBUG_MEMORY_INIT 136b74ab97SMel Gorman int __meminitdata mminit_loglevel; 146b74ab97SMel Gorman 1568ad8df4SMel Gorman /* The zonelists are simply reported, validation is manual. */ 1668ad8df4SMel Gorman void mminit_verify_zonelist(void) 1768ad8df4SMel Gorman { 1868ad8df4SMel Gorman int nid; 1968ad8df4SMel Gorman 2068ad8df4SMel Gorman if (mminit_loglevel < MMINIT_VERIFY) 2168ad8df4SMel Gorman return; 2268ad8df4SMel Gorman 2368ad8df4SMel Gorman for_each_online_node(nid) { 2468ad8df4SMel Gorman pg_data_t *pgdat = NODE_DATA(nid); 2568ad8df4SMel Gorman struct zone *zone; 2668ad8df4SMel Gorman struct zoneref *z; 2768ad8df4SMel Gorman struct zonelist *zonelist; 2868ad8df4SMel Gorman int i, listid, zoneid; 2968ad8df4SMel Gorman 3068ad8df4SMel Gorman BUG_ON(MAX_ZONELISTS > 2); 3168ad8df4SMel Gorman for (i = 0; i < MAX_ZONELISTS * MAX_NR_ZONES; i++) { 3268ad8df4SMel Gorman 3368ad8df4SMel Gorman /* Identify the zone and nodelist */ 3468ad8df4SMel Gorman zoneid = i % MAX_NR_ZONES; 3568ad8df4SMel Gorman listid = i / MAX_NR_ZONES; 3668ad8df4SMel Gorman zonelist = &pgdat->node_zonelists[listid]; 3768ad8df4SMel Gorman zone = &pgdat->node_zones[zoneid]; 3868ad8df4SMel Gorman if (!populated_zone(zone)) 3968ad8df4SMel Gorman continue; 4068ad8df4SMel Gorman 4168ad8df4SMel Gorman /* Print information about the zonelist */ 4268ad8df4SMel Gorman printk(KERN_DEBUG "mminit::zonelist %s %d:%s = ", 4368ad8df4SMel Gorman listid > 0 ? "thisnode" : "general", nid, 4468ad8df4SMel Gorman zone->name); 4568ad8df4SMel Gorman 4668ad8df4SMel Gorman /* Iterate the zonelist */ 4768ad8df4SMel Gorman for_each_zone_zonelist(zone, z, zonelist, zoneid) { 4868ad8df4SMel Gorman #ifdef CONFIG_NUMA 4968ad8df4SMel Gorman printk(KERN_CONT "%d:%s ", 5068ad8df4SMel Gorman zone->node, zone->name); 5168ad8df4SMel Gorman #else 5268ad8df4SMel Gorman printk(KERN_CONT "0:%s ", zone->name); 5368ad8df4SMel Gorman #endif /* CONFIG_NUMA */ 5468ad8df4SMel Gorman } 5568ad8df4SMel Gorman printk(KERN_CONT "\n"); 5668ad8df4SMel Gorman } 5768ad8df4SMel Gorman } 5868ad8df4SMel Gorman } 5968ad8df4SMel Gorman 60708614e6SMel Gorman void __init mminit_verify_pageflags_layout(void) 61708614e6SMel Gorman { 62708614e6SMel Gorman int shift, width; 63708614e6SMel Gorman unsigned long or_mask, add_mask; 64708614e6SMel Gorman 65708614e6SMel Gorman shift = 8 * sizeof(unsigned long); 66708614e6SMel Gorman width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH; 67708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_widths", 68708614e6SMel Gorman "Section %d Node %d Zone %d Flags %d\n", 69708614e6SMel Gorman SECTIONS_WIDTH, 70708614e6SMel Gorman NODES_WIDTH, 71708614e6SMel Gorman ZONES_WIDTH, 72708614e6SMel Gorman NR_PAGEFLAGS); 73708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts", 74708614e6SMel Gorman "Section %d Node %d Zone %d\n", 75708614e6SMel Gorman #ifdef SECTIONS_SHIFT 76708614e6SMel Gorman SECTIONS_SHIFT, 77708614e6SMel Gorman #else 78708614e6SMel Gorman 0, 79708614e6SMel Gorman #endif 80708614e6SMel Gorman NODES_SHIFT, 81708614e6SMel Gorman ZONES_SHIFT); 82708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_offsets", 83708614e6SMel Gorman "Section %lu Node %lu Zone %lu\n", 84708614e6SMel Gorman (unsigned long)SECTIONS_PGSHIFT, 85708614e6SMel Gorman (unsigned long)NODES_PGSHIFT, 86708614e6SMel Gorman (unsigned long)ZONES_PGSHIFT); 87708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_zoneid", 88708614e6SMel Gorman "Zone ID: %lu -> %lu\n", 89708614e6SMel Gorman (unsigned long)ZONEID_PGOFF, 90708614e6SMel Gorman (unsigned long)(ZONEID_PGOFF + ZONEID_SHIFT)); 91708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_usage", 92708614e6SMel Gorman "location: %d -> %d unused %d -> %d flags %d -> %d\n", 93708614e6SMel Gorman shift, width, width, NR_PAGEFLAGS, NR_PAGEFLAGS, 0); 94708614e6SMel Gorman #ifdef NODE_NOT_IN_PAGE_FLAGS 95708614e6SMel Gorman mminit_dprintk(MMINIT_TRACE, "pageflags_layout_nodeflags", 96708614e6SMel Gorman "Node not in page flags"); 97708614e6SMel Gorman #endif 98708614e6SMel Gorman 99708614e6SMel Gorman if (SECTIONS_WIDTH) { 100708614e6SMel Gorman shift -= SECTIONS_WIDTH; 101708614e6SMel Gorman BUG_ON(shift != SECTIONS_PGSHIFT); 102708614e6SMel Gorman } 103708614e6SMel Gorman if (NODES_WIDTH) { 104708614e6SMel Gorman shift -= NODES_WIDTH; 105708614e6SMel Gorman BUG_ON(shift != NODES_PGSHIFT); 106708614e6SMel Gorman } 107708614e6SMel Gorman if (ZONES_WIDTH) { 108708614e6SMel Gorman shift -= ZONES_WIDTH; 109708614e6SMel Gorman BUG_ON(shift != ZONES_PGSHIFT); 110708614e6SMel Gorman } 111708614e6SMel Gorman 112708614e6SMel Gorman /* Check for bitmask overlaps */ 113708614e6SMel Gorman or_mask = (ZONES_MASK << ZONES_PGSHIFT) | 114708614e6SMel Gorman (NODES_MASK << NODES_PGSHIFT) | 115708614e6SMel Gorman (SECTIONS_MASK << SECTIONS_PGSHIFT); 116708614e6SMel Gorman add_mask = (ZONES_MASK << ZONES_PGSHIFT) + 117708614e6SMel Gorman (NODES_MASK << NODES_PGSHIFT) + 118708614e6SMel Gorman (SECTIONS_MASK << SECTIONS_PGSHIFT); 119708614e6SMel Gorman BUG_ON(or_mask != add_mask); 120708614e6SMel Gorman } 121708614e6SMel Gorman 122708614e6SMel Gorman void __meminit mminit_verify_page_links(struct page *page, enum zone_type zone, 123708614e6SMel Gorman unsigned long nid, unsigned long pfn) 124708614e6SMel Gorman { 125708614e6SMel Gorman BUG_ON(page_to_nid(page) != nid); 126708614e6SMel Gorman BUG_ON(page_zonenum(page) != zone); 127708614e6SMel Gorman BUG_ON(page_to_pfn(page) != pfn); 128708614e6SMel Gorman } 129708614e6SMel Gorman 1306b74ab97SMel Gorman static __init int set_mminit_loglevel(char *str) 1316b74ab97SMel Gorman { 1326b74ab97SMel Gorman get_option(&str, &mminit_loglevel); 1336b74ab97SMel Gorman return 0; 1346b74ab97SMel Gorman } 1356b74ab97SMel Gorman early_param("mminit_loglevel", set_mminit_loglevel); 136*5e9426abSNishanth Aravamudan #endif /* CONFIG_DEBUG_MEMORY_INIT */ 137