diff options
author | Tejun Heo <tj@kernel.org> | 2009-08-14 02:00:51 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2009-08-14 02:00:51 -0400 |
commit | fb435d5233f8b6f9b93c11d6304d8e98fed03234 (patch) | |
tree | 76a210c3895b9db5dc7e1f185ee0a60744fef99a /arch | |
parent | fd1e8a1fe2b54df6c185b4fa65f181f50b9c4d4e (diff) |
percpu: add pcpu_unit_offsets[]
Currently units are mapped sequentially into address space. This
patch adds pcpu_unit_offsets[] which allows units to be mapped to
arbitrary offsets from the chunk base address. This is necessary to
allow sparse embedding which might would need to allocate address
ranges and memory areas which aren't aligned to unit size but
allocation atom size (page or large page size). This also simplifies
things a bit by removing the need to calculate offset from unit
number.
With this change, there's no need for the arch code to know
pcpu_unit_size. Update pcpu_setup_first_chunk() and first chunk
allocators to return regular 0 or -errno return code instead of unit
size or -errno.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc/kernel/smp_64.c | 12 | ||||
-rw-r--r-- | arch/x86/kernel/setup_percpu.c | 51 |
2 files changed, 30 insertions, 33 deletions
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index a42a4a744d14..b03fd362c629 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c | |||
@@ -1478,9 +1478,10 @@ void __init setup_per_cpu_areas(void) | |||
1478 | static struct vm_struct vm; | 1478 | static struct vm_struct vm; |
1479 | struct pcpu_alloc_info *ai; | 1479 | struct pcpu_alloc_info *ai; |
1480 | unsigned long delta, cpu; | 1480 | unsigned long delta, cpu; |
1481 | size_t size_sum, pcpu_unit_size; | 1481 | size_t size_sum; |
1482 | size_t ptrs_size; | 1482 | size_t ptrs_size; |
1483 | void **ptrs; | 1483 | void **ptrs; |
1484 | int rc; | ||
1484 | 1485 | ||
1485 | ai = pcpu_alloc_alloc_info(1, nr_cpu_ids); | 1486 | ai = pcpu_alloc_alloc_info(1, nr_cpu_ids); |
1486 | 1487 | ||
@@ -1526,14 +1527,15 @@ void __init setup_per_cpu_areas(void) | |||
1526 | pcpu_map_range(start, end, virt_to_page(ptrs[cpu])); | 1527 | pcpu_map_range(start, end, virt_to_page(ptrs[cpu])); |
1527 | } | 1528 | } |
1528 | 1529 | ||
1529 | pcpu_unit_size = pcpu_setup_first_chunk(ai, vm.addr); | 1530 | rc = pcpu_setup_first_chunk(ai, vm.addr); |
1531 | if (rc) | ||
1532 | panic("failed to setup percpu first chunk (%d)", rc); | ||
1530 | 1533 | ||
1531 | free_bootmem(__pa(ptrs), ptrs_size); | 1534 | free_bootmem(__pa(ptrs), ptrs_size); |
1532 | 1535 | ||
1533 | delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; | 1536 | delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; |
1534 | for_each_possible_cpu(cpu) { | 1537 | for_each_possible_cpu(cpu) |
1535 | __per_cpu_offset(cpu) = delta + cpu * pcpu_unit_size; | 1538 | __per_cpu_offset(cpu) = delta + pcpu_unit_offsets[cpu]; |
1536 | } | ||
1537 | 1539 | ||
1538 | /* Setup %g5 for the boot cpu. */ | 1540 | /* Setup %g5 for the boot cpu. */ |
1539 | __local_per_cpu_offset = __per_cpu_offset(smp_processor_id()); | 1541 | __local_per_cpu_offset = __per_cpu_offset(smp_processor_id()); |
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index db5f9c49fec5..9becc5d4b518 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c | |||
@@ -157,12 +157,12 @@ static int pcpu_lpage_cpu_distance(unsigned int from, unsigned int to) | |||
157 | return REMOTE_DISTANCE; | 157 | return REMOTE_DISTANCE; |
158 | } | 158 | } |
159 | 159 | ||
160 | static ssize_t __init setup_pcpu_lpage(bool chosen) | 160 | static int __init setup_pcpu_lpage(bool chosen) |
161 | { | 161 | { |
162 | size_t reserve = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE; | 162 | size_t reserve = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE; |
163 | size_t dyn_size = reserve - PERCPU_FIRST_CHUNK_RESERVE; | 163 | size_t dyn_size = reserve - PERCPU_FIRST_CHUNK_RESERVE; |
164 | struct pcpu_alloc_info *ai; | 164 | struct pcpu_alloc_info *ai; |
165 | ssize_t ret; | 165 | int rc; |
166 | 166 | ||
167 | /* on non-NUMA, embedding is better */ | 167 | /* on non-NUMA, embedding is better */ |
168 | if (!chosen && !pcpu_need_numa()) | 168 | if (!chosen && !pcpu_need_numa()) |
@@ -196,19 +196,18 @@ static ssize_t __init setup_pcpu_lpage(bool chosen) | |||
196 | if (tot_size > vm_size / 5) { | 196 | if (tot_size > vm_size / 5) { |
197 | pr_info("PERCPU: too large chunk size %zuMB for " | 197 | pr_info("PERCPU: too large chunk size %zuMB for " |
198 | "large page remap\n", tot_size >> 20); | 198 | "large page remap\n", tot_size >> 20); |
199 | ret = -EINVAL; | 199 | rc = -EINVAL; |
200 | goto out_free; | 200 | goto out_free; |
201 | } | 201 | } |
202 | } | 202 | } |
203 | 203 | ||
204 | ret = pcpu_lpage_first_chunk(ai, pcpu_fc_alloc, pcpu_fc_free, | 204 | rc = pcpu_lpage_first_chunk(ai, pcpu_fc_alloc, pcpu_fc_free, pcpul_map); |
205 | pcpul_map); | ||
206 | out_free: | 205 | out_free: |
207 | pcpu_free_alloc_info(ai); | 206 | pcpu_free_alloc_info(ai); |
208 | return ret; | 207 | return rc; |
209 | } | 208 | } |
210 | #else | 209 | #else |
211 | static ssize_t __init setup_pcpu_lpage(bool chosen) | 210 | static int __init setup_pcpu_lpage(bool chosen) |
212 | { | 211 | { |
213 | return -EINVAL; | 212 | return -EINVAL; |
214 | } | 213 | } |
@@ -222,7 +221,7 @@ static ssize_t __init setup_pcpu_lpage(bool chosen) | |||
222 | * mapping so that it can use PMD mapping without additional TLB | 221 | * mapping so that it can use PMD mapping without additional TLB |
223 | * pressure. | 222 | * pressure. |
224 | */ | 223 | */ |
225 | static ssize_t __init setup_pcpu_embed(bool chosen) | 224 | static int __init setup_pcpu_embed(bool chosen) |
226 | { | 225 | { |
227 | size_t reserve = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE; | 226 | size_t reserve = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE; |
228 | 227 | ||
@@ -250,7 +249,7 @@ static void __init pcpup_populate_pte(unsigned long addr) | |||
250 | populate_extra_pte(addr); | 249 | populate_extra_pte(addr); |
251 | } | 250 | } |
252 | 251 | ||
253 | static ssize_t __init setup_pcpu_page(void) | 252 | static int __init setup_pcpu_page(void) |
254 | { | 253 | { |
255 | return pcpu_page_first_chunk(PERCPU_FIRST_CHUNK_RESERVE, | 254 | return pcpu_page_first_chunk(PERCPU_FIRST_CHUNK_RESERVE, |
256 | pcpu_fc_alloc, pcpu_fc_free, | 255 | pcpu_fc_alloc, pcpu_fc_free, |
@@ -274,8 +273,7 @@ void __init setup_per_cpu_areas(void) | |||
274 | { | 273 | { |
275 | unsigned int cpu; | 274 | unsigned int cpu; |
276 | unsigned long delta; | 275 | unsigned long delta; |
277 | size_t pcpu_unit_size; | 276 | int rc; |
278 | ssize_t ret; | ||
279 | 277 | ||
280 | pr_info("NR_CPUS:%d nr_cpumask_bits:%d nr_cpu_ids:%d nr_node_ids:%d\n", | 278 | pr_info("NR_CPUS:%d nr_cpumask_bits:%d nr_cpu_ids:%d nr_node_ids:%d\n", |
281 | NR_CPUS, nr_cpumask_bits, nr_cpu_ids, nr_node_ids); | 279 | NR_CPUS, nr_cpumask_bits, nr_cpu_ids, nr_node_ids); |
@@ -285,36 +283,33 @@ void __init setup_per_cpu_areas(void) | |||
285 | * of large page mappings. Please read comments on top of | 283 | * of large page mappings. Please read comments on top of |
286 | * each allocator for details. | 284 | * each allocator for details. |
287 | */ | 285 | */ |
288 | ret = -EINVAL; | 286 | rc = -EINVAL; |
289 | if (pcpu_chosen_fc != PCPU_FC_AUTO) { | 287 | if (pcpu_chosen_fc != PCPU_FC_AUTO) { |
290 | if (pcpu_chosen_fc != PCPU_FC_PAGE) { | 288 | if (pcpu_chosen_fc != PCPU_FC_PAGE) { |
291 | if (pcpu_chosen_fc == PCPU_FC_LPAGE) | 289 | if (pcpu_chosen_fc == PCPU_FC_LPAGE) |
292 | ret = setup_pcpu_lpage(true); | 290 | rc = setup_pcpu_lpage(true); |
293 | else | 291 | else |
294 | ret = setup_pcpu_embed(true); | 292 | rc = setup_pcpu_embed(true); |
295 | 293 | ||
296 | if (ret < 0) | 294 | if (rc < 0) |
297 | pr_warning("PERCPU: %s allocator failed (%zd), " | 295 | pr_warning("PERCPU: %s allocator failed (%d), " |
298 | "falling back to page size\n", | 296 | "falling back to page size\n", |
299 | pcpu_fc_names[pcpu_chosen_fc], ret); | 297 | pcpu_fc_names[pcpu_chosen_fc], rc); |
300 | } | 298 | } |
301 | } else { | 299 | } else { |
302 | ret = setup_pcpu_lpage(false); | 300 | rc = setup_pcpu_lpage(false); |
303 | if (ret < 0) | 301 | if (rc < 0) |
304 | ret = setup_pcpu_embed(false); | 302 | rc = setup_pcpu_embed(false); |
305 | } | 303 | } |
306 | if (ret < 0) | 304 | if (rc < 0) |
307 | ret = setup_pcpu_page(); | 305 | rc = setup_pcpu_page(); |
308 | if (ret < 0) | 306 | if (rc < 0) |
309 | panic("cannot initialize percpu area (err=%zd)", ret); | 307 | panic("cannot initialize percpu area (err=%d)", rc); |
310 | |||
311 | pcpu_unit_size = ret; | ||
312 | 308 | ||
313 | /* alrighty, percpu areas up and running */ | 309 | /* alrighty, percpu areas up and running */ |
314 | delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; | 310 | delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; |
315 | for_each_possible_cpu(cpu) { | 311 | for_each_possible_cpu(cpu) { |
316 | per_cpu_offset(cpu) = | 312 | per_cpu_offset(cpu) = delta + pcpu_unit_offsets[cpu]; |
317 | delta + pcpu_unit_map[cpu] * pcpu_unit_size; | ||
318 | per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu); | 313 | per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu); |
319 | per_cpu(cpu_number, cpu) = cpu; | 314 | per_cpu(cpu_number, cpu) = cpu; |
320 | setup_percpu_segment(cpu); | 315 | setup_percpu_segment(cpu); |