Skip to content

Commit

Permalink
Merge master.kernel.org:/home/rmk/linux-2.6-arm
Browse files Browse the repository at this point in the history
  • Loading branch information
Linus Torvalds committed Nov 3, 2005
2 parents 3a71423 + a054a81 commit cfa024f
Show file tree
Hide file tree
Showing 13 changed files with 250 additions and 57 deletions.
7 changes: 7 additions & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
31 changes: 31 additions & 0 deletions arch/arm/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
9 changes: 9 additions & 0 deletions arch/arm/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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();
Expand Down
109 changes: 100 additions & 9 deletions arch/arm/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,23 @@ 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
*/
idle = fork_idle(cpu);
if (IS_ERR(idle)) {
printk(KERN_ERR "CPU%u: fork() failed\n", cpu);
return PTR_ERR(idle);
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;
}

/*
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
44 changes: 37 additions & 7 deletions arch/arm/mach-realview/realview_eb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down
9 changes: 8 additions & 1 deletion arch/arm/mm/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -486,10 +486,17 @@ static void __init devicemaps_init(struct machine_desc *mdesc)

/*
* Ask the machine support to map in the statically mapped devices.
* After this point, we can start to touch devices again.
*/
if (mdesc->map_io)
mdesc->map_io();

/*
* Finally flush the tlb again - this ensures that we're in a
* consistent state wrt the writebuffer if the writebuffer needs
* draining. After this point, we can start to touch devices
* again.
*/
local_flush_tlb_all();
}

/*
Expand Down
4 changes: 2 additions & 2 deletions drivers/video/amba-clcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -505,14 +505,14 @@ static int clcdfb_remove(struct amba_device *dev)
static struct amba_id clcdfb_id_table[] = {
{
.id = 0x00041110,
.mask = 0x000fffff,
.mask = 0x000ffffe,
},
{ 0, 0 },
};

static struct amba_driver clcd_driver = {
.drv = {
.name = "clcd-pl110",
.name = "clcd-pl11x",
},
.probe = clcdfb_probe,
.remove = clcdfb_remove,
Expand Down
Loading

0 comments on commit cfa024f

Please sign in to comment.