mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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:
1 parent
b8bac01f1a
commit
5e40a1b435
5 files changed
+71
-10
No files matched your search
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||