Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cfa024f4 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge master.kernel.org:/home/rmk/linux-2.6-arm

parents 3a714237 a054a811
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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
+31 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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>
@@ -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();
+100 −9
Original line number Diff line number Diff line
@@ -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
@@ -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.
@@ -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);
@@ -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
+37 −7
Original line number Diff line number Diff line
@@ -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