1378b39a4SYinghai Lu #include <linux/kernel.h> 2378b39a4SYinghai Lu #include <linux/module.h> 3378b39a4SYinghai Lu #include <linux/init.h> 4378b39a4SYinghai Lu #include <linux/bootmem.h> 5378b39a4SYinghai Lu #include <linux/percpu.h> 6378b39a4SYinghai Lu #include <linux/kexec.h> 7378b39a4SYinghai Lu #include <linux/crash_dump.h> 88a87dd9aSJaswinder Singh Rajput #include <linux/smp.h> 98a87dd9aSJaswinder Singh Rajput #include <linux/topology.h> 10378b39a4SYinghai Lu #include <asm/sections.h> 11378b39a4SYinghai Lu #include <asm/processor.h> 12378b39a4SYinghai Lu #include <asm/setup.h> 13378b39a4SYinghai Lu #include <asm/mpspec.h> 14378b39a4SYinghai Lu #include <asm/apicdef.h> 15378b39a4SYinghai Lu #include <asm/highmem.h> 161a51e3a0STejun Heo #include <asm/proto.h> 1706879033SJaswinder Singh Rajput #include <asm/cpumask.h> 1834019be1SBrian Gerst #include <asm/cpu.h> 1960a5317fSTejun Heo #include <asm/stackprotector.h> 20378b39a4SYinghai Lu 21c90aa894SMike Travis #ifdef CONFIG_DEBUG_PER_CPU_MAPS 22c90aa894SMike Travis # define DBG(x...) printk(KERN_DEBUG x) 23c90aa894SMike Travis #else 24c90aa894SMike Travis # define DBG(x...) 25c90aa894SMike Travis #endif 26c90aa894SMike Travis 27ea927906SBrian Gerst DEFINE_PER_CPU(int, cpu_number); 28ea927906SBrian Gerst EXPORT_PER_CPU_SYMBOL(cpu_number); 29ea927906SBrian Gerst 301688401aSBrian Gerst #ifdef CONFIG_X86_64 311688401aSBrian Gerst #define BOOT_PERCPU_OFFSET ((unsigned long)__per_cpu_load) 321688401aSBrian Gerst #else 331688401aSBrian Gerst #define BOOT_PERCPU_OFFSET 0 341688401aSBrian Gerst #endif 351688401aSBrian Gerst 361688401aSBrian Gerst DEFINE_PER_CPU(unsigned long, this_cpu_off) = BOOT_PERCPU_OFFSET; 371688401aSBrian Gerst EXPORT_PER_CPU_SYMBOL(this_cpu_off); 381688401aSBrian Gerst 399939ddafSTejun Heo unsigned long __per_cpu_offset[NR_CPUS] __read_mostly = { 4034019be1SBrian Gerst [0 ... NR_CPUS-1] = BOOT_PERCPU_OFFSET, 419939ddafSTejun Heo }; 429939ddafSTejun Heo EXPORT_SYMBOL(__per_cpu_offset); 43378b39a4SYinghai Lu 44*458a3e64STejun Heo static void __init pcpu4k_populate_pte(unsigned long addr) 45*458a3e64STejun Heo { 46*458a3e64STejun Heo populate_extra_pte(addr); 47*458a3e64STejun Heo } 48*458a3e64STejun Heo 49b2d2f431SBrian Gerst static inline void setup_percpu_segment(int cpu) 50b2d2f431SBrian Gerst { 51b2d2f431SBrian Gerst #ifdef CONFIG_X86_32 52b2d2f431SBrian Gerst struct desc_struct gdt; 53b2d2f431SBrian Gerst 54b2d2f431SBrian Gerst pack_descriptor(&gdt, per_cpu_offset(cpu), 0xFFFFF, 55b2d2f431SBrian Gerst 0x2 | DESCTYPE_S, 0x8); 56b2d2f431SBrian Gerst gdt.s = 1; 57b2d2f431SBrian Gerst write_gdt_entry(get_cpu_gdt_table(cpu), 58b2d2f431SBrian Gerst GDT_ENTRY_PERCPU, &gdt, DESCTYPE_S); 59b2d2f431SBrian Gerst #endif 60b2d2f431SBrian Gerst } 61b2d2f431SBrian Gerst 62378b39a4SYinghai Lu /* 63378b39a4SYinghai Lu * Great future plan: 64378b39a4SYinghai Lu * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data. 65378b39a4SYinghai Lu * Always point %gs to its beginning 66378b39a4SYinghai Lu */ 67378b39a4SYinghai Lu void __init setup_per_cpu_areas(void) 68378b39a4SYinghai Lu { 6911124411STejun Heo ssize_t size = __per_cpu_end - __per_cpu_start; 7011124411STejun Heo unsigned int nr_cpu_pages = DIV_ROUND_UP(size, PAGE_SIZE); 7111124411STejun Heo static struct page **pages; 7211124411STejun Heo size_t pages_size; 7311124411STejun Heo unsigned int cpu, i, j; 7411124411STejun Heo unsigned long delta; 7511124411STejun Heo size_t pcpu_unit_size; 76a1681965SMike Travis 77ab14398aSCyrill Gorcunov pr_info("NR_CPUS:%d nr_cpumask_bits:%d nr_cpu_ids:%d nr_node_ids:%d\n", 78a1681965SMike Travis NR_CPUS, nr_cpumask_bits, nr_cpu_ids, nr_node_ids); 7911124411STejun Heo pr_info("PERCPU: Allocating %zd bytes for static per cpu data\n", size); 80a1681965SMike Travis 8111124411STejun Heo pages_size = nr_cpu_pages * num_possible_cpus() * sizeof(pages[0]); 8211124411STejun Heo pages = alloc_bootmem(pages_size); 83378b39a4SYinghai Lu 8411124411STejun Heo j = 0; 85378b39a4SYinghai Lu for_each_possible_cpu(cpu) { 8611124411STejun Heo void *ptr; 8711124411STejun Heo 8811124411STejun Heo for (i = 0; i < nr_cpu_pages; i++) { 89378b39a4SYinghai Lu #ifndef CONFIG_NEED_MULTIPLE_NODES 9011124411STejun Heo ptr = alloc_bootmem_pages(PAGE_SIZE); 91378b39a4SYinghai Lu #else 92378b39a4SYinghai Lu int node = early_cpu_to_node(cpu); 9311124411STejun Heo 94378b39a4SYinghai Lu if (!node_online(node) || !NODE_DATA(node)) { 9511124411STejun Heo ptr = alloc_bootmem_pages(PAGE_SIZE); 9611124411STejun Heo pr_info("cpu %d has no node %d or node-local " 9711124411STejun Heo "memory\n", cpu, node); 98ab14398aSCyrill Gorcunov pr_debug("per cpu data for cpu%d at %016lx\n", 99a677f58aSYinghai Lu cpu, __pa(ptr)); 100ab14398aSCyrill Gorcunov } else { 10111124411STejun Heo ptr = alloc_bootmem_pages_node(NODE_DATA(node), 10211124411STejun Heo PAGE_SIZE); 10311124411STejun Heo pr_debug("per cpu data for cpu%d on node%d " 10411124411STejun Heo "at %016lx\n", cpu, node, __pa(ptr)); 105a677f58aSYinghai Lu } 106378b39a4SYinghai Lu #endif 10711124411STejun Heo memcpy(ptr, __per_cpu_load + i * PAGE_SIZE, PAGE_SIZE); 10811124411STejun Heo pages[j++] = virt_to_page(ptr); 10911124411STejun Heo } 11011124411STejun Heo } 1111a51e3a0STejun Heo 112*458a3e64STejun Heo pcpu_unit_size = pcpu_setup_static(pcpu4k_populate_pte, pages, size); 11311124411STejun Heo 11411124411STejun Heo free_bootmem(__pa(pages), pages_size); 11511124411STejun Heo 11611124411STejun Heo delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; 11711124411STejun Heo for_each_possible_cpu(cpu) { 11811124411STejun Heo per_cpu_offset(cpu) = delta + cpu * pcpu_unit_size; 11926f80bd6SBrian Gerst per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu); 120ea927906SBrian Gerst per_cpu(cpu_number, cpu) = cpu; 121b2d2f431SBrian Gerst setup_percpu_segment(cpu); 12260a5317fSTejun Heo setup_stack_canary_segment(cpu); 1230d77e7f0SBrian Gerst /* 124cf3997f5STejun Heo * Copy data used in early init routines from the 125cf3997f5STejun Heo * initial arrays to the per cpu data areas. These 126cf3997f5STejun Heo * arrays then become expendable and the *_early_ptr's 127cf3997f5STejun Heo * are zeroed indicating that the static arrays are 128cf3997f5STejun Heo * gone. 1290d77e7f0SBrian Gerst */ 130ec70de8bSBrian Gerst #ifdef CONFIG_X86_LOCAL_APIC 1310d77e7f0SBrian Gerst per_cpu(x86_cpu_to_apicid, cpu) = 1320d77e7f0SBrian Gerst early_per_cpu_map(x86_cpu_to_apicid, cpu); 1330d77e7f0SBrian Gerst per_cpu(x86_bios_cpu_apicid, cpu) = 1340d77e7f0SBrian Gerst early_per_cpu_map(x86_bios_cpu_apicid, cpu); 135ec70de8bSBrian Gerst #endif 1361a51e3a0STejun Heo #ifdef CONFIG_X86_64 13726f80bd6SBrian Gerst per_cpu(irq_stack_ptr, cpu) = 138cf3997f5STejun Heo per_cpu(irq_stack_union.irq_stack, cpu) + 139cf3997f5STejun Heo IRQ_STACK_SIZE - 64; 1406470aff6SBrian Gerst #ifdef CONFIG_NUMA 1416470aff6SBrian Gerst per_cpu(x86_cpu_to_node_map, cpu) = 1426470aff6SBrian Gerst early_per_cpu_map(x86_cpu_to_node_map, cpu); 1436470aff6SBrian Gerst #endif 1442697fbd5SBrian Gerst #endif 1451a51e3a0STejun Heo /* 14634019be1SBrian Gerst * Up to this point, the boot CPU has been using .data.init 1472697fbd5SBrian Gerst * area. Reload any changed state for the boot CPU. 1481a51e3a0STejun Heo */ 14934019be1SBrian Gerst if (cpu == boot_cpu_id) 150552be871SBrian Gerst switch_to_new_gdt(cpu); 151c90aa894SMike Travis 152c90aa894SMike Travis DBG("PERCPU: cpu %4d %p\n", cpu, ptr); 153378b39a4SYinghai Lu } 154378b39a4SYinghai Lu 1550d77e7f0SBrian Gerst /* indicate the early static arrays will soon be gone */ 15622f25138SJames Bottomley #ifdef CONFIG_X86_LOCAL_APIC 1570d77e7f0SBrian Gerst early_per_cpu_ptr(x86_cpu_to_apicid) = NULL; 1580d77e7f0SBrian Gerst early_per_cpu_ptr(x86_bios_cpu_apicid) = NULL; 15922f25138SJames Bottomley #endif 1606470aff6SBrian Gerst #if defined(CONFIG_X86_64) && defined(CONFIG_NUMA) 1610d77e7f0SBrian Gerst early_per_cpu_ptr(x86_cpu_to_node_map) = NULL; 1620d77e7f0SBrian Gerst #endif 163378b39a4SYinghai Lu 164378b39a4SYinghai Lu /* Setup node to cpumask map */ 165378b39a4SYinghai Lu setup_node_to_cpumask_map(); 166c2d1cec1SMike Travis 167c2d1cec1SMike Travis /* Setup cpu initialized, callin, callout masks */ 168c2d1cec1SMike Travis setup_cpu_local_masks(); 169378b39a4SYinghai Lu } 170