diff options
Diffstat (limited to 'arch/x86/kernel/setup_percpu.c')
-rw-r--r-- | arch/x86/kernel/setup_percpu.c | 62 |
1 files changed, 40 insertions, 22 deletions
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index d992e6cff73..2dce4355821 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c | |||
@@ -61,38 +61,56 @@ static inline void setup_percpu_segment(int cpu) | |||
61 | */ | 61 | */ |
62 | void __init setup_per_cpu_areas(void) | 62 | void __init setup_per_cpu_areas(void) |
63 | { | 63 | { |
64 | ssize_t size; | 64 | ssize_t size = __per_cpu_end - __per_cpu_start; |
65 | char *ptr; | 65 | unsigned int nr_cpu_pages = DIV_ROUND_UP(size, PAGE_SIZE); |
66 | int cpu; | 66 | static struct page **pages; |
67 | 67 | size_t pages_size; | |
68 | /* Copy section for each CPU (we discard the original) */ | 68 | unsigned int cpu, i, j; |
69 | size = roundup(PERCPU_ENOUGH_ROOM, PAGE_SIZE); | 69 | unsigned long delta; |
70 | size_t pcpu_unit_size; | ||
70 | 71 | ||
71 | pr_info("NR_CPUS:%d nr_cpumask_bits:%d nr_cpu_ids:%d nr_node_ids:%d\n", | 72 | pr_info("NR_CPUS:%d nr_cpumask_bits:%d nr_cpu_ids:%d nr_node_ids:%d\n", |
72 | NR_CPUS, nr_cpumask_bits, nr_cpu_ids, nr_node_ids); | 73 | NR_CPUS, nr_cpumask_bits, nr_cpu_ids, nr_node_ids); |
74 | pr_info("PERCPU: Allocating %zd bytes for static per cpu data\n", size); | ||
73 | 75 | ||
74 | pr_info("PERCPU: Allocating %zd bytes of per cpu data\n", size); | 76 | pages_size = nr_cpu_pages * num_possible_cpus() * sizeof(pages[0]); |
77 | pages = alloc_bootmem(pages_size); | ||
75 | 78 | ||
79 | j = 0; | ||
76 | for_each_possible_cpu(cpu) { | 80 | for_each_possible_cpu(cpu) { |
81 | void *ptr; | ||
82 | |||
83 | for (i = 0; i < nr_cpu_pages; i++) { | ||
77 | #ifndef CONFIG_NEED_MULTIPLE_NODES | 84 | #ifndef CONFIG_NEED_MULTIPLE_NODES |
78 | ptr = alloc_bootmem_pages(size); | 85 | ptr = alloc_bootmem_pages(PAGE_SIZE); |
79 | #else | 86 | #else |
80 | int node = early_cpu_to_node(cpu); | 87 | int node = early_cpu_to_node(cpu); |
81 | if (!node_online(node) || !NODE_DATA(node)) { | 88 | |
82 | ptr = alloc_bootmem_pages(size); | 89 | if (!node_online(node) || !NODE_DATA(node)) { |
83 | pr_info("cpu %d has no node %d or node-local memory\n", | 90 | ptr = alloc_bootmem_pages(PAGE_SIZE); |
84 | cpu, node); | 91 | pr_info("cpu %d has no node %d or node-local " |
85 | pr_debug("per cpu data for cpu%d at %016lx\n", | 92 | "memory\n", cpu, node); |
86 | cpu, __pa(ptr)); | 93 | pr_debug("per cpu data for cpu%d at %016lx\n", |
87 | } else { | 94 | cpu, __pa(ptr)); |
88 | ptr = alloc_bootmem_pages_node(NODE_DATA(node), size); | 95 | } else { |
89 | pr_debug("per cpu data for cpu%d on node%d at %016lx\n", | 96 | ptr = alloc_bootmem_pages_node(NODE_DATA(node), |
90 | cpu, node, __pa(ptr)); | 97 | PAGE_SIZE); |
91 | } | 98 | pr_debug("per cpu data for cpu%d on node%d " |
99 | "at %016lx\n", cpu, node, __pa(ptr)); | ||
100 | } | ||
92 | #endif | 101 | #endif |
102 | memcpy(ptr, __per_cpu_load + i * PAGE_SIZE, PAGE_SIZE); | ||
103 | pages[j++] = virt_to_page(ptr); | ||
104 | } | ||
105 | } | ||
106 | |||
107 | pcpu_unit_size = pcpu_setup_static(populate_extra_pte, pages, size); | ||
93 | 108 | ||
94 | memcpy(ptr, __per_cpu_load, __per_cpu_end - __per_cpu_start); | 109 | free_bootmem(__pa(pages), pages_size); |
95 | per_cpu_offset(cpu) = ptr - __per_cpu_start; | 110 | |
111 | delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; | ||
112 | for_each_possible_cpu(cpu) { | ||
113 | per_cpu_offset(cpu) = delta + cpu * pcpu_unit_size; | ||
96 | per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu); | 114 | per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu); |
97 | per_cpu(cpu_number, cpu) = cpu; | 115 | per_cpu(cpu_number, cpu) = cpu; |
98 | setup_percpu_segment(cpu); | 116 | setup_percpu_segment(cpu); |