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; |
