aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/Makefile2
-rw-r--r--mm/allocpercpu.c28
-rw-r--r--mm/percpu.c40
3 files changed, 68 insertions, 2 deletions
diff --git a/mm/Makefile b/mm/Makefile
index 5e0bd6426693..c77c6487552f 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -33,7 +33,7 @@ obj-$(CONFIG_FAILSLAB) += failslab.o
33obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o 33obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
34obj-$(CONFIG_FS_XIP) += filemap_xip.o 34obj-$(CONFIG_FS_XIP) += filemap_xip.o
35obj-$(CONFIG_MIGRATION) += migrate.o 35obj-$(CONFIG_MIGRATION) += migrate.o
36ifdef CONFIG_HAVE_DYNAMIC_PER_CPU_AREA 36ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
37obj-$(CONFIG_SMP) += percpu.o 37obj-$(CONFIG_SMP) += percpu.o
38else 38else
39obj-$(CONFIG_SMP) += allocpercpu.o 39obj-$(CONFIG_SMP) += allocpercpu.o
diff --git a/mm/allocpercpu.c b/mm/allocpercpu.c
index dfdee6a47359..df34ceae0c67 100644
--- a/mm/allocpercpu.c
+++ b/mm/allocpercpu.c
@@ -5,6 +5,8 @@
5 */ 5 */
6#include <linux/mm.h> 6#include <linux/mm.h>
7#include <linux/module.h> 7#include <linux/module.h>
8#include <linux/bootmem.h>
9#include <asm/sections.h>
8 10
9#ifndef cache_line_size 11#ifndef cache_line_size
10#define cache_line_size() L1_CACHE_BYTES 12#define cache_line_size() L1_CACHE_BYTES
@@ -147,3 +149,29 @@ void free_percpu(void *__pdata)
147 kfree(__percpu_disguise(__pdata)); 149 kfree(__percpu_disguise(__pdata));
148} 150}
149EXPORT_SYMBOL_GPL(free_percpu); 151EXPORT_SYMBOL_GPL(free_percpu);
152
153/*
154 * Generic percpu area setup.
155 */
156#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
157unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
158
159EXPORT_SYMBOL(__per_cpu_offset);
160
161void __init setup_per_cpu_areas(void)
162{
163 unsigned long size, i;
164 char *ptr;
165 unsigned long nr_possible_cpus = num_possible_cpus();
166
167 /* Copy section for each CPU (we discard the original) */
168 size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
169 ptr = alloc_bootmem_pages(size * nr_possible_cpus);
170
171 for_each_possible_cpu(i) {
172 __per_cpu_offset[i] = ptr - __per_cpu_start;
173 memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
174 ptr += size;
175 }
176}
177#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
diff --git a/mm/percpu.c b/mm/percpu.c
index b70f2acd8853..b14984566f5a 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -43,7 +43,7 @@
43 * 43 *
44 * To use this allocator, arch code should do the followings. 44 * To use this allocator, arch code should do the followings.
45 * 45 *
46 * - define CONFIG_HAVE_DYNAMIC_PER_CPU_AREA 46 * - drop CONFIG_HAVE_LEGACY_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 if they need to be 49 * regular address to percpu pointer and back if they need to be
@@ -1275,3 +1275,41 @@ ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size,
1275 reserved_size, dyn_size, 1275 reserved_size, dyn_size,
1276 pcpue_unit_size, pcpue_ptr, NULL); 1276 pcpue_unit_size, pcpue_ptr, NULL);
1277} 1277}
1278
1279/*
1280 * Generic percpu area setup.
1281 *
1282 * The embedding helper is used because its behavior closely resembles
1283 * the original non-dynamic generic percpu area setup. This is
1284 * important because many archs have addressing restrictions and might
1285 * fail if the percpu area is located far away from the previous
1286 * location. As an added bonus, in non-NUMA cases, embedding is
1287 * generally a good idea TLB-wise because percpu area can piggy back
1288 * on the physical linear memory mapping which uses large page
1289 * mappings on applicable archs.
1290 */
1291#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
1292unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
1293EXPORT_SYMBOL(__per_cpu_offset);
1294
1295void __init setup_per_cpu_areas(void)
1296{
1297 size_t static_size = __per_cpu_end - __per_cpu_start;
1298 ssize_t unit_size;
1299 unsigned long delta;
1300 unsigned int cpu;
1301
1302 /*
1303 * Always reserve area for module percpu variables. That's
1304 * what the legacy allocator did.
1305 */
1306 unit_size = pcpu_embed_first_chunk(static_size, PERCPU_MODULE_RESERVE,
1307 PERCPU_DYNAMIC_RESERVE, -1);
1308 if (unit_size < 0)
1309 panic("Failed to initialized percpu areas.");
1310
1311 delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
1312 for_each_possible_cpu(cpu)
1313 __per_cpu_offset[cpu] = delta + cpu * unit_size;
1314}
1315#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */