diff options
author | Yinghai Lu <yhlu.kernel@gmail.com> | 2008-08-19 23:49:43 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-16 10:52:02 -0400 |
commit | 3ddfda11861d305b02ed810b522dcf48b74ca808 (patch) | |
tree | 869836872865f07fb56b5fa9649241143ae87b79 | |
parent | 38395738f581ce9417402f28774a8c4650264a00 (diff) |
generic: add dyn_array support
Allow crazy big arrays via bootmem at init stage.
Architectures use CONFIG_HAVE_DYN_ARRAY to enable it.
usage:
| static struct irq_desc irq_desc_init __initdata = {
| .status = IRQ_DISABLED,
| .chip = &no_irq_chip,
| .handle_irq = handle_bad_irq,
| .depth = 1,
| .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
| #ifdef CONFIG_SMP
| .affinity = CPU_MASK_ALL
| #endif
| };
|
| static void __init init_work(void *data)
| {
| struct dyn_array *da = data;
| struct irq_desc *desc;
| int i;
|
| desc = *da->name;
|
| for (i = 0; i < *da->nr; i++)
| memcpy(&desc[i], &irq_desc_init, sizeof(struct irq_desc));
| }
|
| struct irq_desc *irq_desc;
| DEFINE_DYN_ARRAY(irq_desc, sizeof(struct irq_desc), nr_irqs, PAGE_SIZE, init_work);
after pre_alloc_dyn_array() after setup_arch(), the array is ready to be
used.
Via this facility we can replace irq_desc[NR_IRQS] array with dyn_array
irq_desc[nr_irqs].
v2: remove _nopanic in pre_alloc_dyn_array()
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | include/asm-generic/vmlinux.lds.h | 7 | ||||
-rw-r--r-- | include/linux/init.h | 23 | ||||
-rw-r--r-- | init/main.c | 24 |
3 files changed, 54 insertions, 0 deletions
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 7440a0dcedd..7881406c03e 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h | |||
@@ -210,6 +210,13 @@ | |||
210 | * All archs are supposed to use RO_DATA() */ | 210 | * All archs are supposed to use RO_DATA() */ |
211 | #define RODATA RO_DATA(4096) | 211 | #define RODATA RO_DATA(4096) |
212 | 212 | ||
213 | #define DYN_ARRAY_INIT(align) \ | ||
214 | . = ALIGN((align)); \ | ||
215 | .dyn_array.init : AT(ADDR(.dyn_array.init) - LOAD_OFFSET) { \ | ||
216 | VMLINUX_SYMBOL(__dyn_array_start) = .; \ | ||
217 | *(.dyn_array.init) \ | ||
218 | VMLINUX_SYMBOL(__dyn_array_end) = .; \ | ||
219 | } | ||
213 | #define SECURITY_INIT \ | 220 | #define SECURITY_INIT \ |
214 | .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \ | 221 | .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \ |
215 | VMLINUX_SYMBOL(__security_initcall_start) = .; \ | 222 | VMLINUX_SYMBOL(__security_initcall_start) = .; \ |
diff --git a/include/linux/init.h b/include/linux/init.h index 93538b696e3..cf9fa7f174a 100644 --- a/include/linux/init.h +++ b/include/linux/init.h | |||
@@ -246,6 +246,29 @@ struct obs_kernel_param { | |||
246 | 246 | ||
247 | /* Relies on boot_command_line being set */ | 247 | /* Relies on boot_command_line being set */ |
248 | void __init parse_early_param(void); | 248 | void __init parse_early_param(void); |
249 | |||
250 | struct dyn_array { | ||
251 | void **name; | ||
252 | unsigned long size; | ||
253 | unsigned int *nr; | ||
254 | unsigned long align; | ||
255 | void (*init_work)(void *); | ||
256 | }; | ||
257 | extern struct dyn_array *__dyn_array_start[], *__dyn_array_end[]; | ||
258 | |||
259 | #define DEFINE_DYN_ARRAY(nameX, sizeX, nrX, alignX, init_workX) \ | ||
260 | static struct dyn_array __dyn_array_##nameX __initdata = \ | ||
261 | { .name = (void **)&nameX,\ | ||
262 | .size = sizeX,\ | ||
263 | .nr = &nrX,\ | ||
264 | .align = alignX,\ | ||
265 | .init_work = init_workX,\ | ||
266 | }; \ | ||
267 | static struct dyn_array *__dyn_array_ptr_##nameX __used \ | ||
268 | __attribute__((__section__(".dyn_array.init"))) = \ | ||
269 | &__dyn_array_##nameX | ||
270 | |||
271 | extern void pre_alloc_dyn_array(void); | ||
249 | #endif /* __ASSEMBLY__ */ | 272 | #endif /* __ASSEMBLY__ */ |
250 | 273 | ||
251 | /** | 274 | /** |
diff --git a/init/main.c b/init/main.c index 27f6bf6108e..638d3a78641 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -536,6 +536,29 @@ void __init __weak thread_info_cache_init(void) | |||
536 | { | 536 | { |
537 | } | 537 | } |
538 | 538 | ||
539 | void pre_alloc_dyn_array(void) | ||
540 | { | ||
541 | #ifdef CONFIG_HAVE_DYN_ARRAY | ||
542 | unsigned long size, phys = 0; | ||
543 | struct dyn_array **daa; | ||
544 | |||
545 | for (daa = __dyn_array_start ; daa < __dyn_array_end; daa++) { | ||
546 | struct dyn_array *da = *daa; | ||
547 | |||
548 | size = da->size * (*da->nr); | ||
549 | print_fn_descriptor_symbol("dyna_array %s ", da->name); | ||
550 | printk(KERN_CONT "size:%#lx nr:%d align:%#lx", | ||
551 | da->size, *da->nr, da->align); | ||
552 | *da->name = __alloc_bootmem(size, da->align, phys); | ||
553 | phys = virt_to_phys(*da->name); | ||
554 | printk(KERN_CONT " ==> [%#lx - %#lx]\n", phys, phys + size); | ||
555 | |||
556 | if (da->init_work) | ||
557 | da->init_work(da); | ||
558 | } | ||
559 | #endif | ||
560 | } | ||
561 | |||
539 | asmlinkage void __init start_kernel(void) | 562 | asmlinkage void __init start_kernel(void) |
540 | { | 563 | { |
541 | char * command_line; | 564 | char * command_line; |
@@ -567,6 +590,7 @@ asmlinkage void __init start_kernel(void) | |||
567 | printk(KERN_NOTICE); | 590 | printk(KERN_NOTICE); |
568 | printk(linux_banner); | 591 | printk(linux_banner); |
569 | setup_arch(&command_line); | 592 | setup_arch(&command_line); |
593 | pre_alloc_dyn_array(); | ||
570 | mm_init_owner(&init_mm, &init_task); | 594 | mm_init_owner(&init_mm, &init_task); |
571 | setup_command_line(command_line); | 595 | setup_command_line(command_line); |
572 | unwind_setup(); | 596 | unwind_setup(); |