diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/setup_percpu.c | 44 |
1 files changed, 28 insertions, 16 deletions
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index ef3a2cd3fe64..38e2b2a470a5 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c | |||
@@ -241,24 +241,31 @@ static ssize_t __init setup_pcpu_remap(size_t static_size) | |||
241 | * Embedding allocator | 241 | * Embedding allocator |
242 | * | 242 | * |
243 | * The first chunk is sized to just contain the static area plus | 243 | * The first chunk is sized to just contain the static area plus |
244 | * PERCPU_DYNAMIC_RESERVE and allocated as a contiguous area using | 244 | * module and dynamic reserves, and allocated as a contiguous area |
245 | * bootmem allocator and used as-is without being mapped into vmalloc | 245 | * using bootmem allocator and used as-is without being mapped into |
246 | * area. This enables the first chunk to piggy back on the linear | 246 | * vmalloc area. This enables the first chunk to piggy back on the |
247 | * physical PMD mapping and doesn't add any additional pressure to | 247 | * linear physical PMD mapping and doesn't add any additional pressure |
248 | * TLB. | 248 | * to TLB. Note that if the needed size is smaller than the minimum |
249 | * unit size, the leftover is returned to the bootmem allocator. | ||
249 | */ | 250 | */ |
250 | static void *pcpue_ptr __initdata; | 251 | static void *pcpue_ptr __initdata; |
252 | static size_t pcpue_size __initdata; | ||
251 | static size_t pcpue_unit_size __initdata; | 253 | static size_t pcpue_unit_size __initdata; |
252 | 254 | ||
253 | static struct page * __init pcpue_get_page(unsigned int cpu, int pageno) | 255 | static struct page * __init pcpue_get_page(unsigned int cpu, int pageno) |
254 | { | 256 | { |
255 | return virt_to_page(pcpue_ptr + cpu * pcpue_unit_size | 257 | size_t off = (size_t)pageno << PAGE_SHIFT; |
256 | + ((size_t)pageno << PAGE_SHIFT)); | 258 | |
259 | if (off >= pcpue_size) | ||
260 | return NULL; | ||
261 | |||
262 | return virt_to_page(pcpue_ptr + cpu * pcpue_unit_size + off); | ||
257 | } | 263 | } |
258 | 264 | ||
259 | static ssize_t __init setup_pcpu_embed(size_t static_size) | 265 | static ssize_t __init setup_pcpu_embed(size_t static_size) |
260 | { | 266 | { |
261 | unsigned int cpu; | 267 | unsigned int cpu; |
268 | size_t dyn_size; | ||
262 | 269 | ||
263 | /* | 270 | /* |
264 | * If large page isn't supported, there's no benefit in doing | 271 | * If large page isn't supported, there's no benefit in doing |
@@ -269,25 +276,30 @@ static ssize_t __init setup_pcpu_embed(size_t static_size) | |||
269 | return -EINVAL; | 276 | return -EINVAL; |
270 | 277 | ||
271 | /* allocate and copy */ | 278 | /* allocate and copy */ |
272 | pcpue_unit_size = PFN_ALIGN(static_size + PERCPU_DYNAMIC_RESERVE); | 279 | pcpue_size = PFN_ALIGN(static_size + PERCPU_DYNAMIC_RESERVE); |
273 | pcpue_unit_size = max_t(size_t, pcpue_unit_size, PCPU_MIN_UNIT_SIZE); | 280 | pcpue_unit_size = max_t(size_t, pcpue_size, PCPU_MIN_UNIT_SIZE); |
281 | dyn_size = pcpue_size - static_size; | ||
282 | |||
274 | pcpue_ptr = pcpu_alloc_bootmem(0, num_possible_cpus() * pcpue_unit_size, | 283 | pcpue_ptr = pcpu_alloc_bootmem(0, num_possible_cpus() * pcpue_unit_size, |
275 | PAGE_SIZE); | 284 | PAGE_SIZE); |
276 | if (!pcpue_ptr) | 285 | if (!pcpue_ptr) |
277 | return -ENOMEM; | 286 | return -ENOMEM; |
278 | 287 | ||
279 | for_each_possible_cpu(cpu) | 288 | for_each_possible_cpu(cpu) { |
280 | memcpy(pcpue_ptr + cpu * pcpue_unit_size, __per_cpu_load, | 289 | void *ptr = pcpue_ptr + cpu * pcpue_unit_size; |
281 | static_size); | 290 | |
291 | free_bootmem(__pa(ptr + pcpue_size), | ||
292 | pcpue_unit_size - pcpue_size); | ||
293 | memcpy(ptr, __per_cpu_load, static_size); | ||
294 | } | ||
282 | 295 | ||
283 | /* we're ready, commit */ | 296 | /* we're ready, commit */ |
284 | pr_info("PERCPU: Embedded %zu pages at %p, static data %zu bytes\n", | 297 | pr_info("PERCPU: Embedded %zu pages at %p, static data %zu bytes\n", |
285 | pcpue_unit_size >> PAGE_SHIFT, pcpue_ptr, static_size); | 298 | pcpue_size >> PAGE_SHIFT, pcpue_ptr, static_size); |
286 | 299 | ||
287 | return pcpu_setup_first_chunk(pcpue_get_page, static_size, | 300 | return pcpu_setup_first_chunk(pcpue_get_page, static_size, |
288 | pcpue_unit_size, | 301 | pcpue_unit_size, dyn_size, |
289 | pcpue_unit_size - static_size, pcpue_ptr, | 302 | pcpue_ptr, NULL); |
290 | NULL); | ||
291 | } | 303 | } |
292 | 304 | ||
293 | /* | 305 | /* |