Skip to content

Commit

Permalink
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git…
Browse files Browse the repository at this point in the history
…/benh/powerpc

* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc:
  kdump: Allow shrinking of kdump region to be overridden
  powerpc/pmac/smp: Remove no-longer needed preempt workaround
  powerpc/smp: Increase vdso_data->processorCount, not just decrease it
  powerpc/smp: Create idle threads on demand and properly reset them
  powerpc/smp: Don't expose per-cpu "cpu_state" array
  powerpc/pmac/smp: Fix CPU hotplug crashes on some machines
  powerpc/smp: Add a smp_ops->bringup_up() done callback
  powerpc/pmac: Rename cpu_state in therm_pm72 to avoid collision
  powerpc/pmac/smp: Properly NAP offlined CPU on G5
  powerpc/pmac/smp: Remove HMT changes for PowerMac offline code
  powerpc/pmac/smp: Consolidate 32-bit and 64-bit PowerMac cpu_die in one file
  powerpc/pmac/smp: Fixup smp_core99_cpu_disable() and use it on 64-bit
  powerpc/pmac/smp: Rename fixup_irqs() to migrate_irqs() and use it on ppc32
  powerpc/pmac/smp: Fix 32-bit PowerMac cpu_die
  powerpc/smp: Remove unused smp_ops->cpu_enable()
  powerpc/smp: Remove unused generic_cpu_enable()
  powerpc/smp: Fix generic_mach_cpu_die()
  powerpc/smp: soft-replugged CPUs must go back to start_secondary
  powerpc: Make decrementer interrupt robust against offlined CPUs
  • Loading branch information
torvalds committed Apr 1, 2011
2 parents afdef69 + c0bb9e4 commit ccd00d1
Show file tree
Hide file tree
Showing 15 changed files with 272 additions and 223 deletions.
3 changes: 1 addition & 2 deletions arch/powerpc/include/asm/machdep.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ struct smp_ops_t {
int (*probe)(void);
void (*kick_cpu)(int nr);
void (*setup_cpu)(int nr);
void (*bringup_done)(void);
void (*take_timebase)(void);
void (*give_timebase)(void);
int (*cpu_enable)(unsigned int nr);
int (*cpu_disable)(void);
void (*cpu_die)(unsigned int nr);
int (*cpu_bootable)(unsigned int nr);
Expand Down Expand Up @@ -267,7 +267,6 @@ struct machdep_calls {

extern void e500_idle(void);
extern void power4_idle(void);
extern void power4_cpu_offline_powersave(void);
extern void ppc6xx_idle(void);
extern void book3e_idle(void);

Expand Down
5 changes: 3 additions & 2 deletions arch/powerpc/include/asm/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,16 @@ extern void cpu_die(void);

extern void smp_send_debugger_break(int cpu);
extern void smp_message_recv(int);
extern void start_secondary_resume(void);

DECLARE_PER_CPU(unsigned int, cpu_pvr);

#ifdef CONFIG_HOTPLUG_CPU
extern void fixup_irqs(const struct cpumask *map);
extern void migrate_irqs(void);
int generic_cpu_disable(void);
int generic_cpu_enable(unsigned int cpu);
void generic_cpu_die(unsigned int cpu);
void generic_mach_cpu_die(void);
void generic_set_cpu_dead(unsigned int cpu);
#endif

#ifdef CONFIG_PPC64
Expand Down
9 changes: 9 additions & 0 deletions arch/powerpc/kernel/head_32.S
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,15 @@ __secondary_start:
mtspr SPRN_SRR1,r4
SYNC
RFI

_GLOBAL(start_secondary_resume)
/* Reset stack */
rlwinm r1,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
li r3,0
std r3,0(r1) /* Zero the stack frame pointer */
bl start_secondary
b .
#endif /* CONFIG_SMP */

#ifdef CONFIG_KVM_BOOK3S_HANDLER
Expand Down
7 changes: 7 additions & 0 deletions arch/powerpc/kernel/head_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,13 @@ _GLOBAL(pmac_secondary_start)
add r13,r13,r4 /* for this processor. */
mtspr SPRN_SPRG_PACA,r13 /* Save vaddr of paca in an SPRG*/

/* Mark interrupts soft and hard disabled (they might be enabled
* in the PACA when doing hotplug)
*/
li r0,0
stb r0,PACASOFTIRQEN(r13)
stb r0,PACAHARDIRQEN(r13)

/* Create a temp kernel stack for use before relocation is on. */
ld r1,PACAEMERGSP(r13)
subi r1,r1,STACK_FRAME_OVERHEAD
Expand Down
21 changes: 0 additions & 21 deletions arch/powerpc/kernel/idle_power4.S
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,3 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
isync
b 1b

_GLOBAL(power4_cpu_offline_powersave)
/* Go to NAP now */
mfmsr r7
rldicl r0,r7,48,1
rotldi r0,r0,16
mtmsrd r0,1 /* hard-disable interrupts */
li r0,1
li r6,0
stb r0,PACAHARDIRQEN(r13) /* we'll hard-enable shortly */
stb r6,PACASOFTIRQEN(r13) /* soft-disable irqs */
BEGIN_FTR_SECTION
DSSALL
sync
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
ori r7,r7,MSR_EE
oris r7,r7,MSR_POW@h
sync
isync
mtmsrd r7
isync
blr
3 changes: 2 additions & 1 deletion arch/powerpc/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,13 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
}

#ifdef CONFIG_HOTPLUG_CPU
void fixup_irqs(const struct cpumask *map)
void migrate_irqs(void)
{
struct irq_desc *desc;
unsigned int irq;
static int warned;
cpumask_var_t mask;
const struct cpumask *map = cpu_online_mask;

alloc_cpumask_var(&mask, GFP_KERNEL);

Expand Down
153 changes: 97 additions & 56 deletions arch/powerpc/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,25 @@
#define DBG(fmt...)
#endif


/* Store all idle threads, this can be reused instead of creating
* a new thread. Also avoids complicated thread destroy functionality
* for idle threads.
*/
#ifdef CONFIG_HOTPLUG_CPU
/*
* Needed only for CONFIG_HOTPLUG_CPU because __cpuinitdata is
* removed after init for !CONFIG_HOTPLUG_CPU.
*/
static DEFINE_PER_CPU(struct task_struct *, idle_thread_array);
#define get_idle_for_cpu(x) (per_cpu(idle_thread_array, x))
#define set_idle_for_cpu(x, p) (per_cpu(idle_thread_array, x) = (p))
#else
static struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
#define get_idle_for_cpu(x) (idle_thread_array[(x)])
#define set_idle_for_cpu(x, p) (idle_thread_array[(x)] = (p))
#endif

struct thread_info *secondary_ti;

DEFINE_PER_CPU(cpumask_var_t, cpu_sibling_map);
Expand Down Expand Up @@ -238,23 +257,6 @@ static void __devinit smp_store_cpu_info(int id)
per_cpu(cpu_pvr, id) = mfspr(SPRN_PVR);
}

static void __init smp_create_idle(unsigned int cpu)
{
struct task_struct *p;

/* create a process for the processor */
p = fork_idle(cpu);
if (IS_ERR(p))
panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
#ifdef CONFIG_PPC64
paca[cpu].__current = p;
paca[cpu].kstack = (unsigned long) task_thread_info(p)
+ THREAD_SIZE - STACK_FRAME_OVERHEAD;
#endif
current_set[cpu] = task_thread_info(p);
task_thread_info(p)->cpu = cpu;
}

void __init smp_prepare_cpus(unsigned int max_cpus)
{
unsigned int cpu;
Expand Down Expand Up @@ -288,10 +290,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
max_cpus = NR_CPUS;
else
max_cpus = 1;

for_each_possible_cpu(cpu)
if (cpu != boot_cpuid)
smp_create_idle(cpu);
}

void __devinit smp_prepare_boot_cpu(void)
Expand All @@ -305,7 +303,7 @@ void __devinit smp_prepare_boot_cpu(void)

#ifdef CONFIG_HOTPLUG_CPU
/* State of each CPU during hotplug phases */
DEFINE_PER_CPU(int, cpu_state) = { 0 };
static DEFINE_PER_CPU(int, cpu_state) = { 0 };

int generic_cpu_disable(void)
{
Expand All @@ -317,30 +315,8 @@ int generic_cpu_disable(void)
set_cpu_online(cpu, false);
#ifdef CONFIG_PPC64
vdso_data->processorCount--;
fixup_irqs(cpu_online_mask);
#endif
return 0;
}

int generic_cpu_enable(unsigned int cpu)
{
/* Do the normal bootup if we haven't
* already bootstrapped. */
if (system_state != SYSTEM_RUNNING)
return -ENOSYS;

/* get the target out of it's holding state */
per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
smp_wmb();

while (!cpu_online(cpu))
cpu_relax();

#ifdef CONFIG_PPC64
fixup_irqs(cpu_online_mask);
/* counter the irq disable in fixup_irqs */
local_irq_enable();
#endif
migrate_irqs();
return 0;
}

Expand All @@ -362,37 +338,89 @@ void generic_mach_cpu_die(void)
unsigned int cpu;

local_irq_disable();
idle_task_exit();
cpu = smp_processor_id();
printk(KERN_DEBUG "CPU%d offline\n", cpu);
__get_cpu_var(cpu_state) = CPU_DEAD;
smp_wmb();
while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
cpu_relax();
set_cpu_online(cpu, true);
local_irq_enable();
}

void generic_set_cpu_dead(unsigned int cpu)
{
per_cpu(cpu_state, cpu) = CPU_DEAD;
}
#endif

static int __devinit cpu_enable(unsigned int cpu)
struct create_idle {
struct work_struct work;
struct task_struct *idle;
struct completion done;
int cpu;
};

static void __cpuinit do_fork_idle(struct work_struct *work)
{
if (smp_ops && smp_ops->cpu_enable)
return smp_ops->cpu_enable(cpu);
struct create_idle *c_idle =
container_of(work, struct create_idle, work);

c_idle->idle = fork_idle(c_idle->cpu);
complete(&c_idle->done);
}

static int __cpuinit create_idle(unsigned int cpu)
{
struct thread_info *ti;
struct create_idle c_idle = {
.cpu = cpu,
.done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
};
INIT_WORK_ONSTACK(&c_idle.work, do_fork_idle);

c_idle.idle = get_idle_for_cpu(cpu);

/* We can't use kernel_thread since we must avoid to
* reschedule the child. We use a workqueue because
* we want to fork from a kernel thread, not whatever
* userspace process happens to be trying to online us.
*/
if (!c_idle.idle) {
schedule_work(&c_idle.work);
wait_for_completion(&c_idle.done);
} else
init_idle(c_idle.idle, cpu);
if (IS_ERR(c_idle.idle)) {
pr_err("Failed fork for CPU %u: %li", cpu, PTR_ERR(c_idle.idle));
return PTR_ERR(c_idle.idle);
}
ti = task_thread_info(c_idle.idle);

#ifdef CONFIG_PPC64
paca[cpu].__current = c_idle.idle;
paca[cpu].kstack = (unsigned long)ti + THREAD_SIZE - STACK_FRAME_OVERHEAD;
#endif
ti->cpu = cpu;
current_set[cpu] = ti;

return -ENOSYS;
return 0;
}

int __cpuinit __cpu_up(unsigned int cpu)
{
int c;
int rc, c;

secondary_ti = current_set[cpu];
if (!cpu_enable(cpu))
return 0;

if (smp_ops == NULL ||
(smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu)))
return -EINVAL;

/* Make sure we have an idle thread */
rc = create_idle(cpu);
if (rc)
return rc;

/* Make sure callin-map entry is 0 (can be leftover a CPU
* hotplug
*/
Expand Down Expand Up @@ -502,7 +530,7 @@ static struct device_node *cpu_to_l2cache(int cpu)
}

/* Activate a secondary processor. */
int __devinit start_secondary(void *unused)
void __devinit start_secondary(void *unused)
{
unsigned int cpu = smp_processor_id();
struct device_node *l2_cache;
Expand All @@ -523,6 +551,10 @@ int __devinit start_secondary(void *unused)

secondary_cpu_time_init();

#ifdef CONFIG_PPC64
if (system_state == SYSTEM_RUNNING)
vdso_data->processorCount++;
#endif
ipi_call_lock();
notify_cpu_starting(cpu);
set_cpu_online(cpu, true);
Expand Down Expand Up @@ -558,7 +590,8 @@ int __devinit start_secondary(void *unused)
local_irq_enable();

cpu_idle();
return 0;

BUG();
}

int setup_profiling_timer(unsigned int multiplier)
Expand All @@ -585,7 +618,11 @@ void __init smp_cpus_done(unsigned int max_cpus)

free_cpumask_var(old_mask);

if (smp_ops && smp_ops->bringup_done)
smp_ops->bringup_done();

dump_numa_cpu_topology();

}

int arch_sd_sibling_asym_packing(void)
Expand Down Expand Up @@ -660,5 +697,9 @@ void cpu_die(void)
{
if (ppc_md.cpu_die)
ppc_md.cpu_die();

/* If we return, we re-enter start_secondary */
start_secondary_resume();
}

#endif
15 changes: 11 additions & 4 deletions arch/powerpc/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -577,14 +577,21 @@ void timer_interrupt(struct pt_regs * regs)
struct clock_event_device *evt = &decrementer->event;
u64 now;

/* Ensure a positive value is written to the decrementer, or else
* some CPUs will continue to take decrementer exceptions.
*/
set_dec(DECREMENTER_MAX);

/* Some implementations of hotplug will get timer interrupts while
* offline, just ignore these
*/
if (!cpu_online(smp_processor_id()))
return;

trace_timer_interrupt_entry(regs);

__get_cpu_var(irq_stat).timer_irqs++;

/* Ensure a positive value is written to the decrementer, or else
* some CPUs will continuue to take decrementer exceptions */
set_dec(DECREMENTER_MAX);

#if defined(CONFIG_PPC32) && defined(CONFIG_PMAC)
if (atomic_read(&ppc_n_lost_interrupts) != 0)
do_IRQ(regs);
Expand Down
1 change: 0 additions & 1 deletion arch/powerpc/platforms/powermac/pmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ extern void pmac_setup_pci_dma(void);
extern void pmac_check_ht_link(void);

extern void pmac_setup_smp(void);
extern void pmac32_cpu_die(void);
extern void low_cpu_die(void) __attribute__((noreturn));

extern int pmac_nvram_init(void);
Expand Down
Loading

0 comments on commit ccd00d1

Please sign in to comment.