diff options
author | Tejun Heo <tj@kernel.org> | 2009-03-10 03:27:48 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2009-03-10 03:27:48 -0400 |
commit | 66c3a75772247c31feabefb724e082220a1ab060 (patch) | |
tree | 5e61a0e44c82474729e81007edc2093d37fffe95 /mm | |
parent | 6074d5b0a319fe8400ff079a3c289406ca024321 (diff) |
percpu: generalize embedding first chunk setup helper
Impact: code reorganization
Separate out embedding first chunk setup helper from x86 embedding
first chunk allocator and put it in mm/percpu.c. This will be used by
the default percpu first chunk allocator and possibly by other archs.
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/percpu.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/mm/percpu.c b/mm/percpu.c index 2f94661d3e36..1aa5d8fbca12 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
@@ -1238,3 +1238,89 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, | |||
1238 | pcpu_base_addr = (void *)pcpu_chunk_addr(schunk, 0, 0); | 1238 | pcpu_base_addr = (void *)pcpu_chunk_addr(schunk, 0, 0); |
1239 | return pcpu_unit_size; | 1239 | return pcpu_unit_size; |
1240 | } | 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 | } | ||