diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/kernel/atags.c | 86 | ||||
-rw-r--r-- | arch/arm/kernel/atags.h | 5 | ||||
-rw-r--r-- | arch/arm/kernel/machine_kexec.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/relocate_kernel.S | 30 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 33 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 39 |
7 files changed, 133 insertions, 63 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index faa761921153..00d44c6fbfe9 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -20,6 +20,7 @@ obj-$(CONFIG_PCI) += bios32.o isa.o | |||
20 | obj-$(CONFIG_SMP) += smp.o | 20 | obj-$(CONFIG_SMP) += smp.o |
21 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 21 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
22 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o | 22 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o |
23 | obj-$(CONFIG_ATAGS_PROC) += atags.o | ||
23 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o | 24 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o |
24 | 25 | ||
25 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o | 26 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o |
diff --git a/arch/arm/kernel/atags.c b/arch/arm/kernel/atags.c new file mode 100644 index 000000000000..e2e934c38080 --- /dev/null +++ b/arch/arm/kernel/atags.c | |||
@@ -0,0 +1,86 @@ | |||
1 | #include <linux/slab.h> | ||
2 | #include <linux/kexec.h> | ||
3 | #include <linux/proc_fs.h> | ||
4 | #include <asm/setup.h> | ||
5 | #include <asm/types.h> | ||
6 | #include <asm/page.h> | ||
7 | |||
8 | struct buffer { | ||
9 | size_t size; | ||
10 | char *data; | ||
11 | }; | ||
12 | static struct buffer tags_buffer; | ||
13 | |||
14 | static int | ||
15 | read_buffer(char* page, char** start, off_t off, int count, | ||
16 | int* eof, void* data) | ||
17 | { | ||
18 | struct buffer *buffer = (struct buffer *)data; | ||
19 | |||
20 | if (off >= buffer->size) { | ||
21 | *eof = 1; | ||
22 | return 0; | ||
23 | } | ||
24 | |||
25 | count = min((int) (buffer->size - off), count); | ||
26 | |||
27 | memcpy(page, &buffer->data[off], count); | ||
28 | |||
29 | return count; | ||
30 | } | ||
31 | |||
32 | |||
33 | static int | ||
34 | create_proc_entries(void) | ||
35 | { | ||
36 | struct proc_dir_entry* tags_entry; | ||
37 | |||
38 | tags_entry = create_proc_read_entry("atags", 0400, &proc_root, read_buffer, &tags_buffer); | ||
39 | if (!tags_entry) | ||
40 | return -ENOMEM; | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | |||
46 | static char __initdata atags_copy_buf[KEXEC_BOOT_PARAMS_SIZE]; | ||
47 | static char __initdata *atags_copy; | ||
48 | |||
49 | void __init save_atags(const struct tag *tags) | ||
50 | { | ||
51 | atags_copy = atags_copy_buf; | ||
52 | memcpy(atags_copy, tags, KEXEC_BOOT_PARAMS_SIZE); | ||
53 | } | ||
54 | |||
55 | |||
56 | static int __init init_atags_procfs(void) | ||
57 | { | ||
58 | struct tag *tag; | ||
59 | int error; | ||
60 | |||
61 | if (!atags_copy) { | ||
62 | printk(KERN_WARNING "Exporting ATAGs: No saved tags found\n"); | ||
63 | return -EIO; | ||
64 | } | ||
65 | |||
66 | for (tag = (struct tag *) atags_copy; tag->hdr.size; tag = tag_next(tag)) | ||
67 | ; | ||
68 | |||
69 | tags_buffer.size = ((char *) tag - atags_copy) + sizeof(tag->hdr); | ||
70 | tags_buffer.data = kmalloc(tags_buffer.size, GFP_KERNEL); | ||
71 | if (tags_buffer.data == NULL) | ||
72 | return -ENOMEM; | ||
73 | memcpy(tags_buffer.data, atags_copy, tags_buffer.size); | ||
74 | |||
75 | error = create_proc_entries(); | ||
76 | if (error) { | ||
77 | printk(KERN_ERR "Exporting ATAGs: not enough memory\n"); | ||
78 | kfree(tags_buffer.data); | ||
79 | tags_buffer.size = 0; | ||
80 | tags_buffer.data = NULL; | ||
81 | } | ||
82 | |||
83 | return error; | ||
84 | } | ||
85 | |||
86 | arch_initcall(init_atags_procfs); | ||
diff --git a/arch/arm/kernel/atags.h b/arch/arm/kernel/atags.h new file mode 100644 index 000000000000..e5f028d214a1 --- /dev/null +++ b/arch/arm/kernel/atags.h | |||
@@ -0,0 +1,5 @@ | |||
1 | #ifdef CONFIG_ATAGS_PROC | ||
2 | extern void save_atags(struct tag *tags); | ||
3 | #else | ||
4 | static inline void save_atags(struct tag *tags) { } | ||
5 | #endif | ||
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index 863c66454f2b..db8f54a3451f 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c | |||
@@ -21,6 +21,7 @@ extern void setup_mm_for_reboot(char mode); | |||
21 | extern unsigned long kexec_start_address; | 21 | extern unsigned long kexec_start_address; |
22 | extern unsigned long kexec_indirection_page; | 22 | extern unsigned long kexec_indirection_page; |
23 | extern unsigned long kexec_mach_type; | 23 | extern unsigned long kexec_mach_type; |
24 | extern unsigned long kexec_boot_atags; | ||
24 | 25 | ||
25 | /* | 26 | /* |
26 | * Provide a dummy crash_notes definition while crash dump arrives to arm. | 27 | * Provide a dummy crash_notes definition while crash dump arrives to arm. |
@@ -62,6 +63,7 @@ void machine_kexec(struct kimage *image) | |||
62 | kexec_start_address = image->start; | 63 | kexec_start_address = image->start; |
63 | kexec_indirection_page = page_list; | 64 | kexec_indirection_page = page_list; |
64 | kexec_mach_type = machine_arch_type; | 65 | kexec_mach_type = machine_arch_type; |
66 | kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET; | ||
65 | 67 | ||
66 | /* copy our kernel relocation code to the control code page */ | 68 | /* copy our kernel relocation code to the control code page */ |
67 | memcpy(reboot_code_buffer, | 69 | memcpy(reboot_code_buffer, |
diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S index 062c111c572f..61930eb09029 100644 --- a/arch/arm/kernel/relocate_kernel.S +++ b/arch/arm/kernel/relocate_kernel.S | |||
@@ -7,23 +7,6 @@ | |||
7 | .globl relocate_new_kernel | 7 | .globl relocate_new_kernel |
8 | relocate_new_kernel: | 8 | relocate_new_kernel: |
9 | 9 | ||
10 | /* Move boot params back to where the kernel expects them */ | ||
11 | |||
12 | ldr r0,kexec_boot_params_address | ||
13 | teq r0,#0 | ||
14 | beq 8f | ||
15 | |||
16 | ldr r1,kexec_boot_params_copy | ||
17 | mov r6,#KEXEC_BOOT_PARAMS_SIZE/4 | ||
18 | 7: | ||
19 | ldr r5,[r1],#4 | ||
20 | str r5,[r0],#4 | ||
21 | subs r6,r6,#1 | ||
22 | bne 7b | ||
23 | |||
24 | 8: | ||
25 | /* Boot params moved, now go on with the kernel */ | ||
26 | |||
27 | ldr r0,kexec_indirection_page | 10 | ldr r0,kexec_indirection_page |
28 | ldr r1,kexec_start_address | 11 | ldr r1,kexec_start_address |
29 | 12 | ||
@@ -67,7 +50,7 @@ relocate_new_kernel: | |||
67 | mov lr,r1 | 50 | mov lr,r1 |
68 | mov r0,#0 | 51 | mov r0,#0 |
69 | ldr r1,kexec_mach_type | 52 | ldr r1,kexec_mach_type |
70 | ldr r2,kexec_boot_params_address | 53 | ldr r2,kexec_boot_atags |
71 | mov pc,lr | 54 | mov pc,lr |
72 | 55 | ||
73 | .globl kexec_start_address | 56 | .globl kexec_start_address |
@@ -82,14 +65,9 @@ kexec_indirection_page: | |||
82 | kexec_mach_type: | 65 | kexec_mach_type: |
83 | .long 0x0 | 66 | .long 0x0 |
84 | 67 | ||
85 | /* phy addr where new kernel will expect to find boot params */ | 68 | /* phy addr of the atags for the new kernel */ |
86 | .globl kexec_boot_params_address | 69 | .globl kexec_boot_atags |
87 | kexec_boot_params_address: | 70 | kexec_boot_atags: |
88 | .long 0x0 | ||
89 | |||
90 | /* phy addr where old kernel put a copy of orig boot params */ | ||
91 | .globl kexec_boot_params_copy | ||
92 | kexec_boot_params_copy: | ||
93 | .long 0x0 | 71 | .long 0x0 |
94 | 72 | ||
95 | relocate_new_kernel_end: | 73 | relocate_new_kernel_end: |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index bf56eb337df1..d3941a7b0455 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/smp.h> | 25 | #include <linux/smp.h> |
26 | #include <linux/fs.h> | 26 | #include <linux/fs.h> |
27 | #include <linux/kexec.h> | ||
28 | 27 | ||
29 | #include <asm/cpu.h> | 28 | #include <asm/cpu.h> |
30 | #include <asm/elf.h> | 29 | #include <asm/elf.h> |
@@ -39,6 +38,7 @@ | |||
39 | #include <asm/mach/time.h> | 38 | #include <asm/mach/time.h> |
40 | 39 | ||
41 | #include "compat.h" | 40 | #include "compat.h" |
41 | #include "atags.h" | ||
42 | 42 | ||
43 | #ifndef MEM_SIZE | 43 | #ifndef MEM_SIZE |
44 | #define MEM_SIZE (16*1024*1024) | 44 | #define MEM_SIZE (16*1024*1024) |
@@ -62,6 +62,7 @@ extern int root_mountflags; | |||
62 | extern void _stext, _text, _etext, __data_start, _edata, _end; | 62 | extern void _stext, _text, _etext, __data_start, _edata, _end; |
63 | 63 | ||
64 | unsigned int processor_id; | 64 | unsigned int processor_id; |
65 | EXPORT_SYMBOL(processor_id); | ||
65 | unsigned int __machine_arch_type; | 66 | unsigned int __machine_arch_type; |
66 | EXPORT_SYMBOL(__machine_arch_type); | 67 | EXPORT_SYMBOL(__machine_arch_type); |
67 | 68 | ||
@@ -784,23 +785,6 @@ static int __init customize_machine(void) | |||
784 | } | 785 | } |
785 | arch_initcall(customize_machine); | 786 | arch_initcall(customize_machine); |
786 | 787 | ||
787 | #ifdef CONFIG_KEXEC | ||
788 | |||
789 | /* Physical addr of where the boot params should be for this machine */ | ||
790 | extern unsigned long kexec_boot_params_address; | ||
791 | |||
792 | /* Physical addr of the buffer into which the boot params are copied */ | ||
793 | extern unsigned long kexec_boot_params_copy; | ||
794 | |||
795 | /* Pointer to the boot params buffer, for manipulation and display */ | ||
796 | unsigned long kexec_boot_params; | ||
797 | EXPORT_SYMBOL(kexec_boot_params); | ||
798 | |||
799 | /* The buffer itself - make sure it is sized correctly */ | ||
800 | static unsigned long kexec_boot_params_buf[(KEXEC_BOOT_PARAMS_SIZE + 3) / 4]; | ||
801 | |||
802 | #endif | ||
803 | |||
804 | void __init setup_arch(char **cmdline_p) | 788 | void __init setup_arch(char **cmdline_p) |
805 | { | 789 | { |
806 | struct tag *tags = (struct tag *)&init_tags; | 790 | struct tag *tags = (struct tag *)&init_tags; |
@@ -819,18 +803,6 @@ void __init setup_arch(char **cmdline_p) | |||
819 | else if (mdesc->boot_params) | 803 | else if (mdesc->boot_params) |
820 | tags = phys_to_virt(mdesc->boot_params); | 804 | tags = phys_to_virt(mdesc->boot_params); |
821 | 805 | ||
822 | #ifdef CONFIG_KEXEC | ||
823 | kexec_boot_params_copy = virt_to_phys(kexec_boot_params_buf); | ||
824 | kexec_boot_params = (unsigned long)kexec_boot_params_buf; | ||
825 | if (__atags_pointer) { | ||
826 | kexec_boot_params_address = __atags_pointer; | ||
827 | memcpy((void *)kexec_boot_params, tags, KEXEC_BOOT_PARAMS_SIZE); | ||
828 | } else if (mdesc->boot_params) { | ||
829 | kexec_boot_params_address = mdesc->boot_params; | ||
830 | memcpy((void *)kexec_boot_params, tags, KEXEC_BOOT_PARAMS_SIZE); | ||
831 | } | ||
832 | #endif | ||
833 | |||
834 | /* | 806 | /* |
835 | * If we have the old style parameters, convert them to | 807 | * If we have the old style parameters, convert them to |
836 | * a tag list. | 808 | * a tag list. |
@@ -846,6 +818,7 @@ void __init setup_arch(char **cmdline_p) | |||
846 | if (tags->hdr.tag == ATAG_CORE) { | 818 | if (tags->hdr.tag == ATAG_CORE) { |
847 | if (meminfo.nr_banks != 0) | 819 | if (meminfo.nr_banks != 0) |
848 | squash_mem_tags(tags); | 820 | squash_mem_tags(tags); |
821 | save_atags(tags); | ||
849 | parse_tags(tags); | 822 | parse_tags(tags); |
850 | } | 823 | } |
851 | 824 | ||
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index eafbb2b05eb8..e9dfbab46cb6 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
@@ -290,6 +290,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void) | |||
290 | local_irq_enable(); | 290 | local_irq_enable(); |
291 | local_fiq_enable(); | 291 | local_fiq_enable(); |
292 | 292 | ||
293 | /* | ||
294 | * Setup local timer for this CPU. | ||
295 | */ | ||
296 | local_timer_setup(cpu); | ||
297 | |||
293 | calibrate_delay(); | 298 | calibrate_delay(); |
294 | 299 | ||
295 | smp_store_cpu_info(cpu); | 300 | smp_store_cpu_info(cpu); |
@@ -300,11 +305,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void) | |||
300 | cpu_set(cpu, cpu_online_map); | 305 | cpu_set(cpu, cpu_online_map); |
301 | 306 | ||
302 | /* | 307 | /* |
303 | * Setup local timer for this CPU. | ||
304 | */ | ||
305 | local_timer_setup(cpu); | ||
306 | |||
307 | /* | ||
308 | * OK, it's off to the idle thread for us | 308 | * OK, it's off to the idle thread for us |
309 | */ | 309 | */ |
310 | cpu_idle(); | 310 | cpu_idle(); |
@@ -454,6 +454,27 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, | |||
454 | } | 454 | } |
455 | EXPORT_SYMBOL_GPL(smp_call_function); | 455 | EXPORT_SYMBOL_GPL(smp_call_function); |
456 | 456 | ||
457 | int smp_call_function_single(int cpu, void (*func)(void *info), void *info, | ||
458 | int retry, int wait) | ||
459 | { | ||
460 | /* prevent preemption and reschedule on another processor */ | ||
461 | int current_cpu = get_cpu(); | ||
462 | int ret = 0; | ||
463 | |||
464 | if (cpu == current_cpu) { | ||
465 | local_irq_disable(); | ||
466 | func(info); | ||
467 | local_irq_enable(); | ||
468 | } else | ||
469 | ret = smp_call_function_on_cpu(func, info, retry, wait, | ||
470 | cpumask_of_cpu(cpu)); | ||
471 | |||
472 | put_cpu(); | ||
473 | |||
474 | return ret; | ||
475 | } | ||
476 | EXPORT_SYMBOL_GPL(smp_call_function_single); | ||
477 | |||
457 | void show_ipi_list(struct seq_file *p) | 478 | void show_ipi_list(struct seq_file *p) |
458 | { | 479 | { |
459 | unsigned int cpu; | 480 | unsigned int cpu; |
@@ -481,8 +502,7 @@ void show_local_irqs(struct seq_file *p) | |||
481 | static void ipi_timer(void) | 502 | static void ipi_timer(void) |
482 | { | 503 | { |
483 | irq_enter(); | 504 | irq_enter(); |
484 | profile_tick(CPU_PROFILING); | 505 | local_timer_interrupt(); |
485 | update_process_times(user_mode(get_irq_regs())); | ||
486 | irq_exit(); | 506 | irq_exit(); |
487 | } | 507 | } |
488 | 508 | ||
@@ -621,6 +641,11 @@ void smp_send_timer(void) | |||
621 | send_ipi_message(mask, IPI_TIMER); | 641 | send_ipi_message(mask, IPI_TIMER); |
622 | } | 642 | } |
623 | 643 | ||
644 | void smp_timer_broadcast(cpumask_t mask) | ||
645 | { | ||
646 | send_ipi_message(mask, IPI_TIMER); | ||
647 | } | ||
648 | |||
624 | void smp_send_stop(void) | 649 | void smp_send_stop(void) |
625 | { | 650 | { |
626 | cpumask_t mask = cpu_online_map; | 651 | cpumask_t mask = cpu_online_map; |