arm: SMP CPU shutdown

For completeness, also implelent the CPU shutdown path.

Signed-off-by: Tim Deegan <tim@xen.org>
Committed-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
Tim Deegan committed 2012-03-13 15:10:56 +00:00
1 parent b8bac01f1a
commit 5e40a1b435
5 files changed
+71 -10

No files matched your search

+4 -6
View File
@@ -31,12 +31,10 @@ void idle_loop(void)
{ {
for ( ; ; ) for ( ; ; )
{ {
/* TODO if ( cpu_is_offline(smp_processor_id()) )
if ( cpu_is_offline(smp_processor_id()) ) stop_cpu();
play_dead();
(*pm_idle)(); /* TODO: (*pm_idle)(); */
BUG();
*/
do_tasklet(); do_tasklet();
do_softirq(); do_softirq();
} }
+19
View File
@@ -239,6 +239,11 @@ static void __cpuinit gic_cpu_init(void)
GICC[GICC_CTLR] = GICC_CTL_ENABLE|GICC_CTL_EOI; /* Turn on delivery */ GICC[GICC_CTLR] = GICC_CTL_ENABLE|GICC_CTL_EOI; /* Turn on delivery */
} }
static void gic_cpu_disable(void)
{
GICC[GICC_CTLR] = 0;
}
static void __cpuinit gic_hyp_init(void) static void __cpuinit gic_hyp_init(void)
{ {
uint32_t vtr; uint32_t vtr;
@@ -250,6 +255,11 @@ static void __cpuinit gic_hyp_init(void)
GICH[GICH_MISR] = GICH_MISR_EOI; GICH[GICH_MISR] = GICH_MISR_EOI;
} }
static void __cpuinit gic_hyp_disable(void)
{
GICH[GICH_HCR] = 0;
}
/* Set up the GIC */ /* Set up the GIC */
int __init gic_init(void) int __init gic_init(void)
{ {
@@ -286,6 +296,15 @@ void __cpuinit gic_init_secondary_cpu(void)
spin_unlock(&gic.lock); spin_unlock(&gic.lock);
} }
/* Shut down the per-CPU GIC interface */
void gic_disable_cpu(void)
{
spin_lock(&gic.lock);
gic_cpu_disable();
gic_hyp_disable();
spin_unlock(&gic.lock);
}
void gic_route_irqs(void) void gic_route_irqs(void)
{ {
/* XXX should get these from DT */ /* XXX should get these from DT */
+2
View File
@@ -142,6 +142,8 @@ extern void gic_interrupt(struct cpu_user_regs *regs, int is_fiq);
extern int gic_init(void); extern int gic_init(void);
/* Bring up a secondary CPU's per-CPU GIC interface */ /* Bring up a secondary CPU's per-CPU GIC interface */
extern void gic_init_secondary_cpu(void); extern void gic_init_secondary_cpu(void);
/* Take down a CPU's per-CPU GIC interface */
extern void gic_disable_cpu(void);
/* setup the gic virtual interface for a guest */ /* setup the gic virtual interface for a guest */
extern void gicv_setup(struct domain *d); extern void gicv_setup(struct domain *d);
#endif #endif
+44 -4
View File
@@ -18,6 +18,7 @@
#include <xen/cpu.h> #include <xen/cpu.h>
#include <xen/cpumask.h> #include <xen/cpumask.h>
#include <xen/delay.h>
#include <xen/errno.h> #include <xen/errno.h>
#include <xen/init.h> #include <xen/init.h>
#include <xen/mm.h> #include <xen/mm.h>
@@ -57,6 +58,7 @@ smp_prepare_cpus (unsigned int max_cpus)
/* Shared state for coordinating CPU bringup */ /* Shared state for coordinating CPU bringup */
unsigned long smp_up_cpu = 0; unsigned long smp_up_cpu = 0;
static bool_t cpu_is_dead = 0;
/* Boot the current CPU */ /* Boot the current CPU */
void __cpuinit start_secondary(unsigned long boot_phys_offset, void __cpuinit start_secondary(unsigned long boot_phys_offset,
@@ -97,8 +99,35 @@ void __cpuinit start_secondary(unsigned long boot_phys_offset,
/* Shut down the current CPU */ /* Shut down the current CPU */
void __cpu_disable(void) void __cpu_disable(void)
{ {
/* TODO: take down timers, GIC, &c. */ unsigned int cpu = get_processor_id();
BUG();
local_irq_disable();
gic_disable_cpu();
/* Allow any queued timer interrupts to get serviced */
local_irq_enable();
mdelay(1);
local_irq_disable();
/* It's now safe to remove this processor from the online map */
cpumask_clear_cpu(cpu, &cpu_online_map);
if ( cpu_disable_scheduler(cpu) )
BUG();
mb();
/* Return to caller; eventually the IPI mechanism will unwind and the
* scheduler will drop to the idle loop, which will call stop_cpu(). */
}
void stop_cpu(void)
{
local_irq_disable();
cpu_is_dead = 1;
/* Make sure the write happens before we sleep forever */
dsb();
isb();
while ( 1 )
asm volatile("wfi");
} }
/* Bring up a remote CPU */ /* Bring up a remote CPU */
@@ -124,8 +153,19 @@ int __cpu_up(unsigned int cpu)
/* Wait for a remote CPU to die */ /* Wait for a remote CPU to die */
void __cpu_die(unsigned int cpu) void __cpu_die(unsigned int cpu)
{ {
/* TODO: interlock with __cpu_disable */ unsigned int i = 0;
BUG();
while ( !cpu_is_dead )
{
mdelay(100);
cpu_relax();
process_pending_softirqs();
if ( (++i % 10) == 0 )
printk(KERN_ERR "CPU %u still not dead...\n", cpu);
mb();
}
cpu_is_dead = 0;
mb();
} }
+2
View File
@@ -14,6 +14,8 @@ DECLARE_PER_CPU(cpumask_var_t, cpu_core_mask);
#define raw_smp_processor_id() (get_processor_id()) #define raw_smp_processor_id() (get_processor_id())
extern void stop_cpu(void);
#endif #endif
/* /*
* Local variables: * Local variables:
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.