1*3947be19SDave Hansen /* 2*3947be19SDave Hansen * linux/mm/memory_hotplug.c 3*3947be19SDave Hansen * 4*3947be19SDave Hansen * Copyright (C) 5*3947be19SDave Hansen */ 6*3947be19SDave Hansen 7*3947be19SDave Hansen #include <linux/config.h> 8*3947be19SDave Hansen #include <linux/stddef.h> 9*3947be19SDave Hansen #include <linux/mm.h> 10*3947be19SDave Hansen #include <linux/swap.h> 11*3947be19SDave Hansen #include <linux/interrupt.h> 12*3947be19SDave Hansen #include <linux/pagemap.h> 13*3947be19SDave Hansen #include <linux/bootmem.h> 14*3947be19SDave Hansen #include <linux/compiler.h> 15*3947be19SDave Hansen #include <linux/module.h> 16*3947be19SDave Hansen #include <linux/pagevec.h> 17*3947be19SDave Hansen #include <linux/slab.h> 18*3947be19SDave Hansen #include <linux/sysctl.h> 19*3947be19SDave Hansen #include <linux/cpu.h> 20*3947be19SDave Hansen #include <linux/memory.h> 21*3947be19SDave Hansen #include <linux/memory_hotplug.h> 22*3947be19SDave Hansen #include <linux/highmem.h> 23*3947be19SDave Hansen #include <linux/vmalloc.h> 24*3947be19SDave Hansen 25*3947be19SDave Hansen #include <asm/tlbflush.h> 26*3947be19SDave Hansen 27*3947be19SDave Hansen static struct page *__kmalloc_section_memmap(unsigned long nr_pages) 28*3947be19SDave Hansen { 29*3947be19SDave Hansen struct page *page, *ret; 30*3947be19SDave Hansen unsigned long memmap_size = sizeof(struct page) * nr_pages; 31*3947be19SDave Hansen 32*3947be19SDave Hansen page = alloc_pages(GFP_KERNEL, get_order(memmap_size)); 33*3947be19SDave Hansen if (page) 34*3947be19SDave Hansen goto got_map_page; 35*3947be19SDave Hansen 36*3947be19SDave Hansen ret = vmalloc(memmap_size); 37*3947be19SDave Hansen if (ret) 38*3947be19SDave Hansen goto got_map_ptr; 39*3947be19SDave Hansen 40*3947be19SDave Hansen return NULL; 41*3947be19SDave Hansen got_map_page: 42*3947be19SDave Hansen ret = (struct page *)pfn_to_kaddr(page_to_pfn(page)); 43*3947be19SDave Hansen got_map_ptr: 44*3947be19SDave Hansen memset(ret, 0, memmap_size); 45*3947be19SDave Hansen 46*3947be19SDave Hansen return ret; 47*3947be19SDave Hansen } 48*3947be19SDave Hansen 49*3947be19SDave Hansen extern void zonetable_add(struct zone *zone, int nid, int zid, unsigned long pfn, 50*3947be19SDave Hansen unsigned long size); 51*3947be19SDave Hansen static void __add_zone(struct zone *zone, unsigned long phys_start_pfn) 52*3947be19SDave Hansen { 53*3947be19SDave Hansen struct pglist_data *pgdat = zone->zone_pgdat; 54*3947be19SDave Hansen int nr_pages = PAGES_PER_SECTION; 55*3947be19SDave Hansen int nid = pgdat->node_id; 56*3947be19SDave Hansen int zone_type; 57*3947be19SDave Hansen 58*3947be19SDave Hansen zone_type = zone - pgdat->node_zones; 59*3947be19SDave Hansen memmap_init_zone(nr_pages, nid, zone_type, phys_start_pfn); 60*3947be19SDave Hansen zonetable_add(zone, nid, zone_type, phys_start_pfn, nr_pages); 61*3947be19SDave Hansen } 62*3947be19SDave Hansen 63*3947be19SDave Hansen extern int sparse_add_one_section(struct zone *, unsigned long, 64*3947be19SDave Hansen struct page *mem_map); 65*3947be19SDave Hansen static int __add_section(struct zone *zone, unsigned long phys_start_pfn) 66*3947be19SDave Hansen { 67*3947be19SDave Hansen struct pglist_data *pgdat = zone->zone_pgdat; 68*3947be19SDave Hansen int nr_pages = PAGES_PER_SECTION; 69*3947be19SDave Hansen struct page *memmap; 70*3947be19SDave Hansen int ret; 71*3947be19SDave Hansen 72*3947be19SDave Hansen /* 73*3947be19SDave Hansen * This can potentially allocate memory, and does its own 74*3947be19SDave Hansen * internal locking. 75*3947be19SDave Hansen */ 76*3947be19SDave Hansen sparse_index_init(pfn_to_section_nr(phys_start_pfn), pgdat->node_id); 77*3947be19SDave Hansen 78*3947be19SDave Hansen pgdat_resize_lock(pgdat, &flags); 79*3947be19SDave Hansen memmap = __kmalloc_section_memmap(nr_pages); 80*3947be19SDave Hansen ret = sparse_add_one_section(zone, phys_start_pfn, memmap); 81*3947be19SDave Hansen pgdat_resize_unlock(pgdat, &flags); 82*3947be19SDave Hansen 83*3947be19SDave Hansen if (ret <= 0) { 84*3947be19SDave Hansen /* the mem_map didn't get used */ 85*3947be19SDave Hansen if (memmap >= (struct page *)VMALLOC_START && 86*3947be19SDave Hansen memmap < (struct page *)VMALLOC_END) 87*3947be19SDave Hansen vfree(memmap); 88*3947be19SDave Hansen else 89*3947be19SDave Hansen free_pages((unsigned long)memmap, 90*3947be19SDave Hansen get_order(sizeof(struct page) * nr_pages)); 91*3947be19SDave Hansen } 92*3947be19SDave Hansen 93*3947be19SDave Hansen if (ret < 0) 94*3947be19SDave Hansen return ret; 95*3947be19SDave Hansen 96*3947be19SDave Hansen __add_zone(zone, phys_start_pfn); 97*3947be19SDave Hansen return register_new_memory(__pfn_to_section(phys_start_pfn)); 98*3947be19SDave Hansen } 99*3947be19SDave Hansen 100*3947be19SDave Hansen /* 101*3947be19SDave Hansen * Reasonably generic function for adding memory. It is 102*3947be19SDave Hansen * expected that archs that support memory hotplug will 103*3947be19SDave Hansen * call this function after deciding the zone to which to 104*3947be19SDave Hansen * add the new pages. 105*3947be19SDave Hansen */ 106*3947be19SDave Hansen int __add_pages(struct zone *zone, unsigned long phys_start_pfn, 107*3947be19SDave Hansen unsigned long nr_pages) 108*3947be19SDave Hansen { 109*3947be19SDave Hansen unsigned long i; 110*3947be19SDave Hansen int err = 0; 111*3947be19SDave Hansen 112*3947be19SDave Hansen for (i = 0; i < nr_pages; i += PAGES_PER_SECTION) { 113*3947be19SDave Hansen err = __add_section(zone, phys_start_pfn + i); 114*3947be19SDave Hansen 115*3947be19SDave Hansen if (err) 116*3947be19SDave Hansen break; 117*3947be19SDave Hansen } 118*3947be19SDave Hansen 119*3947be19SDave Hansen return err; 120*3947be19SDave Hansen } 121*3947be19SDave Hansen 122*3947be19SDave Hansen static void grow_zone_span(struct zone *zone, 123*3947be19SDave Hansen unsigned long start_pfn, unsigned long end_pfn) 124*3947be19SDave Hansen { 125*3947be19SDave Hansen unsigned long old_zone_end_pfn; 126*3947be19SDave Hansen 127*3947be19SDave Hansen zone_span_writelock(zone); 128*3947be19SDave Hansen 129*3947be19SDave Hansen old_zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages; 130*3947be19SDave Hansen if (start_pfn < zone->zone_start_pfn) 131*3947be19SDave Hansen zone->zone_start_pfn = start_pfn; 132*3947be19SDave Hansen 133*3947be19SDave Hansen if (end_pfn > old_zone_end_pfn) 134*3947be19SDave Hansen zone->spanned_pages = end_pfn - zone->zone_start_pfn; 135*3947be19SDave Hansen 136*3947be19SDave Hansen zone_span_writeunlock(zone); 137*3947be19SDave Hansen } 138*3947be19SDave Hansen 139*3947be19SDave Hansen static void grow_pgdat_span(struct pglist_data *pgdat, 140*3947be19SDave Hansen unsigned long start_pfn, unsigned long end_pfn) 141*3947be19SDave Hansen { 142*3947be19SDave Hansen unsigned long old_pgdat_end_pfn = 143*3947be19SDave Hansen pgdat->node_start_pfn + pgdat->node_spanned_pages; 144*3947be19SDave Hansen 145*3947be19SDave Hansen if (start_pfn < pgdat->node_start_pfn) 146*3947be19SDave Hansen pgdat->node_start_pfn = start_pfn; 147*3947be19SDave Hansen 148*3947be19SDave Hansen if (end_pfn > old_pgdat_end_pfn) 149*3947be19SDave Hansen pgdat->node_spanned_pages = end_pfn - pgdat->node_spanned_pages; 150*3947be19SDave Hansen } 151*3947be19SDave Hansen 152*3947be19SDave Hansen int online_pages(unsigned long pfn, unsigned long nr_pages) 153*3947be19SDave Hansen { 154*3947be19SDave Hansen unsigned long i; 155*3947be19SDave Hansen unsigned long flags; 156*3947be19SDave Hansen unsigned long onlined_pages = 0; 157*3947be19SDave Hansen struct zone *zone; 158*3947be19SDave Hansen 159*3947be19SDave Hansen /* 160*3947be19SDave Hansen * This doesn't need a lock to do pfn_to_page(). 161*3947be19SDave Hansen * The section can't be removed here because of the 162*3947be19SDave Hansen * memory_block->state_sem. 163*3947be19SDave Hansen */ 164*3947be19SDave Hansen zone = page_zone(pfn_to_page(pfn)); 165*3947be19SDave Hansen pgdat_resize_lock(zone->zone_pgdat, &flags); 166*3947be19SDave Hansen grow_zone_span(zone, pfn, pfn + nr_pages); 167*3947be19SDave Hansen grow_pgdat_span(zone->zone_pgdat, pfn, pfn + nr_pages); 168*3947be19SDave Hansen pgdat_resize_unlock(zone->zone_pgdat, &flags); 169*3947be19SDave Hansen 170*3947be19SDave Hansen for (i = 0; i < nr_pages; i++) { 171*3947be19SDave Hansen struct page *page = pfn_to_page(pfn + i); 172*3947be19SDave Hansen online_page(page); 173*3947be19SDave Hansen onlined_pages++; 174*3947be19SDave Hansen } 175*3947be19SDave Hansen zone->present_pages += onlined_pages; 176*3947be19SDave Hansen 177*3947be19SDave Hansen return 0; 178*3947be19SDave Hansen } 179