summaryrefslogtreecommitdiff
path: root/init
diff options
context:
space:
mode:
authorYinghai Lu <yhlu.kernel@gmail.com>2008-08-19 20:49:44 -0700
committerIngo Molnar <mingo@elte.hu>2008-10-16 16:52:03 +0200
commit1f3fcd4b1adc972d5c6a34cfed98931c46575b49 (patch)
treea79b6c656a09a8424863a0025d5b20e7264d6999 /init
parent3ddfda11861d305b02ed810b522dcf48b74ca808 (diff)
downloadlwn-1f3fcd4b1adc972d5c6a34cfed98931c46575b49.tar.gz
lwn-1f3fcd4b1adc972d5c6a34cfed98931c46575b49.zip
add per_cpu_dyn_array support
allow dyn-array in per_cpu area, allocated dynamically. usage: | /* in .h */ | struct kernel_stat { | struct cpu_usage_stat cpustat; | unsigned int *irqs; | }; | | /* in .c */ | DEFINE_PER_CPU(struct kernel_stat, kstat); | | DEFINE_PER_CPU_DYN_ARRAY_ADDR(per_cpu__kstat_irqs, per_cpu__kstat.irqs, sizeof(unsigned int), nr_irqs, sizeof(unsigned long), NULL); after setup_percpu()/per_cpu_alloc_dyn_array(), the dyn_array in per_cpu area is ready to use. Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'init')
-rw-r--r--init/main.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/init/main.c b/init/main.c
index 638d3a786412..416bca4f734f 100644
--- a/init/main.c
+++ b/init/main.c
@@ -391,17 +391,19 @@ EXPORT_SYMBOL(__per_cpu_offset);
static void __init setup_per_cpu_areas(void)
{
- unsigned long size, i;
+ unsigned long size, i, old_size;
char *ptr;
unsigned long nr_possible_cpus = num_possible_cpus();
/* Copy section for each CPU (we discard the original) */
- size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
+ old_size = PERCPU_ENOUGH_ROOM;
+ size = ALIGN(old_size + per_cpu_dyn_array_size(), PAGE_SIZE);
ptr = alloc_bootmem_pages(size * nr_possible_cpus);
for_each_possible_cpu(i) {
__per_cpu_offset[i] = ptr - __per_cpu_start;
memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+ per_cpu_alloc_dyn_array(i, ptr + old_size);
ptr += size;
}
}
@@ -559,6 +561,63 @@ void pre_alloc_dyn_array(void)
#endif
}
+unsigned long per_cpu_dyn_array_size(void)
+{
+ unsigned long total_size = 0;
+#ifdef CONFIG_HAVE_DYN_ARRAY
+ unsigned long size;
+ struct dyn_array **daa;
+
+ for (daa = __per_cpu_dyn_array_start ; daa < __per_cpu_dyn_array_end; daa++) {
+ struct dyn_array *da = *daa;
+
+ size = da->size * (*da->nr);
+ print_fn_descriptor_symbol("per_cpu_dyna_array %s ", da->name);
+ printk(KERN_CONT "size:%#lx nr:%d align:%#lx\n",
+ da->size, *da->nr, da->align);
+ total_size += roundup(size, da->align);
+ }
+ if (total_size)
+ printk(KERN_DEBUG "per_cpu_dyna_array total_size: %#lx\n",
+ total_size);
+#endif
+ return total_size;
+}
+
+void per_cpu_alloc_dyn_array(int cpu, char *ptr)
+{
+#ifdef CONFIG_HAVE_DYN_ARRAY
+ unsigned long size, phys;
+ struct dyn_array **daa;
+ unsigned long addr;
+ void **array;
+
+ phys = virt_to_phys(ptr);
+
+ for (daa = __per_cpu_dyn_array_start ; daa < __per_cpu_dyn_array_end; daa++) {
+ struct dyn_array *da = *daa;
+
+ size = da->size * (*da->nr);
+ print_fn_descriptor_symbol("per_cpu_dyna_array %s ", da->name);
+ printk(KERN_CONT "size:%#lx nr:%d align:%#lx",
+ da->size, *da->nr, da->align);
+
+ phys = roundup(phys, da->align);
+ addr = (unsigned long)da->name;
+ addr += per_cpu_offset(cpu);
+ array = (void **)addr;
+ *array = phys_to_virt(phys);
+ *da->name = *array; /* so init_work could use it directly */
+ printk(KERN_CONT " %p ==> [%#lx - %#lx]\n", array, phys, phys + size);
+ phys += size;
+
+ if (da->init_work) {
+ da->init_work(da);
+ }
+ }
+#endif
+}
+
asmlinkage void __init start_kernel(void)
{
char * command_line;