Loading arch/arm/Kconfig +7 −0 Original line number Diff line number Diff line Loading @@ -349,6 +349,13 @@ config NR_CPUS depends on SMP default "4" config HOTPLUG_CPU bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" depends on SMP && HOTPLUG && EXPERIMENTAL help Say Y here to experiment with turning CPUs off and on. CPUs can be controlled through /sys/devices/system/cpu. config PREEMPT bool "Preemptible Kernel (EXPERIMENTAL)" depends on EXPERIMENTAL Loading arch/arm/kernel/irq.c +31 −0 Original line number Diff line number Diff line Loading @@ -1050,3 +1050,34 @@ static int __init noirqdebug_setup(char *str) } __setup("noirqdebug", noirqdebug_setup); #ifdef CONFIG_HOTPLUG_CPU /* * The CPU has been marked offline. Migrate IRQs off this CPU. If * the affinity settings do not allow other CPUs, force them onto any * available CPU. */ void migrate_irqs(void) { unsigned int i, cpu = smp_processor_id(); for (i = 0; i < NR_IRQS; i++) { struct irqdesc *desc = irq_desc + i; if (desc->cpu == cpu) { unsigned int newcpu = any_online_cpu(desc->affinity); if (newcpu == NR_CPUS) { if (printk_ratelimit()) printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n", i, cpu); cpus_setall(desc->affinity); newcpu = any_online_cpu(desc->affinity); } route_irq(desc, i, newcpu); } } } #endif /* CONFIG_HOTPLUG_CPU */ arch/arm/kernel/process.c +9 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <linux/interrupt.h> #include <linux/kallsyms.h> #include <linux/init.h> #include <linux/cpu.h> #include <asm/system.h> #include <asm/io.h> Loading Loading @@ -105,6 +106,14 @@ void cpu_idle(void) /* endless idle loop with no priority at all */ while (1) { void (*idle)(void) = pm_idle; #ifdef CONFIG_HOTPLUG_CPU if (cpu_is_offline(smp_processor_id())) { leds_event(led_idle_start); cpu_die(); } #endif if (!idle) idle = default_idle; preempt_disable(); Loading arch/arm/kernel/smp.c +100 −9 Original line number Diff line number Diff line Loading @@ -80,20 +80,24 @@ static DEFINE_SPINLOCK(smp_call_function_lock); int __cpuinit __cpu_up(unsigned int cpu) { struct task_struct *idle; struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu); struct task_struct *idle = ci->idle; pgd_t *pgd; pmd_t *pmd; int ret; /* * Spawn a new process manually. Grab a pointer to * its task struct so we can mess with it * Spawn a new process manually, if not already done. * Grab a pointer to its task struct so we can mess with it */ if (!idle) { idle = fork_idle(cpu); if (IS_ERR(idle)) { printk(KERN_ERR "CPU%u: fork() failed\n", cpu); return PTR_ERR(idle); } ci->idle = idle; } /* * Allocate initial page tables to allow the new CPU to Loading Loading @@ -155,6 +159,91 @@ int __cpuinit __cpu_up(unsigned int cpu) return ret; } #ifdef CONFIG_HOTPLUG_CPU /* * __cpu_disable runs on the processor to be shutdown. */ int __cpuexit __cpu_disable(void) { unsigned int cpu = smp_processor_id(); struct task_struct *p; int ret; ret = mach_cpu_disable(cpu); if (ret) return ret; /* * Take this CPU offline. Once we clear this, we can't return, * and we must not schedule until we're ready to give up the cpu. */ cpu_clear(cpu, cpu_online_map); /* * OK - migrate IRQs away from this CPU */ migrate_irqs(); /* * Flush user cache and TLB mappings, and then remove this CPU * from the vm mask set of all processes. */ flush_cache_all(); local_flush_tlb_all(); read_lock(&tasklist_lock); for_each_process(p) { if (p->mm) cpu_clear(cpu, p->mm->cpu_vm_mask); } read_unlock(&tasklist_lock); return 0; } /* * called on the thread which is asking for a CPU to be shutdown - * waits until shutdown has completed, or it is timed out. */ void __cpuexit __cpu_die(unsigned int cpu) { if (!platform_cpu_kill(cpu)) printk("CPU%u: unable to kill\n", cpu); } /* * Called from the idle thread for the CPU which has been shutdown. * * Note that we disable IRQs here, but do not re-enable them * before returning to the caller. This is also the behaviour * of the other hotplug-cpu capable cores, so presumably coming * out of idle fixes this. */ void __cpuexit cpu_die(void) { unsigned int cpu = smp_processor_id(); local_irq_disable(); idle_task_exit(); /* * actual CPU shutdown procedure is at least platform (if not * CPU) specific */ platform_cpu_die(cpu); /* * Do not return to the idle loop - jump back to the secondary * cpu initialisation. There's some initialisation which needs * to be repeated to undo the effects of taking the CPU offline. */ __asm__("mov sp, %0\n" " b secondary_start_kernel" : : "r" ((void *)current->thread_info + THREAD_SIZE - 8)); } #endif /* CONFIG_HOTPLUG_CPU */ /* * This is the secondary CPU boot entry. We're using this CPUs * idle thread stack, but a set of temporary page tables. Loading Loading @@ -236,6 +325,8 @@ void __init smp_prepare_boot_cpu(void) { unsigned int cpu = smp_processor_id(); per_cpu(cpu_data, cpu).idle = current; cpu_set(cpu, cpu_possible_map); cpu_set(cpu, cpu_present_map); cpu_set(cpu, cpu_online_map); Loading Loading @@ -309,8 +400,8 @@ int smp_call_function_on_cpu(void (*func)(void *info), void *info, int retry, printk(KERN_CRIT "CPU%u: smp_call_function timeout for %p(%p)\n" " callmap %lx pending %lx, %swait\n", smp_processor_id(), func, info, callmap, data.pending, wait ? "" : "no "); smp_processor_id(), func, info, *cpus_addr(callmap), *cpus_addr(data.pending), wait ? "" : "no "); /* * TRACE Loading arch/arm/mach-realview/realview_eb.c +37 −7 Original line number Diff line number Diff line Loading @@ -43,14 +43,44 @@ #include "clock.h" static struct map_desc realview_eb_io_desc[] __initdata = { { IO_ADDRESS(REALVIEW_SYS_BASE), REALVIEW_SYS_BASE, SZ_4K, MT_DEVICE }, { IO_ADDRESS(REALVIEW_GIC_CPU_BASE), REALVIEW_GIC_CPU_BASE, SZ_4K, MT_DEVICE }, { IO_ADDRESS(REALVIEW_GIC_DIST_BASE), REALVIEW_GIC_DIST_BASE, SZ_4K, MT_DEVICE }, { IO_ADDRESS(REALVIEW_SCTL_BASE), REALVIEW_SCTL_BASE, SZ_4K, MT_DEVICE }, { IO_ADDRESS(REALVIEW_TIMER0_1_BASE), REALVIEW_TIMER0_1_BASE, SZ_4K, MT_DEVICE }, { IO_ADDRESS(REALVIEW_TIMER2_3_BASE), REALVIEW_TIMER2_3_BASE, SZ_4K, MT_DEVICE }, { .virtual = IO_ADDRESS(REALVIEW_SYS_BASE), .pfn = __phys_to_pfn(REALVIEW_SYS_BASE), .length = SZ_4K, .type = MT_DEVICE, }, { .virtual = IO_ADDRESS(REALVIEW_GIC_CPU_BASE), .pfn = __phys_to_pfn(REALVIEW_GIC_CPU_BASE), .length = SZ_4K, .type = MT_DEVICE, }, { .virtual = IO_ADDRESS(REALVIEW_GIC_DIST_BASE), .pfn = __phys_to_pfn(REALVIEW_GIC_DIST_BASE), .length = SZ_4K, .type = MT_DEVICE, }, { .virtual = IO_ADDRESS(REALVIEW_SCTL_BASE), .pfn = __phys_to_pfn(REALVIEW_SCTL_BASE), .length = SZ_4K, .type = MT_DEVICE, }, { .virtual = IO_ADDRESS(REALVIEW_TIMER0_1_BASE), .pfn = __phys_to_pfn(REALVIEW_TIMER0_1_BASE), .length = SZ_4K, .type = MT_DEVICE, }, { .virtual = IO_ADDRESS(REALVIEW_TIMER2_3_BASE), .pfn = __phys_to_pfn(REALVIEW_TIMER2_3_BASE), .length = SZ_4K, .type = MT_DEVICE, }, #ifdef CONFIG_DEBUG_LL { IO_ADDRESS(REALVIEW_UART0_BASE), REALVIEW_UART0_BASE, SZ_4K, MT_DEVICE }, { .virtual = IO_ADDRESS(REALVIEW_UART0_BASE), .pfn = __phys_to_pfn(REALVIEW_UART0_BASE), .length = SZ_4K, .type = MT_DEVICE, } #endif }; Loading Loading
arch/arm/Kconfig +7 −0 Original line number Diff line number Diff line Loading @@ -349,6 +349,13 @@ config NR_CPUS depends on SMP default "4" config HOTPLUG_CPU bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" depends on SMP && HOTPLUG && EXPERIMENTAL help Say Y here to experiment with turning CPUs off and on. CPUs can be controlled through /sys/devices/system/cpu. config PREEMPT bool "Preemptible Kernel (EXPERIMENTAL)" depends on EXPERIMENTAL Loading
arch/arm/kernel/irq.c +31 −0 Original line number Diff line number Diff line Loading @@ -1050,3 +1050,34 @@ static int __init noirqdebug_setup(char *str) } __setup("noirqdebug", noirqdebug_setup); #ifdef CONFIG_HOTPLUG_CPU /* * The CPU has been marked offline. Migrate IRQs off this CPU. If * the affinity settings do not allow other CPUs, force them onto any * available CPU. */ void migrate_irqs(void) { unsigned int i, cpu = smp_processor_id(); for (i = 0; i < NR_IRQS; i++) { struct irqdesc *desc = irq_desc + i; if (desc->cpu == cpu) { unsigned int newcpu = any_online_cpu(desc->affinity); if (newcpu == NR_CPUS) { if (printk_ratelimit()) printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n", i, cpu); cpus_setall(desc->affinity); newcpu = any_online_cpu(desc->affinity); } route_irq(desc, i, newcpu); } } } #endif /* CONFIG_HOTPLUG_CPU */
arch/arm/kernel/process.c +9 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <linux/interrupt.h> #include <linux/kallsyms.h> #include <linux/init.h> #include <linux/cpu.h> #include <asm/system.h> #include <asm/io.h> Loading Loading @@ -105,6 +106,14 @@ void cpu_idle(void) /* endless idle loop with no priority at all */ while (1) { void (*idle)(void) = pm_idle; #ifdef CONFIG_HOTPLUG_CPU if (cpu_is_offline(smp_processor_id())) { leds_event(led_idle_start); cpu_die(); } #endif if (!idle) idle = default_idle; preempt_disable(); Loading
arch/arm/kernel/smp.c +100 −9 Original line number Diff line number Diff line Loading @@ -80,20 +80,24 @@ static DEFINE_SPINLOCK(smp_call_function_lock); int __cpuinit __cpu_up(unsigned int cpu) { struct task_struct *idle; struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu); struct task_struct *idle = ci->idle; pgd_t *pgd; pmd_t *pmd; int ret; /* * Spawn a new process manually. Grab a pointer to * its task struct so we can mess with it * Spawn a new process manually, if not already done. * Grab a pointer to its task struct so we can mess with it */ if (!idle) { idle = fork_idle(cpu); if (IS_ERR(idle)) { printk(KERN_ERR "CPU%u: fork() failed\n", cpu); return PTR_ERR(idle); } ci->idle = idle; } /* * Allocate initial page tables to allow the new CPU to Loading Loading @@ -155,6 +159,91 @@ int __cpuinit __cpu_up(unsigned int cpu) return ret; } #ifdef CONFIG_HOTPLUG_CPU /* * __cpu_disable runs on the processor to be shutdown. */ int __cpuexit __cpu_disable(void) { unsigned int cpu = smp_processor_id(); struct task_struct *p; int ret; ret = mach_cpu_disable(cpu); if (ret) return ret; /* * Take this CPU offline. Once we clear this, we can't return, * and we must not schedule until we're ready to give up the cpu. */ cpu_clear(cpu, cpu_online_map); /* * OK - migrate IRQs away from this CPU */ migrate_irqs(); /* * Flush user cache and TLB mappings, and then remove this CPU * from the vm mask set of all processes. */ flush_cache_all(); local_flush_tlb_all(); read_lock(&tasklist_lock); for_each_process(p) { if (p->mm) cpu_clear(cpu, p->mm->cpu_vm_mask); } read_unlock(&tasklist_lock); return 0; } /* * called on the thread which is asking for a CPU to be shutdown - * waits until shutdown has completed, or it is timed out. */ void __cpuexit __cpu_die(unsigned int cpu) { if (!platform_cpu_kill(cpu)) printk("CPU%u: unable to kill\n", cpu); } /* * Called from the idle thread for the CPU which has been shutdown. * * Note that we disable IRQs here, but do not re-enable them * before returning to the caller. This is also the behaviour * of the other hotplug-cpu capable cores, so presumably coming * out of idle fixes this. */ void __cpuexit cpu_die(void) { unsigned int cpu = smp_processor_id(); local_irq_disable(); idle_task_exit(); /* * actual CPU shutdown procedure is at least platform (if not * CPU) specific */ platform_cpu_die(cpu); /* * Do not return to the idle loop - jump back to the secondary * cpu initialisation. There's some initialisation which needs * to be repeated to undo the effects of taking the CPU offline. */ __asm__("mov sp, %0\n" " b secondary_start_kernel" : : "r" ((void *)current->thread_info + THREAD_SIZE - 8)); } #endif /* CONFIG_HOTPLUG_CPU */ /* * This is the secondary CPU boot entry. We're using this CPUs * idle thread stack, but a set of temporary page tables. Loading Loading @@ -236,6 +325,8 @@ void __init smp_prepare_boot_cpu(void) { unsigned int cpu = smp_processor_id(); per_cpu(cpu_data, cpu).idle = current; cpu_set(cpu, cpu_possible_map); cpu_set(cpu, cpu_present_map); cpu_set(cpu, cpu_online_map); Loading Loading @@ -309,8 +400,8 @@ int smp_call_function_on_cpu(void (*func)(void *info), void *info, int retry, printk(KERN_CRIT "CPU%u: smp_call_function timeout for %p(%p)\n" " callmap %lx pending %lx, %swait\n", smp_processor_id(), func, info, callmap, data.pending, wait ? "" : "no "); smp_processor_id(), func, info, *cpus_addr(callmap), *cpus_addr(data.pending), wait ? "" : "no "); /* * TRACE Loading
arch/arm/mach-realview/realview_eb.c +37 −7 Original line number Diff line number Diff line Loading @@ -43,14 +43,44 @@ #include "clock.h" static struct map_desc realview_eb_io_desc[] __initdata = { { IO_ADDRESS(REALVIEW_SYS_BASE), REALVIEW_SYS_BASE, SZ_4K, MT_DEVICE }, { IO_ADDRESS(REALVIEW_GIC_CPU_BASE), REALVIEW_GIC_CPU_BASE, SZ_4K, MT_DEVICE }, { IO_ADDRESS(REALVIEW_GIC_DIST_BASE), REALVIEW_GIC_DIST_BASE, SZ_4K, MT_DEVICE }, { IO_ADDRESS(REALVIEW_SCTL_BASE), REALVIEW_SCTL_BASE, SZ_4K, MT_DEVICE }, { IO_ADDRESS(REALVIEW_TIMER0_1_BASE), REALVIEW_TIMER0_1_BASE, SZ_4K, MT_DEVICE }, { IO_ADDRESS(REALVIEW_TIMER2_3_BASE), REALVIEW_TIMER2_3_BASE, SZ_4K, MT_DEVICE }, { .virtual = IO_ADDRESS(REALVIEW_SYS_BASE), .pfn = __phys_to_pfn(REALVIEW_SYS_BASE), .length = SZ_4K, .type = MT_DEVICE, }, { .virtual = IO_ADDRESS(REALVIEW_GIC_CPU_BASE), .pfn = __phys_to_pfn(REALVIEW_GIC_CPU_BASE), .length = SZ_4K, .type = MT_DEVICE, }, { .virtual = IO_ADDRESS(REALVIEW_GIC_DIST_BASE), .pfn = __phys_to_pfn(REALVIEW_GIC_DIST_BASE), .length = SZ_4K, .type = MT_DEVICE, }, { .virtual = IO_ADDRESS(REALVIEW_SCTL_BASE), .pfn = __phys_to_pfn(REALVIEW_SCTL_BASE), .length = SZ_4K, .type = MT_DEVICE, }, { .virtual = IO_ADDRESS(REALVIEW_TIMER0_1_BASE), .pfn = __phys_to_pfn(REALVIEW_TIMER0_1_BASE), .length = SZ_4K, .type = MT_DEVICE, }, { .virtual = IO_ADDRESS(REALVIEW_TIMER2_3_BASE), .pfn = __phys_to_pfn(REALVIEW_TIMER2_3_BASE), .length = SZ_4K, .type = MT_DEVICE, }, #ifdef CONFIG_DEBUG_LL { IO_ADDRESS(REALVIEW_UART0_BASE), REALVIEW_UART0_BASE, SZ_4K, MT_DEVICE }, { .virtual = IO_ADDRESS(REALVIEW_UART0_BASE), .pfn = __phys_to_pfn(REALVIEW_UART0_BASE), .length = SZ_4K, .type = MT_DEVICE, } #endif }; Loading