diff options
-rw-r--r-- | arch/arm/kernel/vmlinux.lds.S | 1 | ||||
-rw-r--r-- | arch/ia64/kernel/vmlinux.lds.S | 12 | ||||
-rw-r--r-- | arch/powerpc/kernel/vmlinux.lds.S | 9 | ||||
-rw-r--r-- | arch/x86/include/asm/percpu.h | 8 | ||||
-rw-r--r-- | arch/x86/kernel/setup_percpu.c | 63 | ||||
-rw-r--r-- | include/linux/percpu.h | 6 | ||||
-rw-r--r-- | mm/allocpercpu.c | 2 | ||||
-rw-r--r-- | mm/percpu.c | 130 |
8 files changed, 135 insertions, 96 deletions
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 85598f7da407..1602373e539c 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S | |||
@@ -64,6 +64,7 @@ SECTIONS | |||
64 | __initramfs_end = .; | 64 | __initramfs_end = .; |
65 | #endif | 65 | #endif |
66 | . = ALIGN(4096); | 66 | . = ALIGN(4096); |
67 | __per_cpu_load = .; | ||
67 | __per_cpu_start = .; | 68 | __per_cpu_start = .; |
68 | *(.data.percpu.page_aligned) | 69 | *(.data.percpu.page_aligned) |
69 | *(.data.percpu) | 70 | *(.data.percpu) |
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index f45e4e508eca..3765efc5f963 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S | |||
@@ -213,17 +213,9 @@ SECTIONS | |||
213 | { *(.data.cacheline_aligned) } | 213 | { *(.data.cacheline_aligned) } |
214 | 214 | ||
215 | /* Per-cpu data: */ | 215 | /* Per-cpu data: */ |
216 | percpu : { } :percpu | ||
217 | . = ALIGN(PERCPU_PAGE_SIZE); | 216 | . = ALIGN(PERCPU_PAGE_SIZE); |
218 | __phys_per_cpu_start = .; | 217 | PERCPU_VADDR(PERCPU_ADDR, :percpu) |
219 | .data.percpu PERCPU_ADDR : AT(__phys_per_cpu_start - LOAD_OFFSET) | 218 | __phys_per_cpu_start = __per_cpu_load; |
220 | { | ||
221 | __per_cpu_start = .; | ||
222 | *(.data.percpu.page_aligned) | ||
223 | *(.data.percpu) | ||
224 | *(.data.percpu.shared_aligned) | ||
225 | __per_cpu_end = .; | ||
226 | } | ||
227 | . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits | 219 | . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits |
228 | * into percpu page size | 220 | * into percpu page size |
229 | */ | 221 | */ |
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 295ccc5e86b1..67f07f453385 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S | |||
@@ -181,14 +181,7 @@ SECTIONS | |||
181 | __initramfs_end = .; | 181 | __initramfs_end = .; |
182 | } | 182 | } |
183 | #endif | 183 | #endif |
184 | . = ALIGN(PAGE_SIZE); | 184 | PERCPU(PAGE_SIZE) |
185 | .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { | ||
186 | __per_cpu_start = .; | ||
187 | *(.data.percpu.page_aligned) | ||
188 | *(.data.percpu) | ||
189 | *(.data.percpu.shared_aligned) | ||
190 | __per_cpu_end = .; | ||
191 | } | ||
192 | 185 | ||
193 | . = ALIGN(8); | 186 | . = ALIGN(8); |
194 | .machine.desc : AT(ADDR(.machine.desc) - LOAD_OFFSET) { | 187 | .machine.desc : AT(ADDR(.machine.desc) - LOAD_OFFSET) { |
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index 8f1d2fbec1d4..aee103b26d01 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h | |||
@@ -43,14 +43,6 @@ | |||
43 | #else /* ...!ASSEMBLY */ | 43 | #else /* ...!ASSEMBLY */ |
44 | 44 | ||
45 | #include <linux/stringify.h> | 45 | #include <linux/stringify.h> |
46 | #include <asm/sections.h> | ||
47 | |||
48 | #define __addr_to_pcpu_ptr(addr) \ | ||
49 | (void *)((unsigned long)(addr) - (unsigned long)pcpu_base_addr \ | ||
50 | + (unsigned long)__per_cpu_start) | ||
51 | #define __pcpu_ptr_to_addr(ptr) \ | ||
52 | (void *)((unsigned long)(ptr) + (unsigned long)pcpu_base_addr \ | ||
53 | - (unsigned long)__per_cpu_start) | ||
54 | 46 | ||
55 | #ifdef CONFIG_SMP | 47 | #ifdef CONFIG_SMP |
56 | #define __percpu_arg(x) "%%"__stringify(__percpu_seg)":%P" #x | 48 | #define __percpu_arg(x) "%%"__stringify(__percpu_seg)":%P" #x |
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index efa615f2bf43..400331b50a53 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c | |||
@@ -233,8 +233,8 @@ proceed: | |||
233 | "%zu bytes\n", vm.addr, static_size); | 233 | "%zu bytes\n", vm.addr, static_size); |
234 | 234 | ||
235 | ret = pcpu_setup_first_chunk(pcpur_get_page, static_size, | 235 | ret = pcpu_setup_first_chunk(pcpur_get_page, static_size, |
236 | PERCPU_FIRST_CHUNK_RESERVE, | 236 | PERCPU_FIRST_CHUNK_RESERVE, dyn_size, |
237 | PMD_SIZE, dyn_size, vm.addr, NULL); | 237 | PMD_SIZE, vm.addr, NULL); |
238 | goto out_free_ar; | 238 | goto out_free_ar; |
239 | 239 | ||
240 | enomem: | 240 | enomem: |
@@ -257,31 +257,13 @@ static ssize_t __init setup_pcpu_remap(size_t static_size) | |||
257 | * Embedding allocator | 257 | * Embedding allocator |
258 | * | 258 | * |
259 | * The first chunk is sized to just contain the static area plus | 259 | * The first chunk is sized to just contain the static area plus |
260 | * module and dynamic reserves, and allocated as a contiguous area | 260 | * module and dynamic reserves and embedded into linear physical |
261 | * using bootmem allocator and used as-is without being mapped into | 261 | * mapping so that it can use PMD mapping without additional TLB |
262 | * vmalloc area. This enables the first chunk to piggy back on the | 262 | * pressure. |
263 | * linear physical PMD mapping and doesn't add any additional pressure | ||
264 | * to TLB. Note that if the needed size is smaller than the minimum | ||
265 | * unit size, the leftover is returned to the bootmem allocator. | ||
266 | */ | 263 | */ |
267 | static void *pcpue_ptr __initdata; | ||
268 | static size_t pcpue_size __initdata; | ||
269 | static size_t pcpue_unit_size __initdata; | ||
270 | |||
271 | static struct page * __init pcpue_get_page(unsigned int cpu, int pageno) | ||
272 | { | ||
273 | size_t off = (size_t)pageno << PAGE_SHIFT; | ||
274 | |||
275 | if (off >= pcpue_size) | ||
276 | return NULL; | ||
277 | |||
278 | return virt_to_page(pcpue_ptr + cpu * pcpue_unit_size + off); | ||
279 | } | ||
280 | |||
281 | static ssize_t __init setup_pcpu_embed(size_t static_size) | 264 | static ssize_t __init setup_pcpu_embed(size_t static_size) |
282 | { | 265 | { |
283 | unsigned int cpu; | 266 | size_t reserve = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE; |
284 | size_t dyn_size; | ||
285 | 267 | ||
286 | /* | 268 | /* |
287 | * If large page isn't supported, there's no benefit in doing | 269 | * If large page isn't supported, there's no benefit in doing |
@@ -291,33 +273,8 @@ static ssize_t __init setup_pcpu_embed(size_t static_size) | |||
291 | if (!cpu_has_pse || pcpu_need_numa()) | 273 | if (!cpu_has_pse || pcpu_need_numa()) |
292 | return -EINVAL; | 274 | return -EINVAL; |
293 | 275 | ||
294 | /* allocate and copy */ | 276 | return pcpu_embed_first_chunk(static_size, PERCPU_FIRST_CHUNK_RESERVE, |
295 | pcpue_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE + | 277 | reserve - PERCPU_FIRST_CHUNK_RESERVE, -1); |
296 | PERCPU_DYNAMIC_RESERVE); | ||
297 | pcpue_unit_size = max_t(size_t, pcpue_size, PCPU_MIN_UNIT_SIZE); | ||
298 | dyn_size = pcpue_size - static_size - PERCPU_FIRST_CHUNK_RESERVE; | ||
299 | |||
300 | pcpue_ptr = pcpu_alloc_bootmem(0, num_possible_cpus() * pcpue_unit_size, | ||
301 | PAGE_SIZE); | ||
302 | if (!pcpue_ptr) | ||
303 | return -ENOMEM; | ||
304 | |||
305 | for_each_possible_cpu(cpu) { | ||
306 | void *ptr = pcpue_ptr + cpu * pcpue_unit_size; | ||
307 | |||
308 | free_bootmem(__pa(ptr + pcpue_size), | ||
309 | pcpue_unit_size - pcpue_size); | ||
310 | memcpy(ptr, __per_cpu_load, static_size); | ||
311 | } | ||
312 | |||
313 | /* we're ready, commit */ | ||
314 | pr_info("PERCPU: Embedded %zu pages at %p, static data %zu bytes\n", | ||
315 | pcpue_size >> PAGE_SHIFT, pcpue_ptr, static_size); | ||
316 | |||
317 | return pcpu_setup_first_chunk(pcpue_get_page, static_size, | ||
318 | PERCPU_FIRST_CHUNK_RESERVE, | ||
319 | pcpue_unit_size, dyn_size, | ||
320 | pcpue_ptr, NULL); | ||
321 | } | 278 | } |
322 | 279 | ||
323 | /* | 280 | /* |
@@ -375,8 +332,8 @@ static ssize_t __init setup_pcpu_4k(size_t static_size) | |||
375 | pcpu4k_nr_static_pages, static_size); | 332 | pcpu4k_nr_static_pages, static_size); |
376 | 333 | ||
377 | ret = pcpu_setup_first_chunk(pcpu4k_get_page, static_size, | 334 | ret = pcpu_setup_first_chunk(pcpu4k_get_page, static_size, |
378 | PERCPU_FIRST_CHUNK_RESERVE, -1, -1, NULL, | 335 | PERCPU_FIRST_CHUNK_RESERVE, -1, |
379 | pcpu4k_populate_pte); | 336 | -1, NULL, pcpu4k_populate_pte); |
380 | goto out_free_ar; | 337 | goto out_free_ar; |
381 | 338 | ||
382 | enomem: | 339 | enomem: |
diff --git a/include/linux/percpu.h b/include/linux/percpu.h index 54a968b4b924..ee5615d65211 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h | |||
@@ -107,10 +107,14 @@ typedef void (*pcpu_populate_pte_fn_t)(unsigned long addr); | |||
107 | 107 | ||
108 | extern size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, | 108 | extern size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, |
109 | size_t static_size, size_t reserved_size, | 109 | size_t static_size, size_t reserved_size, |
110 | ssize_t unit_size, ssize_t dyn_size, | 110 | ssize_t dyn_size, ssize_t unit_size, |
111 | void *base_addr, | 111 | void *base_addr, |
112 | pcpu_populate_pte_fn_t populate_pte_fn); | 112 | pcpu_populate_pte_fn_t populate_pte_fn); |
113 | 113 | ||
114 | extern ssize_t __init pcpu_embed_first_chunk( | ||
115 | size_t static_size, size_t reserved_size, | ||
116 | ssize_t dyn_size, ssize_t unit_size); | ||
117 | |||
114 | /* | 118 | /* |
115 | * Use this to get to a cpu's version of the per-cpu object | 119 | * Use this to get to a cpu's version of the per-cpu object |
116 | * dynamically allocated. Non-atomic access to the current CPU's | 120 | * dynamically allocated. Non-atomic access to the current CPU's |
diff --git a/mm/allocpercpu.c b/mm/allocpercpu.c index 3653c570232b..1882923bc706 100644 --- a/mm/allocpercpu.c +++ b/mm/allocpercpu.c | |||
@@ -120,7 +120,7 @@ void *__alloc_percpu(size_t size, size_t align) | |||
120 | * on it. Larger alignment should only be used for module | 120 | * on it. Larger alignment should only be used for module |
121 | * percpu sections on SMP for which this path isn't used. | 121 | * percpu sections on SMP for which this path isn't used. |
122 | */ | 122 | */ |
123 | WARN_ON_ONCE(align > __alignof__(unsigned long long)); | 123 | WARN_ON_ONCE(align > SMP_CACHE_BYTES); |
124 | 124 | ||
125 | if (unlikely(!pdata)) | 125 | if (unlikely(!pdata)) |
126 | return NULL; | 126 | return NULL; |
diff --git a/mm/percpu.c b/mm/percpu.c index bfe6a3afaf45..1aa5d8fbca12 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
@@ -46,7 +46,8 @@ | |||
46 | * - define CONFIG_HAVE_DYNAMIC_PER_CPU_AREA | 46 | * - define CONFIG_HAVE_DYNAMIC_PER_CPU_AREA |
47 | * | 47 | * |
48 | * - define __addr_to_pcpu_ptr() and __pcpu_ptr_to_addr() to translate | 48 | * - define __addr_to_pcpu_ptr() and __pcpu_ptr_to_addr() to translate |
49 | * regular address to percpu pointer and back | 49 | * regular address to percpu pointer and back if they need to be |
50 | * different from the default | ||
50 | * | 51 | * |
51 | * - use pcpu_setup_first_chunk() during percpu area initialization to | 52 | * - use pcpu_setup_first_chunk() during percpu area initialization to |
52 | * setup the first chunk containing the kernel static percpu area | 53 | * setup the first chunk containing the kernel static percpu area |
@@ -67,11 +68,24 @@ | |||
67 | #include <linux/workqueue.h> | 68 | #include <linux/workqueue.h> |
68 | 69 | ||
69 | #include <asm/cacheflush.h> | 70 | #include <asm/cacheflush.h> |
71 | #include <asm/sections.h> | ||
70 | #include <asm/tlbflush.h> | 72 | #include <asm/tlbflush.h> |
71 | 73 | ||
72 | #define PCPU_SLOT_BASE_SHIFT 5 /* 1-31 shares the same slot */ | 74 | #define PCPU_SLOT_BASE_SHIFT 5 /* 1-31 shares the same slot */ |
73 | #define PCPU_DFL_MAP_ALLOC 16 /* start a map with 16 ents */ | 75 | #define PCPU_DFL_MAP_ALLOC 16 /* start a map with 16 ents */ |
74 | 76 | ||
77 | /* default addr <-> pcpu_ptr mapping, override in asm/percpu.h if necessary */ | ||
78 | #ifndef __addr_to_pcpu_ptr | ||
79 | #define __addr_to_pcpu_ptr(addr) \ | ||
80 | (void *)((unsigned long)(addr) - (unsigned long)pcpu_base_addr \ | ||
81 | + (unsigned long)__per_cpu_start) | ||
82 | #endif | ||
83 | #ifndef __pcpu_ptr_to_addr | ||
84 | #define __pcpu_ptr_to_addr(ptr) \ | ||
85 | (void *)((unsigned long)(ptr) + (unsigned long)pcpu_base_addr \ | ||
86 | - (unsigned long)__per_cpu_start) | ||
87 | #endif | ||
88 | |||
75 | struct pcpu_chunk { | 89 | struct pcpu_chunk { |
76 | struct list_head list; /* linked to pcpu_slot lists */ | 90 | struct list_head list; /* linked to pcpu_slot lists */ |
77 | struct rb_node rb_node; /* key is chunk->vm->addr */ | 91 | struct rb_node rb_node; /* key is chunk->vm->addr */ |
@@ -1013,8 +1027,8 @@ EXPORT_SYMBOL_GPL(free_percpu); | |||
1013 | * @get_page_fn: callback to fetch page pointer | 1027 | * @get_page_fn: callback to fetch page pointer |
1014 | * @static_size: the size of static percpu area in bytes | 1028 | * @static_size: the size of static percpu area in bytes |
1015 | * @reserved_size: the size of reserved percpu area in bytes | 1029 | * @reserved_size: the size of reserved percpu area in bytes |
1016 | * @unit_size: unit size in bytes, must be multiple of PAGE_SIZE, -1 for auto | ||
1017 | * @dyn_size: free size for dynamic allocation in bytes, -1 for auto | 1030 | * @dyn_size: free size for dynamic allocation in bytes, -1 for auto |
1031 | * @unit_size: unit size in bytes, must be multiple of PAGE_SIZE, -1 for auto | ||
1018 | * @base_addr: mapped address, NULL for auto | 1032 | * @base_addr: mapped address, NULL for auto |
1019 | * @populate_pte_fn: callback to allocate pagetable, NULL if unnecessary | 1033 | * @populate_pte_fn: callback to allocate pagetable, NULL if unnecessary |
1020 | * | 1034 | * |
@@ -1039,14 +1053,14 @@ EXPORT_SYMBOL_GPL(free_percpu); | |||
1039 | * limited offset range for symbol relocations to guarantee module | 1053 | * limited offset range for symbol relocations to guarantee module |
1040 | * percpu symbols fall inside the relocatable range. | 1054 | * percpu symbols fall inside the relocatable range. |
1041 | * | 1055 | * |
1056 | * @dyn_size, if non-negative, determines the number of bytes | ||
1057 | * available for dynamic allocation in the first chunk. Specifying | ||
1058 | * non-negative value makes percpu leave alone the area beyond | ||
1059 | * @static_size + @reserved_size + @dyn_size. | ||
1060 | * | ||
1042 | * @unit_size, if non-negative, specifies unit size and must be | 1061 | * @unit_size, if non-negative, specifies unit size and must be |
1043 | * aligned to PAGE_SIZE and equal to or larger than @static_size + | 1062 | * aligned to PAGE_SIZE and equal to or larger than @static_size + |
1044 | * @reserved_size + @dyn_size. | 1063 | * @reserved_size + if non-negative, @dyn_size. |
1045 | * | ||
1046 | * @dyn_size, if non-negative, limits the number of bytes available | ||
1047 | * for dynamic allocation in the first chunk. Specifying non-negative | ||
1048 | * value make percpu leave alone the area beyond @static_size + | ||
1049 | * @reserved_size + @dyn_size. | ||
1050 | * | 1064 | * |
1051 | * Non-null @base_addr means that the caller already allocated virtual | 1065 | * Non-null @base_addr means that the caller already allocated virtual |
1052 | * region for the first chunk and mapped it. percpu must not mess | 1066 | * region for the first chunk and mapped it. percpu must not mess |
@@ -1069,12 +1083,14 @@ EXPORT_SYMBOL_GPL(free_percpu); | |||
1069 | */ | 1083 | */ |
1070 | size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, | 1084 | size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, |
1071 | size_t static_size, size_t reserved_size, | 1085 | size_t static_size, size_t reserved_size, |
1072 | ssize_t unit_size, ssize_t dyn_size, | 1086 | ssize_t dyn_size, ssize_t unit_size, |
1073 | void *base_addr, | 1087 | void *base_addr, |
1074 | pcpu_populate_pte_fn_t populate_pte_fn) | 1088 | pcpu_populate_pte_fn_t populate_pte_fn) |
1075 | { | 1089 | { |
1076 | static struct vm_struct first_vm; | 1090 | static struct vm_struct first_vm; |
1077 | static int smap[2], dmap[2]; | 1091 | static int smap[2], dmap[2]; |
1092 | size_t size_sum = static_size + reserved_size + | ||
1093 | (dyn_size >= 0 ? dyn_size : 0); | ||
1078 | struct pcpu_chunk *schunk, *dchunk = NULL; | 1094 | struct pcpu_chunk *schunk, *dchunk = NULL; |
1079 | unsigned int cpu; | 1095 | unsigned int cpu; |
1080 | int nr_pages; | 1096 | int nr_pages; |
@@ -1085,20 +1101,18 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, | |||
1085 | ARRAY_SIZE(dmap) >= PCPU_DFL_MAP_ALLOC); | 1101 | ARRAY_SIZE(dmap) >= PCPU_DFL_MAP_ALLOC); |
1086 | BUG_ON(!static_size); | 1102 | BUG_ON(!static_size); |
1087 | if (unit_size >= 0) { | 1103 | if (unit_size >= 0) { |
1088 | BUG_ON(unit_size < static_size + reserved_size + | 1104 | BUG_ON(unit_size < size_sum); |
1089 | (dyn_size >= 0 ? dyn_size : 0)); | ||
1090 | BUG_ON(unit_size & ~PAGE_MASK); | 1105 | BUG_ON(unit_size & ~PAGE_MASK); |
1091 | } else { | 1106 | BUG_ON(unit_size < PCPU_MIN_UNIT_SIZE); |
1092 | BUG_ON(dyn_size >= 0); | 1107 | } else |
1093 | BUG_ON(base_addr); | 1108 | BUG_ON(base_addr); |
1094 | } | ||
1095 | BUG_ON(base_addr && populate_pte_fn); | 1109 | BUG_ON(base_addr && populate_pte_fn); |
1096 | 1110 | ||
1097 | if (unit_size >= 0) | 1111 | if (unit_size >= 0) |
1098 | pcpu_unit_pages = unit_size >> PAGE_SHIFT; | 1112 | pcpu_unit_pages = unit_size >> PAGE_SHIFT; |
1099 | else | 1113 | else |
1100 | pcpu_unit_pages = max_t(int, PCPU_MIN_UNIT_SIZE >> PAGE_SHIFT, | 1114 | pcpu_unit_pages = max_t(int, PCPU_MIN_UNIT_SIZE >> PAGE_SHIFT, |
1101 | PFN_UP(static_size + reserved_size)); | 1115 | PFN_UP(size_sum)); |
1102 | 1116 | ||
1103 | pcpu_unit_size = pcpu_unit_pages << PAGE_SHIFT; | 1117 | pcpu_unit_size = pcpu_unit_pages << PAGE_SHIFT; |
1104 | pcpu_chunk_size = num_possible_cpus() * pcpu_unit_size; | 1118 | pcpu_chunk_size = num_possible_cpus() * pcpu_unit_size; |
@@ -1224,3 +1238,89 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, | |||
1224 | pcpu_base_addr = (void *)pcpu_chunk_addr(schunk, 0, 0); | 1238 | pcpu_base_addr = (void *)pcpu_chunk_addr(schunk, 0, 0); |
1225 | return pcpu_unit_size; | 1239 | return pcpu_unit_size; |
1226 | } | 1240 | } |
1241 | |||
1242 | /* | ||
1243 | * Embedding first chunk setup helper. | ||
1244 | */ | ||
1245 | static void *pcpue_ptr __initdata; | ||
1246 | static size_t pcpue_size __initdata; | ||
1247 | static size_t pcpue_unit_size __initdata; | ||
1248 | |||
1249 | static struct page * __init pcpue_get_page(unsigned int cpu, int pageno) | ||
1250 | { | ||
1251 | size_t off = (size_t)pageno << PAGE_SHIFT; | ||
1252 | |||
1253 | if (off >= pcpue_size) | ||
1254 | return NULL; | ||
1255 | |||
1256 | return virt_to_page(pcpue_ptr + cpu * pcpue_unit_size + off); | ||
1257 | } | ||
1258 | |||
1259 | /** | ||
1260 | * pcpu_embed_first_chunk - embed the first percpu chunk into bootmem | ||
1261 | * @static_size: the size of static percpu area in bytes | ||
1262 | * @reserved_size: the size of reserved percpu area in bytes | ||
1263 | * @dyn_size: free size for dynamic allocation in bytes, -1 for auto | ||
1264 | * @unit_size: unit size in bytes, must be multiple of PAGE_SIZE, -1 for auto | ||
1265 | * | ||
1266 | * This is a helper to ease setting up embedded first percpu chunk and | ||
1267 | * can be called where pcpu_setup_first_chunk() is expected. | ||
1268 | * | ||
1269 | * If this function is used to setup the first chunk, it is allocated | ||
1270 | * as a contiguous area using bootmem allocator and used as-is without | ||
1271 | * being mapped into vmalloc area. This enables the first chunk to | ||
1272 | * piggy back on the linear physical mapping which often uses larger | ||
1273 | * page size. | ||
1274 | * | ||
1275 | * When @dyn_size is positive, dynamic area might be larger than | ||
1276 | * specified to fill page alignment. Also, when @dyn_size is auto, | ||
1277 | * @dyn_size does not fill the whole first chunk but only what's | ||
1278 | * necessary for page alignment after static and reserved areas. | ||
1279 | * | ||
1280 | * If the needed size is smaller than the minimum or specified unit | ||
1281 | * size, the leftover is returned to the bootmem allocator. | ||
1282 | * | ||
1283 | * RETURNS: | ||
1284 | * The determined pcpu_unit_size which can be used to initialize | ||
1285 | * percpu access on success, -errno on failure. | ||
1286 | */ | ||
1287 | ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size, | ||
1288 | ssize_t dyn_size, ssize_t unit_size) | ||
1289 | { | ||
1290 | unsigned int cpu; | ||
1291 | |||
1292 | /* determine parameters and allocate */ | ||
1293 | pcpue_size = PFN_ALIGN(static_size + reserved_size + | ||
1294 | (dyn_size >= 0 ? dyn_size : 0)); | ||
1295 | if (dyn_size != 0) | ||
1296 | dyn_size = pcpue_size - static_size - reserved_size; | ||
1297 | |||
1298 | if (unit_size >= 0) { | ||
1299 | BUG_ON(unit_size < pcpue_size); | ||
1300 | pcpue_unit_size = unit_size; | ||
1301 | } else | ||
1302 | pcpue_unit_size = max_t(size_t, pcpue_size, PCPU_MIN_UNIT_SIZE); | ||
1303 | |||
1304 | pcpue_ptr = __alloc_bootmem_nopanic( | ||
1305 | num_possible_cpus() * pcpue_unit_size, | ||
1306 | PAGE_SIZE, __pa(MAX_DMA_ADDRESS)); | ||
1307 | if (!pcpue_ptr) | ||
1308 | return -ENOMEM; | ||
1309 | |||
1310 | /* return the leftover and copy */ | ||
1311 | for_each_possible_cpu(cpu) { | ||
1312 | void *ptr = pcpue_ptr + cpu * pcpue_unit_size; | ||
1313 | |||
1314 | free_bootmem(__pa(ptr + pcpue_size), | ||
1315 | pcpue_unit_size - pcpue_size); | ||
1316 | memcpy(ptr, __per_cpu_load, static_size); | ||
1317 | } | ||
1318 | |||
1319 | /* we're ready, commit */ | ||
1320 | pr_info("PERCPU: Embedded %zu pages at %p, static data %zu bytes\n", | ||
1321 | pcpue_size >> PAGE_SHIFT, pcpue_ptr, static_size); | ||
1322 | |||
1323 | return pcpu_setup_first_chunk(pcpue_get_page, static_size, | ||
1324 | reserved_size, dyn_size, | ||
1325 | pcpue_unit_size, pcpue_ptr, NULL); | ||
1326 | } | ||