public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/7] x86/paravirt:  Add hooks for CPU hotplugging
@ 2008-08-21 18:04 Alex Nixon
  2008-08-21 18:04 ` [PATCH 2/7] x86/paravirt: Add paravirt hook for wbinvd_halt Alex Nixon
  2008-08-21 18:19 ` [PATCH 1/7] x86/paravirt: Add hooks for CPU hotplugging Jeremy Fitzhardinge
  0 siblings, 2 replies; 10+ messages in thread
From: Alex Nixon @ 2008-08-21 18:04 UTC (permalink / raw)
  To: Linux Kernel Mailing List; +Cc: Alex Nixon, Jeremy Fitzhardinge, Ingo Molnar

Signed-off-by: Alex Nixon <alex.nixon@citrix.com>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Ingo Molnar <mingo@elte.hu>
---
 arch/x86/kernel/paravirt.c   |    8 ++++++++
 arch/x86/kernel/process_32.c |   10 ++++++++--
 arch/x86/kernel/process_64.c |    9 +++++++--
 arch/x86/kernel/smpboot.c    |    8 ++++----
 include/asm-x86/paravirt.h   |   27 +++++++++++++++++++++++++++
 include/asm-x86/smp.h        |   13 +++++++++++--
 6 files changed, 65 insertions(+), 10 deletions(-)

diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 7cd2747..8ffe4d1 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -125,6 +125,7 @@ static void *get_call_destination(u8 type)
 		.pv_apic_ops = pv_apic_ops,
 		.pv_mmu_ops = pv_mmu_ops,
 		.pv_lock_ops = pv_lock_ops,
+		.pv_hotplug_ops = pv_hotplug_ops,
 	};
 	return *((void **)&tmpl + type);
 }
@@ -455,9 +456,16 @@ struct pv_mmu_ops pv_mmu_ops = {
 	.set_fixmap = native_set_fixmap,
 };
 
+struct pv_hotplug_ops pv_hotplug_ops = {
+	.cpu_die = native_cpu_die,
+	.cpu_disable = native_cpu_disable,
+	.play_dead = native_play_dead,
+};
+
 EXPORT_SYMBOL_GPL(pv_time_ops);
 EXPORT_SYMBOL    (pv_cpu_ops);
 EXPORT_SYMBOL    (pv_mmu_ops);
 EXPORT_SYMBOL_GPL(pv_apic_ops);
 EXPORT_SYMBOL_GPL(pv_info);
 EXPORT_SYMBOL    (pv_irq_ops);
+EXPORT_SYMBOL    (pv_hotplug_ops);
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 593b73e..53887cd 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -77,6 +77,12 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
 #ifdef CONFIG_HOTPLUG_CPU
 #include <asm/nmi.h>
 
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#else
+#define play_dead native_play_dead
+#endif
+
 static void cpu_exit_clear(void)
 {
 	int cpu = raw_smp_processor_id();
@@ -93,7 +99,7 @@ static void cpu_exit_clear(void)
 }
 
 /* We don't actually take CPU down, just spin without interrupts. */
-static inline void play_dead(void)
+void native_play_dead(void)
 {
 	/* This must be done before dead CPU ack */
 	cpu_exit_clear();
@@ -109,7 +115,7 @@ static inline void play_dead(void)
 	wbinvd_halt();
 }
 #else
-static inline void play_dead(void)
+void play_dead(void)
 {
 	BUG();
 }
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 8248dc0..7512044 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -86,13 +86,18 @@ void exit_idle(void)
 		return;
 	__exit_idle();
 }
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#else
+#define play_dead native_play_dead
+#endif
 
 #ifdef CONFIG_HOTPLUG_CPU
 DECLARE_PER_CPU(int, cpu_state);
 
 #include <linux/nmi.h>
 /* We halt the CPU with physical CPU hotplug */
-static inline void play_dead(void)
+void native_play_dead(void)
 {
 	idle_task_exit();
 	mb();
@@ -104,7 +109,7 @@ static inline void play_dead(void)
 	wbinvd_halt();
 }
 #else
-static inline void play_dead(void)
+void native_play_dead(void)
 {
 	BUG();
 }
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index eea2fd6..2a555a1 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1340,7 +1340,7 @@ static void __ref remove_cpu_from_maps(int cpu)
 	numa_remove_cpu(cpu);
 }
 
-int __cpu_disable(void)
+int native_cpu_disable(void)
 {
 	int cpu = smp_processor_id();
 
@@ -1379,7 +1379,7 @@ int __cpu_disable(void)
 	return 0;
 }
 
-void __cpu_die(unsigned int cpu)
+void native_cpu_die(unsigned int cpu)
 {
 	/* We don't do anything here: idle task is faking death itself. */
 	unsigned int i;
@@ -1397,12 +1397,12 @@ void __cpu_die(unsigned int cpu)
 	printk(KERN_ERR "CPU %u didn't die...\n", cpu);
 }
 #else /* ... !CONFIG_HOTPLUG_CPU */
-int __cpu_disable(void)
+int native_cpu_disable(void)
 {
 	return -ENOSYS;
 }
 
-void __cpu_die(unsigned int cpu)
+void native_cpu_die(unsigned int cpu)
 {
 	/* We said "no" in __cpu_disable */
 	BUG();
diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h
index eca8c4f..fd922c3 100644
--- a/include/asm-x86/paravirt.h
+++ b/include/asm-x86/paravirt.h
@@ -332,6 +332,12 @@ struct pv_lock_ops {
 	void (*spin_unlock)(struct raw_spinlock *lock);
 };
 
+struct pv_hotplug_ops {
+	void (*play_dead)(void);
+	int (*cpu_disable)(void);
+	void (*cpu_die)(unsigned int);
+};
+
 /* This contains all the paravirt structures: we get a convenient
  * number for each function using the offset which we use to indicate
  * what to patch. */
@@ -343,6 +349,7 @@ struct paravirt_patch_template {
 	struct pv_apic_ops pv_apic_ops;
 	struct pv_mmu_ops pv_mmu_ops;
 	struct pv_lock_ops pv_lock_ops;
+	struct pv_hotplug_ops pv_hotplug_ops;
 };
 
 extern struct pv_info pv_info;
@@ -353,6 +360,7 @@ extern struct pv_irq_ops pv_irq_ops;
 extern struct pv_apic_ops pv_apic_ops;
 extern struct pv_mmu_ops pv_mmu_ops;
 extern struct pv_lock_ops pv_lock_ops;
+extern struct pv_hotplug_ops pv_hotplug_ops;
 
 #define PARAVIRT_PATCH(x)					\
 	(offsetof(struct paravirt_patch_template, x) / sizeof(void *))
@@ -1408,6 +1416,25 @@ static __always_inline void __raw_spin_unlock(struct raw_spinlock *lock)
 
 #endif
 
+#ifdef CONFIG_HOTPLUG_CPU
+
+static inline int __cpu_disable(void)
+{
+	return PVOP_CALL0(int, pv_hotplug_ops.cpu_disable);
+}
+
+static inline void __cpu_die(unsigned int cpu)
+{
+	PVOP_VCALL1(pv_hotplug_ops.cpu_die, cpu);
+}
+
+static inline void play_dead(void)
+{
+	PVOP_VCALL0(pv_hotplug_ops.play_dead);
+}
+
+#endif
+
 /* These all sit in the .parainstructions section to tell us what to patch. */
 struct paravirt_patch_site {
 	u8 *instr; 		/* original instructions */
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index 29324c1..f7d153f 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -113,11 +113,20 @@ void native_smp_prepare_boot_cpu(void);
 void native_smp_prepare_cpus(unsigned int max_cpus);
 void native_smp_cpus_done(unsigned int max_cpus);
 int native_cpu_up(unsigned int cpunum);
+int native_cpu_disable(void);
+void native_cpu_die(unsigned int cpu);
+void native_play_dead(void);
+
 void native_send_call_func_ipi(cpumask_t mask);
 void native_send_call_func_single_ipi(int cpu);
 
-extern int __cpu_disable(void);
-extern void __cpu_die(unsigned int cpu);
+
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#else
+#define __cpu_disable	native_cpu_disable
+#define __cpu_die	native_cpu_die
+#endif
 
 void smp_store_cpu_info(int id);
 #define cpu_physical_id(cpu)	per_cpu(x86_cpu_to_apicid, cpu)
-- 
1.5.4.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/7] x86/paravirt:  Add paravirt hook for wbinvd_halt
  2008-08-21 18:04 [PATCH 1/7] x86/paravirt: Add hooks for CPU hotplugging Alex Nixon
@ 2008-08-21 18:04 ` Alex Nixon
  2008-08-21 18:04   ` [PATCH 3/7] Xen: Add Xen implementation of wbinvd_halt Alex Nixon
  2008-08-21 18:16   ` [PATCH 2/7] x86/paravirt: Add paravirt hook for wbinvd_halt Jeremy Fitzhardinge
  2008-08-21 18:19 ` [PATCH 1/7] x86/paravirt: Add hooks for CPU hotplugging Jeremy Fitzhardinge
  1 sibling, 2 replies; 10+ messages in thread
From: Alex Nixon @ 2008-08-21 18:04 UTC (permalink / raw)
  To: Linux Kernel Mailing List; +Cc: Alex Nixon, Jeremy Fitzhardinge, Ingo Molnar

The native case of wb_invd_halt uses inline asm to ensure the compiler doesn't reorder the sequence of instructions, which has the side-effect of skirting around the paravirt hooks for those instructions.  Thus, create a new hook for this case.

Signed-off-by: Alex Nixon <alex.nixon@citrix.com>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Ingo Molnar <mingo@elte.hu>
---
 arch/x86/kernel/paravirt.c  |    1 +
 include/asm-x86/paravirt.h  |    6 ++++++
 include/asm-x86/processor.h |    3 ++-
 3 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 8ffe4d1..66d6d0d 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -299,6 +299,7 @@ struct pv_irq_ops pv_irq_ops = {
 	.restore_fl = native_restore_fl,
 	.irq_disable = native_irq_disable,
 	.irq_enable = native_irq_enable,
+	.wbinvd_halt = native_wbinvd_halt,
 	.safe_halt = native_safe_halt,
 	.halt = native_halt,
 #ifdef CONFIG_X86_64
diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h
index fd922c3..5360f3f 100644
--- a/include/asm-x86/paravirt.h
+++ b/include/asm-x86/paravirt.h
@@ -194,6 +194,7 @@ struct pv_irq_ops {
 	void (*restore_fl)(unsigned long);
 	void (*irq_disable)(void);
 	void (*irq_enable)(void);
+	void (*wbinvd_halt)(void);
 	void (*safe_halt)(void);
 	void (*halt)(void);
 
@@ -716,6 +717,11 @@ static inline void raw_safe_halt(void)
 	PVOP_VCALL0(pv_irq_ops.safe_halt);
 }
 
+static inline void wbinvd_halt(void)
+{
+	PVOP_VCALL0(pv_irq_ops.wbinvd_halt);
+}
+
 static inline void halt(void)
 {
 	PVOP_VCALL0(pv_irq_ops.safe_halt);
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h
index bcfc727..75db315 100644
--- a/include/asm-x86/processor.h
+++ b/include/asm-x86/processor.h
@@ -558,6 +558,7 @@ static inline void load_sp0(struct tss_struct *tss,
 	native_load_sp0(tss, thread);
 }
 
+#define wbinvd_halt native_wbinvd_halt
 #define set_iopl_mask native_set_iopl_mask
 #endif /* CONFIG_PARAVIRT */
 
@@ -733,7 +734,7 @@ extern unsigned long		idle_nomwait;
  *
  * Systems without cache can just go into halt.
  */
-static inline void wbinvd_halt(void)
+static inline void native_wbinvd_halt(void)
 {
 	mb();
 	/* check for clflush to determine if wbinvd is legal */
-- 
1.5.4.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/7] Xen:  Add Xen implementation of wbinvd_halt
  2008-08-21 18:04 ` [PATCH 2/7] x86/paravirt: Add paravirt hook for wbinvd_halt Alex Nixon
@ 2008-08-21 18:04   ` Alex Nixon
  2008-08-21 18:04     ` [PATCH 4/7] x86_32: Clean up play_dead Alex Nixon
  2008-08-21 18:16   ` [PATCH 2/7] x86/paravirt: Add paravirt hook for wbinvd_halt Jeremy Fitzhardinge
  1 sibling, 1 reply; 10+ messages in thread
From: Alex Nixon @ 2008-08-21 18:04 UTC (permalink / raw)
  To: Linux Kernel Mailing List; +Cc: Alex Nixon, Jeremy Fitzhardinge, Ingo Molnar

Signed-off-by: Alex Nixon <alex.nixon@citrix.com>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Ingo Molnar <mingo@elte.hu>
---
 arch/x86/xen/irq.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
index bb04260..4e3f7f7 100644
--- a/arch/x86/xen/irq.c
+++ b/arch/x86/xen/irq.c
@@ -122,12 +122,19 @@ static void xen_halt(void)
 		xen_safe_halt();
 }
 
+static void xen_wbinvd_halt(void)
+{
+	native_wbinvd();
+	xen_halt();
+}
+
 static const struct pv_irq_ops xen_irq_ops __initdata = {
 	.init_IRQ = __xen_init_IRQ,
 	.save_fl = xen_save_fl,
 	.restore_fl = xen_restore_fl,
 	.irq_disable = xen_irq_disable,
 	.irq_enable = xen_irq_enable,
+	.wb_invd_halt = xen_wbinvd_halt,
 	.safe_halt = xen_safe_halt,
 	.halt = xen_halt,
 #ifdef CONFIG_X86_64
-- 
1.5.4.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/7] x86_32:  Clean up play_dead.
  2008-08-21 18:04   ` [PATCH 3/7] Xen: Add Xen implementation of wbinvd_halt Alex Nixon
@ 2008-08-21 18:04     ` Alex Nixon
  2008-08-21 18:04       ` [PATCH 5/7] x86: Unify x86_32 and x86_64 play_dead into one function Alex Nixon
  0 siblings, 1 reply; 10+ messages in thread
From: Alex Nixon @ 2008-08-21 18:04 UTC (permalink / raw)
  To: Linux Kernel Mailing List; +Cc: Alex Nixon, Jeremy Fitzhardinge, Ingo Molnar

The removal of the CPU from the various maps was redundant as it already happened in cpu_disable.

After cleaning this up, cpu_uninit only resets the tlb state, so rename it and create a noop version for the X86_64 case (so the two play_deads can be unified later).

Signed-off-by: Alex Nixon <alex.nixon@citrix.com>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Ingo Molnar <mingo@elte.hu>
---
 arch/x86/kernel/cpu/common.c |    6 +-----
 arch/x86/kernel/process_32.c |   17 ++++-------------
 include/asm-x86/smp.h        |    7 ++++++-
 3 files changed, 11 insertions(+), 19 deletions(-)

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index d3bc82f..531e054 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -755,14 +755,10 @@ void __cpuinit cpu_init(void)
 	xsave_init();
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-void __cpuinit cpu_uninit(void)
+void reset_lazy_tlbstate(void)
 {
 	int cpu = raw_smp_processor_id();
-	cpu_clear(cpu, cpu_initialized);
 
-	/* lazy TLB state */
 	per_cpu(cpu_tlbstate, cpu).state = 0;
 	per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
 }
-#endif
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 53887cd..2db1746 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -83,26 +83,17 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
 #define play_dead native_play_dead
 #endif
 
-static void cpu_exit_clear(void)
+/* We don't actually take CPU down, just spin without interrupts. */
+void native_play_dead(void)
 {
 	int cpu = raw_smp_processor_id();
 
 	idle_task_exit();
 
-	cpu_uninit();
-	irq_ctx_exit(cpu);
+	reset_lazy_tlbstate();
 
-	cpu_clear(cpu, cpu_callout_map);
-	cpu_clear(cpu, cpu_callin_map);
-
-	numa_remove_cpu(cpu);
-}
+	irq_ctx_exit(cpu);
 
-/* We don't actually take CPU down, just spin without interrupts. */
-void native_play_dead(void)
-{
-	/* This must be done before dead CPU ack */
-	cpu_exit_clear();
 	mb();
 	/* Ack it */
 	__get_cpu_var(cpu_state) = CPU_DEAD;
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index f7d153f..2b97b4c 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -215,7 +215,12 @@ static inline int hard_smp_processor_id(void)
 #endif /* CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_HOTPLUG_CPU
-extern void cpu_uninit(void);
+#ifdef CONFIG_X86_32
+extern void reset_lazy_tlbstate(void);
+#else
+static inline void reset_lazy_tlbstate(void)
+{ }
+#endif /* CONFIG_X86_32 */
 #endif
 
 #endif /* __ASSEMBLY__ */
-- 
1.5.4.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/7] x86:  Unify x86_32 and x86_64 play_dead into one function
  2008-08-21 18:04     ` [PATCH 4/7] x86_32: Clean up play_dead Alex Nixon
@ 2008-08-21 18:04       ` Alex Nixon
  2008-08-21 18:04         ` [PATCH 6/7] x86: Separate generic cpu disabling code from APIC writes in cpu_disable Alex Nixon
  0 siblings, 1 reply; 10+ messages in thread
From: Alex Nixon @ 2008-08-21 18:04 UTC (permalink / raw)
  To: Linux Kernel Mailing List; +Cc: Alex Nixon, Jeremy Fitzhardinge, Ingo Molnar

Add the new play_dead into smpboot.c, as it fits more cleanly in there alongside other CONFIG_HOTPLUG functions.

Signed-off-by: Alex Nixon <alex.nixon@citrix.com>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Ingo Molnar <mingo@elte.hu>
---
 arch/x86/kernel/process_32.c |   38 --------------------------------------
 arch/x86/kernel/process_64.c |   28 ----------------------------
 arch/x86/kernel/smpboot.c    |   25 +++++++++++++++++++++++++
 include/asm-x86/smp.h        |    1 +
 4 files changed, 26 insertions(+), 66 deletions(-)

diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 2db1746..aff137c 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -74,44 +74,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
 	return ((unsigned long *)tsk->thread.sp)[3];
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-#include <asm/nmi.h>
-
-#ifdef CONFIG_PARAVIRT
-#include <asm/paravirt.h>
-#else
-#define play_dead native_play_dead
-#endif
-
-/* We don't actually take CPU down, just spin without interrupts. */
-void native_play_dead(void)
-{
-	int cpu = raw_smp_processor_id();
-
-	idle_task_exit();
-
-	reset_lazy_tlbstate();
-
-	irq_ctx_exit(cpu);
-
-	mb();
-	/* Ack it */
-	__get_cpu_var(cpu_state) = CPU_DEAD;
-
-	/*
-	 * With physical CPU hotplug, we should halt the cpu
-	 */
-	local_irq_disable();
-	/* mask all interrupts, flush any and all caches, and halt */
-	wbinvd_halt();
-}
-#else
-void play_dead(void)
-{
-	BUG();
-}
-#endif /* CONFIG_HOTPLUG_CPU */
-
 /*
  * The idle thread. There's no useful work to be
  * done, so just try to conserve power and have a
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 7512044..b2bab8e 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -86,34 +86,6 @@ void exit_idle(void)
 		return;
 	__exit_idle();
 }
-#ifdef CONFIG_PARAVIRT
-#include <asm/paravirt.h>
-#else
-#define play_dead native_play_dead
-#endif
-
-#ifdef CONFIG_HOTPLUG_CPU
-DECLARE_PER_CPU(int, cpu_state);
-
-#include <linux/nmi.h>
-/* We halt the CPU with physical CPU hotplug */
-void native_play_dead(void)
-{
-	idle_task_exit();
-	mb();
-	/* Ack it */
-	__get_cpu_var(cpu_state) = CPU_DEAD;
-
-	local_irq_disable();
-	/* mask all interrupts, flush any and all caches, and halt */
-	wbinvd_halt();
-}
-#else
-void native_play_dead(void)
-{
-	BUG();
-}
-#endif /* CONFIG_HOTPLUG_CPU */
 
 /*
  * The idle thread. There's no useful work to be
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 2a555a1..83e9591 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1396,6 +1396,25 @@ void native_cpu_die(unsigned int cpu)
 	}
 	printk(KERN_ERR "CPU %u didn't die...\n", cpu);
 }
+
+void native_play_dead(void)
+{
+	idle_task_exit();
+	reset_lazy_tlbstate();
+	irq_ctx_exit(raw_smp_processor_id());
+
+	mb();
+	/* Ack it */
+	__get_cpu_var(cpu_state) = CPU_DEAD;
+
+	/*
+	 * With physical CPU hotplug, we should halt the cpu
+	 */
+	local_irq_disable();
+	/* mask all interrupts, flush any and all caches, and halt */
+	wbinvd_halt();
+}
+
 #else /* ... !CONFIG_HOTPLUG_CPU */
 int native_cpu_disable(void)
 {
@@ -1407,4 +1426,10 @@ void native_cpu_die(unsigned int cpu)
 	/* We said "no" in __cpu_disable */
 	BUG();
 }
+
+void native_play_dead(void)
+{
+	BUG();
+}
+
 #endif
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index 2b97b4c..fd2a070 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -126,6 +126,7 @@ void native_send_call_func_single_ipi(int cpu);
 #else
 #define __cpu_disable	native_cpu_disable
 #define __cpu_die	native_cpu_die
+#define play_dead	native_play_dead
 #endif
 
 void smp_store_cpu_info(int id);
-- 
1.5.4.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/7] x86:  Separate generic cpu disabling code from APIC writes in cpu_disable
  2008-08-21 18:04       ` [PATCH 5/7] x86: Unify x86_32 and x86_64 play_dead into one function Alex Nixon
@ 2008-08-21 18:04         ` Alex Nixon
  2008-08-21 18:04           ` [PATCH 7/7] Xen: Implement CPU hotplugging Alex Nixon
  0 siblings, 1 reply; 10+ messages in thread
From: Alex Nixon @ 2008-08-21 18:04 UTC (permalink / raw)
  To: Linux Kernel Mailing List; +Cc: Alex Nixon, Jeremy Fitzhardinge, Ingo Molnar

It allows paravirt implementations of cpu_disable to share the cpu_disable_common code, without having to take on board APIC writes, which may not be appropriate.

Signed-off-by: Alex Nixon <alex.nixon@citrix.com>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Ingo Molnar <mingo@elte.hu>
---
 arch/x86/kernel/smpboot.c |   40 +++++++++++++++++++++++-----------------
 include/asm-x86/smp.h     |    1 +
 2 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 83e9591..ccb3b12 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1340,25 +1340,9 @@ static void __ref remove_cpu_from_maps(int cpu)
 	numa_remove_cpu(cpu);
 }
 
-int native_cpu_disable(void)
+void cpu_disable_common(void)
 {
 	int cpu = smp_processor_id();
-
-	/*
-	 * Perhaps use cpufreq to drop frequency, but that could go
-	 * into generic code.
-	 *
-	 * We won't take down the boot processor on i386 due to some
-	 * interrupts only being able to be serviced by the BSP.
-	 * Especially so if we're not using an IOAPIC	-zwane
-	 */
-	if (cpu == 0)
-		return -EBUSY;
-
-	if (nmi_watchdog == NMI_LOCAL_APIC)
-		stop_apic_nmi_watchdog(NULL);
-	clear_local_APIC();
-
 	/*
 	 * HACK:
 	 * Allow any queued timer interrupts to get serviced
@@ -1376,6 +1360,28 @@ int native_cpu_disable(void)
 	remove_cpu_from_maps(cpu);
 	unlock_vector_lock();
 	fixup_irqs(cpu_online_map);
+}
+
+int native_cpu_disable(void)
+{
+	int cpu = smp_processor_id();
+
+	/*
+	 * Perhaps use cpufreq to drop frequency, but that could go
+	 * into generic code.
+	 *
+	 * We won't take down the boot processor on i386 due to some
+	 * interrupts only being able to be serviced by the BSP.
+	 * Especially so if we're not using an IOAPIC	-zwane
+	 */
+	if (cpu == 0)
+		return -EBUSY;
+
+	if (nmi_watchdog == NMI_LOCAL_APIC)
+		stop_apic_nmi_watchdog(NULL);
+	clear_local_APIC();
+
+	cpu_disable_common();
 	return 0;
 }
 
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index fd2a070..bff3fa6 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -109,6 +109,7 @@ static inline void arch_send_call_function_ipi(cpumask_t mask)
 	smp_ops.send_call_func_ipi(mask);
 }
 
+void cpu_disable_common(void);
 void native_smp_prepare_boot_cpu(void);
 void native_smp_prepare_cpus(unsigned int max_cpus);
 void native_smp_cpus_done(unsigned int max_cpus);
-- 
1.5.4.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/7] Xen:  Implement CPU hotplugging
  2008-08-21 18:04         ` [PATCH 6/7] x86: Separate generic cpu disabling code from APIC writes in cpu_disable Alex Nixon
@ 2008-08-21 18:04           ` Alex Nixon
  2008-08-21 18:37             ` Jeremy Fitzhardinge
  0 siblings, 1 reply; 10+ messages in thread
From: Alex Nixon @ 2008-08-21 18:04 UTC (permalink / raw)
  To: Linux Kernel Mailing List; +Cc: Alex Nixon, Jeremy Fitzhardinge, Ingo Molnar

Note the changes from 2.6.18-xen CPU hotplugging:

A vcpu_down request from the remote admin via Xenbus both hotunplugs the CPU, and disables it by removing it from the cpu_present map, and removing its entry in /sys

A vcpu_up request from the remote admin only re-enables the CPU, and does not immediately bring the CPU up.  A udev event is emitted, which can be caught by the user if he wishes to automatically re-up CPUs when available, or implement a more complex policy.

Signed-off-by: Alex Nixon <alex.nixon@citrix.com>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Ingo Molnar <mingo@elte.hu>
---
 arch/x86/xen/enlighten.c  |    7 +++
 arch/x86/xen/irq.c        |    2 +-
 arch/x86/xen/smp.c        |   52 +++++++++++++++++++++-----
 arch/x86/xen/spinlock.c   |    5 ++
 arch/x86/xen/time.c       |    8 ++++
 arch/x86/xen/xen-ops.h    |    6 +++
 drivers/xen/Makefile      |    2 +-
 drivers/xen/cpu_hotplug.c |   90 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/xen/events.c      |    4 ++
 9 files changed, 164 insertions(+), 12 deletions(-)
 create mode 100644 drivers/xen/cpu_hotplug.c

diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index c421049..204d64b 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1342,6 +1342,12 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
 	.set_fixmap = xen_set_fixmap,
 };
 
+static const struct pv_hotplug_ops xen_hotplug_ops = {
+	.play_dead = xen_play_dead,
+	.cpu_disable = xen_cpu_disable,
+	.cpu_die = xen_cpu_die,
+};
+
 static void xen_reboot(int reason)
 {
 	struct sched_shutdown r = { .reason = reason };
@@ -1655,6 +1661,7 @@ asmlinkage void __init xen_start_kernel(void)
 	pv_cpu_ops = xen_cpu_ops;
 	pv_apic_ops = xen_apic_ops;
 	pv_mmu_ops = xen_mmu_ops;
+	pv_hotplug_ops = xen_hotplug_ops;
 
 	xen_init_irq_ops();
 
diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
index 4e3f7f7..f33f75b 100644
--- a/arch/x86/xen/irq.c
+++ b/arch/x86/xen/irq.c
@@ -134,7 +134,7 @@ static const struct pv_irq_ops xen_irq_ops __initdata = {
 	.restore_fl = xen_restore_fl,
 	.irq_disable = xen_irq_disable,
 	.irq_enable = xen_irq_enable,
-	.wb_invd_halt = xen_wbinvd_halt,
+	.wbinvd_halt = xen_wbinvd_halt,
 	.safe_halt = xen_safe_halt,
 	.halt = xen_halt,
 #ifdef CONFIG_X86_64
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index baca7f2..682eaa4 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -12,7 +12,6 @@
  * result, all CPUs are treated as if they're single-core and
  * single-threaded.
  *
- * This does not handle HOTPLUG_CPU yet.
  */
 #include <linux/sched.h>
 #include <linux/err.h>
@@ -61,11 +60,12 @@ static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static __cpuinit void cpu_bringup_and_idle(void)
+static __cpuinit void cpu_bringup(void)
 {
 	int cpu = smp_processor_id();
 
 	cpu_init();
+	touch_softlockup_watchdog();
 	preempt_disable();
 
 	xen_enable_sysenter();
@@ -86,6 +86,11 @@ static __cpuinit void cpu_bringup_and_idle(void)
 	local_irq_enable();
 
 	wmb();			/* make sure everything is out */
+}
+
+static __cpuinit void cpu_bringup_and_idle(void)
+{
+	cpu_bringup();
 	cpu_idle();
 }
 
@@ -209,8 +214,6 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
 
 		cpu_set(cpu, cpu_present_map);
 	}
-
-	//init_xenbus_allowed_cpumask();
 }
 
 static __cpuinit int
@@ -278,12 +281,6 @@ static int __cpuinit xen_cpu_up(unsigned int cpu)
 	struct task_struct *idle = idle_task(cpu);
 	int rc;
 
-#if 0
-	rc = cpu_up_check(cpu);
-	if (rc)
-		return rc;
-#endif
-
 #ifdef CONFIG_X86_64
 	/* Allocate node local memory for AP pdas */
 	WARN_ON(cpu == 0);
@@ -336,6 +333,41 @@ static void xen_smp_cpus_done(unsigned int max_cpus)
 {
 }
 
+int xen_cpu_disable(void)
+{
+	unsigned int cpu = smp_processor_id();
+	if (cpu == 0)
+		return -EBUSY;
+
+	cpu_disable_common();
+
+	load_cr3(swapper_pg_dir);
+	return 0;
+}
+
+void xen_cpu_die(unsigned int cpu)
+{
+	while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout(HZ/10);
+	}
+	unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
+	unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
+	unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL);
+	unbind_from_irqhandler(per_cpu(callfuncsingle_irq, cpu), NULL);
+	xen_uninit_lock_cpu(cpu);
+	xen_teardown_timer(cpu);
+
+	if (num_online_cpus() == 1)
+		alternatives_smp_switch(0);
+}
+
+void xen_play_dead(void)
+{
+	native_play_dead();
+	cpu_bringup();
+}
+
 static void stop_self(void *v)
 {
 	int cpu = smp_processor_id();
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
index bfb1707..74a5114 100644
--- a/arch/x86/xen/spinlock.c
+++ b/arch/x86/xen/spinlock.c
@@ -173,6 +173,11 @@ void __cpuinit xen_init_lock_cpu(int cpu)
 	printk("cpu %d spinlock event irq %d\n", cpu, irq);
 }
 
+void xen_uninit_lock_cpu(int cpu)
+{
+	unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
+}
+
 void __init xen_init_spinlocks(void)
 {
 	pv_lock_ops.spin_is_locked = xen_spin_is_locked;
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 685b774..8034d69 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -452,6 +452,14 @@ void xen_setup_timer(int cpu)
 	setup_runstate_info(cpu);
 }
 
+void xen_teardown_timer(int cpu)
+{
+	struct clock_event_device *evt;
+	BUG_ON(cpu == 0);
+	evt = &per_cpu(xen_clock_events, cpu);
+	unbind_from_irqhandler(evt->irq, NULL);
+}
+
 void xen_setup_cpu_clockevents(void)
 {
 	BUG_ON(preemptible());
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index 3c70ebc..a16e5b5 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -33,6 +33,7 @@ void __init xen_build_dynamic_phys_to_machine(void);
 
 void xen_init_irq_ops(void);
 void xen_setup_timer(int cpu);
+void xen_teardown_timer(int cpu);
 void xen_setup_cpu_clockevents(void);
 unsigned long xen_tsc_khz(void);
 void __init xen_time_init(void);
@@ -48,11 +49,16 @@ void xen_mark_init_mm_pinned(void);
 
 void __init xen_setup_vcpu_info_placement(void);
 
+void xen_play_dead(void);
+void xen_cpu_die(unsigned int cpu);
+int xen_cpu_disable(void);
+
 #ifdef CONFIG_SMP
 void xen_smp_init(void);
 
 void __init xen_init_spinlocks(void);
 __cpuinit void xen_init_lock_cpu(int cpu);
+void xen_uninit_lock_cpu(int cpu);
 
 extern cpumask_t xen_cpu_initialized_map;
 #else
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 363286c..f62d8df 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -1,4 +1,4 @@
-obj-y	+= grant-table.o features.o events.o manage.o
+obj-y	+= grant-table.o features.o events.o manage.o cpu_hotplug.o
 obj-y	+= xenbus/
 obj-$(CONFIG_XEN_XENCOMM)	+= xencomm.o
 obj-$(CONFIG_XEN_BALLOON)	+= balloon.o
diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c
new file mode 100644
index 0000000..f1727ce
--- /dev/null
+++ b/drivers/xen/cpu_hotplug.c
@@ -0,0 +1,90 @@
+#include <linux/notifier.h>
+
+#include <xen/xenbus.h>
+
+#include <asm-x86/xen/hypervisor.h>
+#include <asm/cpu.h>
+
+static void enable_hotplug_cpu(int cpu)
+{
+	if (!cpu_present(cpu))
+		arch_register_cpu(cpu);
+
+	cpu_set(cpu, cpu_present_map);
+}
+
+static void disable_hotplug_cpu(int cpu)
+{
+	if (cpu_present(cpu))
+		arch_unregister_cpu(cpu);
+
+	cpu_clear(cpu, cpu_present_map);
+}
+
+static void vcpu_hotplug(unsigned int cpu)
+{
+	int err;
+	char dir[32], state[32];
+
+	if (!cpu_possible(cpu))
+		return;
+
+	sprintf(dir, "cpu/%u", cpu);
+	err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
+	if (err != 1) {
+		printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
+		return;
+	}
+
+	if (strcmp(state, "online") == 0) {
+		enable_hotplug_cpu(cpu);
+	} else if (strcmp(state, "offline") == 0) {
+		(void)cpu_down(cpu);
+		disable_hotplug_cpu(cpu);
+	} else {
+		printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
+		       state, cpu);
+	}
+}
+
+static void handle_vcpu_hotplug_event(
+	struct xenbus_watch *watch, const char **vec, unsigned int len)
+{
+	unsigned int cpu;
+	char *cpustr;
+	const char *node = vec[XS_WATCH_PATH];
+
+	cpustr = strstr(node, "cpu/");
+	if (cpustr != NULL) {
+		sscanf(cpustr, "cpu/%u", &cpu);
+		vcpu_hotplug(cpu);
+	}
+}
+
+static int setup_cpu_watcher(struct notifier_block *notifier,
+			      unsigned long event, void *data)
+{
+	static struct xenbus_watch cpu_watch = {
+		.node = "cpu",
+		.callback = handle_vcpu_hotplug_event};
+
+	(void)register_xenbus_watch(&cpu_watch);
+
+	return NOTIFY_DONE;
+}
+
+static int __init setup_vcpu_hotplug_event(void)
+{
+	static struct notifier_block xsn_cpu = {
+		.notifier_call = setup_cpu_watcher };
+
+	if (!is_running_on_xen())
+		return -ENODEV;
+
+	register_xenstore_notifier(&xsn_cpu);
+
+	return 0;
+}
+
+arch_initcall(setup_vcpu_hotplug_event);
+
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 2a49ffc..63ca861 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -358,6 +358,10 @@ static void unbind_from_irq(unsigned int irq)
 			per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
 				[index_from_irq(irq)] = -1;
 			break;
+		case IRQT_IPI:
+			per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn))
+				[index_from_irq(irq)] = -1;
+			break;
 		default:
 			break;
 		}
-- 
1.5.4.3


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/7] x86/paravirt:  Add paravirt hook for wbinvd_halt
  2008-08-21 18:04 ` [PATCH 2/7] x86/paravirt: Add paravirt hook for wbinvd_halt Alex Nixon
  2008-08-21 18:04   ` [PATCH 3/7] Xen: Add Xen implementation of wbinvd_halt Alex Nixon
@ 2008-08-21 18:16   ` Jeremy Fitzhardinge
  1 sibling, 0 replies; 10+ messages in thread
From: Jeremy Fitzhardinge @ 2008-08-21 18:16 UTC (permalink / raw)
  To: Alex Nixon; +Cc: Linux Kernel Mailing List, Ingo Molnar

Alex Nixon wrote:
> The native case of wb_invd_halt uses inline asm to ensure the compiler doesn't reorder the sequence of instructions, which has the side-effect of skirting around the paravirt hooks for those instructions.  Thus, create a new hook for this case.
>   

Not necessary.  Halting in Xen doesn't require the caches to be flushed
in this way, and I think that would be true for any virtual environment
(and if it were, the invalidate/halt instruction sequence would work
anyway).

The correct fix is to make sure that the native_play_dead calls this,
but the xen_play_dead doesn't (ie, make sure it's not in the common code
path).

    J

> Signed-off-by: Alex Nixon <alex.nixon@citrix.com>
> Cc: Jeremy Fitzhardinge <jeremy@goop.org>
> Cc: Ingo Molnar <mingo@elte.hu>
> ---
>  arch/x86/kernel/paravirt.c  |    1 +
>  include/asm-x86/paravirt.h  |    6 ++++++
>  include/asm-x86/processor.h |    3 ++-
>  3 files changed, 9 insertions(+), 1 deletions(-)
>
> diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
> index 8ffe4d1..66d6d0d 100644
> --- a/arch/x86/kernel/paravirt.c
> +++ b/arch/x86/kernel/paravirt.c
> @@ -299,6 +299,7 @@ struct pv_irq_ops pv_irq_ops = {
>  	.restore_fl = native_restore_fl,
>  	.irq_disable = native_irq_disable,
>  	.irq_enable = native_irq_enable,
> +	.wbinvd_halt = native_wbinvd_halt,
>  	.safe_halt = native_safe_halt,
>  	.halt = native_halt,
>  #ifdef CONFIG_X86_64
> diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h
> index fd922c3..5360f3f 100644
> --- a/include/asm-x86/paravirt.h
> +++ b/include/asm-x86/paravirt.h
> @@ -194,6 +194,7 @@ struct pv_irq_ops {
>  	void (*restore_fl)(unsigned long);
>  	void (*irq_disable)(void);
>  	void (*irq_enable)(void);
> +	void (*wbinvd_halt)(void);
>  	void (*safe_halt)(void);
>  	void (*halt)(void);
>  
> @@ -716,6 +717,11 @@ static inline void raw_safe_halt(void)
>  	PVOP_VCALL0(pv_irq_ops.safe_halt);
>  }
>  
> +static inline void wbinvd_halt(void)
> +{
> +	PVOP_VCALL0(pv_irq_ops.wbinvd_halt);
> +}
> +
>  static inline void halt(void)
>  {
>  	PVOP_VCALL0(pv_irq_ops.safe_halt);
> diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h
> index bcfc727..75db315 100644
> --- a/include/asm-x86/processor.h
> +++ b/include/asm-x86/processor.h
> @@ -558,6 +558,7 @@ static inline void load_sp0(struct tss_struct *tss,
>  	native_load_sp0(tss, thread);
>  }
>  
> +#define wbinvd_halt native_wbinvd_halt
>  #define set_iopl_mask native_set_iopl_mask
>  #endif /* CONFIG_PARAVIRT */
>  
> @@ -733,7 +734,7 @@ extern unsigned long		idle_nomwait;
>   *
>   * Systems without cache can just go into halt.
>   */
> -static inline void wbinvd_halt(void)
> +static inline void native_wbinvd_halt(void)
>  {
>  	mb();
>  	/* check for clflush to determine if wbinvd is legal */
>   


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/7] x86/paravirt:  Add hooks for CPU hotplugging
  2008-08-21 18:04 [PATCH 1/7] x86/paravirt: Add hooks for CPU hotplugging Alex Nixon
  2008-08-21 18:04 ` [PATCH 2/7] x86/paravirt: Add paravirt hook for wbinvd_halt Alex Nixon
@ 2008-08-21 18:19 ` Jeremy Fitzhardinge
  1 sibling, 0 replies; 10+ messages in thread
From: Jeremy Fitzhardinge @ 2008-08-21 18:19 UTC (permalink / raw)
  To: Alex Nixon; +Cc: Linux Kernel Mailing List, Ingo Molnar

Alex Nixon wrote:
> Signed-off-by: Alex Nixon <alex.nixon@citrix.com>
> Cc: Jeremy Fitzhardinge <jeremy@goop.org>
> Cc: Ingo Molnar <mingo@elte.hu>
> ---
>  arch/x86/kernel/paravirt.c   |    8 ++++++++
>  arch/x86/kernel/process_32.c |   10 ++++++++--
>  arch/x86/kernel/process_64.c |    9 +++++++--
>  arch/x86/kernel/smpboot.c    |    8 ++++----
>  include/asm-x86/paravirt.h   |   27 +++++++++++++++++++++++++++
>  include/asm-x86/smp.h        |   13 +++++++++++--
>  6 files changed, 65 insertions(+), 10 deletions(-)
>
> diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
> index 7cd2747..8ffe4d1 100644
> --- a/arch/x86/kernel/paravirt.c
> +++ b/arch/x86/kernel/paravirt.c
> @@ -125,6 +125,7 @@ static void *get_call_destination(u8 type)
>  		.pv_apic_ops = pv_apic_ops,
>  		.pv_mmu_ops = pv_mmu_ops,
>  		.pv_lock_ops = pv_lock_ops,
> +		.pv_hotplug_ops = pv_hotplug_ops,
>   

I think I'd prefer these to be part of smp_ops.  We're only talking
about three new operations, and they're the logical compliments of the
existing smp_ops functions for bringing up cpus.

    J


>  	};
>  	return *((void **)&tmpl + type);
>  }
> @@ -455,9 +456,16 @@ struct pv_mmu_ops pv_mmu_ops = {
>  	.set_fixmap = native_set_fixmap,
>  };
>  
> +struct pv_hotplug_ops pv_hotplug_ops = {
> +	.cpu_die = native_cpu_die,
> +	.cpu_disable = native_cpu_disable,
> +	.play_dead = native_play_dead,
> +};
> +
>  EXPORT_SYMBOL_GPL(pv_time_ops);
>  EXPORT_SYMBOL    (pv_cpu_ops);
>  EXPORT_SYMBOL    (pv_mmu_ops);
>  EXPORT_SYMBOL_GPL(pv_apic_ops);
>  EXPORT_SYMBOL_GPL(pv_info);
>  EXPORT_SYMBOL    (pv_irq_ops);
> +EXPORT_SYMBOL    (pv_hotplug_ops);
> diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
> index 593b73e..53887cd 100644
> --- a/arch/x86/kernel/process_32.c
> +++ b/arch/x86/kernel/process_32.c
> @@ -77,6 +77,12 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
>  #ifdef CONFIG_HOTPLUG_CPU
>  #include <asm/nmi.h>
>  
> +#ifdef CONFIG_PARAVIRT
> +#include <asm/paravirt.h>
> +#else
> +#define play_dead native_play_dead
> +#endif
> +
>  static void cpu_exit_clear(void)
>  {
>  	int cpu = raw_smp_processor_id();
> @@ -93,7 +99,7 @@ static void cpu_exit_clear(void)
>  }
>  
>  /* We don't actually take CPU down, just spin without interrupts. */
> -static inline void play_dead(void)
> +void native_play_dead(void)
>  {
>  	/* This must be done before dead CPU ack */
>  	cpu_exit_clear();
> @@ -109,7 +115,7 @@ static inline void play_dead(void)
>  	wbinvd_halt();
>  }
>  #else
> -static inline void play_dead(void)
> +void play_dead(void)
>  {
>  	BUG();
>  }
> diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
> index 8248dc0..7512044 100644
> --- a/arch/x86/kernel/process_64.c
> +++ b/arch/x86/kernel/process_64.c
> @@ -86,13 +86,18 @@ void exit_idle(void)
>  		return;
>  	__exit_idle();
>  }
> +#ifdef CONFIG_PARAVIRT
> +#include <asm/paravirt.h>
> +#else
> +#define play_dead native_play_dead
> +#endif
>  
>  #ifdef CONFIG_HOTPLUG_CPU
>  DECLARE_PER_CPU(int, cpu_state);
>  
>  #include <linux/nmi.h>
>  /* We halt the CPU with physical CPU hotplug */
> -static inline void play_dead(void)
> +void native_play_dead(void)
>  {
>  	idle_task_exit();
>  	mb();
> @@ -104,7 +109,7 @@ static inline void play_dead(void)
>  	wbinvd_halt();
>  }
>  #else
> -static inline void play_dead(void)
> +void native_play_dead(void)
>  {
>  	BUG();
>  }
> diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
> index eea2fd6..2a555a1 100644
> --- a/arch/x86/kernel/smpboot.c
> +++ b/arch/x86/kernel/smpboot.c
> @@ -1340,7 +1340,7 @@ static void __ref remove_cpu_from_maps(int cpu)
>  	numa_remove_cpu(cpu);
>  }
>  
> -int __cpu_disable(void)
> +int native_cpu_disable(void)
>  {
>  	int cpu = smp_processor_id();
>  
> @@ -1379,7 +1379,7 @@ int __cpu_disable(void)
>  	return 0;
>  }
>  
> -void __cpu_die(unsigned int cpu)
> +void native_cpu_die(unsigned int cpu)
>  {
>  	/* We don't do anything here: idle task is faking death itself. */
>  	unsigned int i;
> @@ -1397,12 +1397,12 @@ void __cpu_die(unsigned int cpu)
>  	printk(KERN_ERR "CPU %u didn't die...\n", cpu);
>  }
>  #else /* ... !CONFIG_HOTPLUG_CPU */
> -int __cpu_disable(void)
> +int native_cpu_disable(void)
>  {
>  	return -ENOSYS;
>  }
>  
> -void __cpu_die(unsigned int cpu)
> +void native_cpu_die(unsigned int cpu)
>  {
>  	/* We said "no" in __cpu_disable */
>  	BUG();
> diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h
> index eca8c4f..fd922c3 100644
> --- a/include/asm-x86/paravirt.h
> +++ b/include/asm-x86/paravirt.h
> @@ -332,6 +332,12 @@ struct pv_lock_ops {
>  	void (*spin_unlock)(struct raw_spinlock *lock);
>  };
>  
> +struct pv_hotplug_ops {
> +	void (*play_dead)(void);
> +	int (*cpu_disable)(void);
> +	void (*cpu_die)(unsigned int);
> +};
> +
>  /* This contains all the paravirt structures: we get a convenient
>   * number for each function using the offset which we use to indicate
>   * what to patch. */
> @@ -343,6 +349,7 @@ struct paravirt_patch_template {
>  	struct pv_apic_ops pv_apic_ops;
>  	struct pv_mmu_ops pv_mmu_ops;
>  	struct pv_lock_ops pv_lock_ops;
> +	struct pv_hotplug_ops pv_hotplug_ops;
>  };
>  
>  extern struct pv_info pv_info;
> @@ -353,6 +360,7 @@ extern struct pv_irq_ops pv_irq_ops;
>  extern struct pv_apic_ops pv_apic_ops;
>  extern struct pv_mmu_ops pv_mmu_ops;
>  extern struct pv_lock_ops pv_lock_ops;
> +extern struct pv_hotplug_ops pv_hotplug_ops;
>  
>  #define PARAVIRT_PATCH(x)					\
>  	(offsetof(struct paravirt_patch_template, x) / sizeof(void *))
> @@ -1408,6 +1416,25 @@ static __always_inline void __raw_spin_unlock(struct raw_spinlock *lock)
>  
>  #endif
>  
> +#ifdef CONFIG_HOTPLUG_CPU
> +
> +static inline int __cpu_disable(void)
> +{
> +	return PVOP_CALL0(int, pv_hotplug_ops.cpu_disable);
> +}
> +
> +static inline void __cpu_die(unsigned int cpu)
> +{
> +	PVOP_VCALL1(pv_hotplug_ops.cpu_die, cpu);
> +}
> +
> +static inline void play_dead(void)
> +{
> +	PVOP_VCALL0(pv_hotplug_ops.play_dead);
> +}
> +
> +#endif
> +
>  /* These all sit in the .parainstructions section to tell us what to patch. */
>  struct paravirt_patch_site {
>  	u8 *instr; 		/* original instructions */
> diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
> index 29324c1..f7d153f 100644
> --- a/include/asm-x86/smp.h
> +++ b/include/asm-x86/smp.h
> @@ -113,11 +113,20 @@ void native_smp_prepare_boot_cpu(void);
>  void native_smp_prepare_cpus(unsigned int max_cpus);
>  void native_smp_cpus_done(unsigned int max_cpus);
>  int native_cpu_up(unsigned int cpunum);
> +int native_cpu_disable(void);
> +void native_cpu_die(unsigned int cpu);
> +void native_play_dead(void);
> +
>  void native_send_call_func_ipi(cpumask_t mask);
>  void native_send_call_func_single_ipi(int cpu);
>  
> -extern int __cpu_disable(void);
> -extern void __cpu_die(unsigned int cpu);
> +
> +#ifdef CONFIG_PARAVIRT
> +#include <asm/paravirt.h>
> +#else
> +#define __cpu_disable	native_cpu_disable
> +#define __cpu_die	native_cpu_die
> +#endif
>  
>  void smp_store_cpu_info(int id);
>  #define cpu_physical_id(cpu)	per_cpu(x86_cpu_to_apicid, cpu)
>   


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 7/7] Xen:  Implement CPU hotplugging
  2008-08-21 18:04           ` [PATCH 7/7] Xen: Implement CPU hotplugging Alex Nixon
@ 2008-08-21 18:37             ` Jeremy Fitzhardinge
  0 siblings, 0 replies; 10+ messages in thread
From: Jeremy Fitzhardinge @ 2008-08-21 18:37 UTC (permalink / raw)
  To: Alex Nixon; +Cc: Linux Kernel Mailing List, Ingo Molnar

Alex Nixon wrote:
> Note the changes from 2.6.18-xen CPU hotplugging:
>
> A vcpu_down request from the remote admin via Xenbus both hotunplugs the CPU, and disables it by removing it from the cpu_present map, and removing its entry in /sys
>
> A vcpu_up request from the remote admin only re-enables the CPU, and does not immediately bring the CPU up.  A udev event is emitted, which can be caught by the user if he wishes to automatically re-up CPUs when available, or implement a more complex policy.
>   

Good, that's better.

> Signed-off-by: Alex Nixon <alex.nixon@citrix.com>
> Cc: Jeremy Fitzhardinge <jeremy@goop.org>
> Cc: Ingo Molnar <mingo@elte.hu>
> ---
>  arch/x86/xen/enlighten.c  |    7 +++
>  arch/x86/xen/irq.c        |    2 +-
>  arch/x86/xen/smp.c        |   52 +++++++++++++++++++++-----
>  arch/x86/xen/spinlock.c   |    5 ++
>  arch/x86/xen/time.c       |    8 ++++
>  arch/x86/xen/xen-ops.h    |    6 +++
>  drivers/xen/Makefile      |    2 +-
>  drivers/xen/cpu_hotplug.c |   90 +++++++++++++++++++++++++++++++++++++++++++++
>  drivers/xen/events.c      |    4 ++
>  9 files changed, 164 insertions(+), 12 deletions(-)
>  create mode 100644 drivers/xen/cpu_hotplug.c
>
> diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
> index c421049..204d64b 100644
> --- a/arch/x86/xen/enlighten.c
> +++ b/arch/x86/xen/enlighten.c
> @@ -1342,6 +1342,12 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
>  	.set_fixmap = xen_set_fixmap,
>  };
>  
> +static const struct pv_hotplug_ops xen_hotplug_ops = {
> +	.play_dead = xen_play_dead,
> +	.cpu_disable = xen_cpu_disable,
> +	.cpu_die = xen_cpu_die,
> +};
> +
>  static void xen_reboot(int reason)
>  {
>  	struct sched_shutdown r = { .reason = reason };
> @@ -1655,6 +1661,7 @@ asmlinkage void __init xen_start_kernel(void)
>  	pv_cpu_ops = xen_cpu_ops;
>  	pv_apic_ops = xen_apic_ops;
>  	pv_mmu_ops = xen_mmu_ops;
> +	pv_hotplug_ops = xen_hotplug_ops;
>  
>  	xen_init_irq_ops();
>  
> diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
> index 4e3f7f7..f33f75b 100644
> --- a/arch/x86/xen/irq.c
> +++ b/arch/x86/xen/irq.c
> @@ -134,7 +134,7 @@ static const struct pv_irq_ops xen_irq_ops __initdata = {
>  	.restore_fl = xen_restore_fl,
>  	.irq_disable = xen_irq_disable,
>  	.irq_enable = xen_irq_enable,
> -	.wb_invd_halt = xen_wbinvd_halt,
> +	.wbinvd_halt = xen_wbinvd_halt,
>   

What's this?  A typo fix?  It should be folded back to the appropriate
patch (except for the fact that I think this op should be gone).

>  	.safe_halt = xen_safe_halt,
>  	.halt = xen_halt,
>  #ifdef CONFIG_X86_64
> diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
> index baca7f2..682eaa4 100644
> --- a/arch/x86/xen/smp.c
> +++ b/arch/x86/xen/smp.c
> @@ -12,7 +12,6 @@
>   * result, all CPUs are treated as if they're single-core and
>   * single-threaded.
>   *
> - * This does not handle HOTPLUG_CPU yet.
>   
Remove the blank line too.
>   */
>  #include <linux/sched.h>
>  #include <linux/err.h>
> @@ -61,11 +60,12 @@ static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
>  	return IRQ_HANDLED;
>  }
>  
> -static __cpuinit void cpu_bringup_and_idle(void)
> +static __cpuinit void cpu_bringup(void)
>  {
>  	int cpu = smp_processor_id();
>  
>  	cpu_init();
> +	touch_softlockup_watchdog();
>  	preempt_disable();
>  
>  	xen_enable_sysenter();
> @@ -86,6 +86,11 @@ static __cpuinit void cpu_bringup_and_idle(void)
>  	local_irq_enable();
>  
>  	wmb();			/* make sure everything is out */
> +}
> +
> +static __cpuinit void cpu_bringup_and_idle(void)
> +{
> +	cpu_bringup();
>  	cpu_idle();
>  }
>  
> @@ -209,8 +214,6 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
>  
>  		cpu_set(cpu, cpu_present_map);
>  	}
> -
> -	//init_xenbus_allowed_cpumask();
>  }
>  
>  static __cpuinit int
> @@ -278,12 +281,6 @@ static int __cpuinit xen_cpu_up(unsigned int cpu)
>  	struct task_struct *idle = idle_task(cpu);
>  	int rc;
>  
> -#if 0
> -	rc = cpu_up_check(cpu);
> -	if (rc)
> -		return rc;
> -#endif
> -
>  #ifdef CONFIG_X86_64
>  	/* Allocate node local memory for AP pdas */
>  	WARN_ON(cpu == 0);
> @@ -336,6 +333,41 @@ static void xen_smp_cpus_done(unsigned int max_cpus)
>  {
>  }
>  
> +int xen_cpu_disable(void)
> +{
> +	unsigned int cpu = smp_processor_id();
> +	if (cpu == 0)
> +		return -EBUSY;
> +
> +	cpu_disable_common();
> +
> +	load_cr3(swapper_pg_dir);
> +	return 0;
> +}
> +
> +void xen_cpu_die(unsigned int cpu)
> +{
> +	while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
> +		current->state = TASK_UNINTERRUPTIBLE;
> +		schedule_timeout(HZ/10);
> +	}
> +	unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
> +	unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
> +	unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL);
> +	unbind_from_irqhandler(per_cpu(callfuncsingle_irq, cpu), NULL);
> +	xen_uninit_lock_cpu(cpu);
> +	xen_teardown_timer(cpu);
> +
> +	if (num_online_cpus() == 1)
> +		alternatives_smp_switch(0);
> +}
> +
> +void xen_play_dead(void)
> +{
> +	native_play_dead();
> +	cpu_bringup();
>   

No, call common_play_dead(), then xen_halt(), then cpu_bringup().

> +}
> +
>  static void stop_self(void *v)
>  {
>  	int cpu = smp_processor_id();
> diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
> index bfb1707..74a5114 100644
> --- a/arch/x86/xen/spinlock.c
> +++ b/arch/x86/xen/spinlock.c
> @@ -173,6 +173,11 @@ void __cpuinit xen_init_lock_cpu(int cpu)
>  	printk("cpu %d spinlock event irq %d\n", cpu, irq);
>  }
>  
> +void xen_uninit_lock_cpu(int cpu)
> +{
> +	unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
> +}
> +
>  void __init xen_init_spinlocks(void)
>  {
>  	pv_lock_ops.spin_is_locked = xen_spin_is_locked;
> diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
> index 685b774..8034d69 100644
> --- a/arch/x86/xen/time.c
> +++ b/arch/x86/xen/time.c
> @@ -452,6 +452,14 @@ void xen_setup_timer(int cpu)
>  	setup_runstate_info(cpu);
>  }
>  
> +void xen_teardown_timer(int cpu)
> +{
> +	struct clock_event_device *evt;
> +	BUG_ON(cpu == 0);
> +	evt = &per_cpu(xen_clock_events, cpu);
> +	unbind_from_irqhandler(evt->irq, NULL);
> +}
> +
>  void xen_setup_cpu_clockevents(void)
>  {
>  	BUG_ON(preemptible());
> diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
> index 3c70ebc..a16e5b5 100644
> --- a/arch/x86/xen/xen-ops.h
> +++ b/arch/x86/xen/xen-ops.h
> @@ -33,6 +33,7 @@ void __init xen_build_dynamic_phys_to_machine(void);
>  
>  void xen_init_irq_ops(void);
>  void xen_setup_timer(int cpu);
> +void xen_teardown_timer(int cpu);
>  void xen_setup_cpu_clockevents(void);
>  unsigned long xen_tsc_khz(void);
>  void __init xen_time_init(void);
> @@ -48,11 +49,16 @@ void xen_mark_init_mm_pinned(void);
>  
>  void __init xen_setup_vcpu_info_placement(void);
>  
> +void xen_play_dead(void);
> +void xen_cpu_die(unsigned int cpu);
> +int xen_cpu_disable(void);
> +
>  #ifdef CONFIG_SMP
>  void xen_smp_init(void);
>  
>  void __init xen_init_spinlocks(void);
>  __cpuinit void xen_init_lock_cpu(int cpu);
> +void xen_uninit_lock_cpu(int cpu);
>  
>  extern cpumask_t xen_cpu_initialized_map;
>  #else
> diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
> index 363286c..f62d8df 100644
> --- a/drivers/xen/Makefile
> +++ b/drivers/xen/Makefile
> @@ -1,4 +1,4 @@
> -obj-y	+= grant-table.o features.o events.o manage.o
> +obj-y	+= grant-table.o features.o events.o manage.o cpu_hotplug.o
>  obj-y	+= xenbus/
>  obj-$(CONFIG_XEN_XENCOMM)	+= xencomm.o
>  obj-$(CONFIG_XEN_BALLOON)	+= balloon.o
> diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c
> new file mode 100644
> index 0000000..f1727ce
> --- /dev/null
> +++ b/drivers/xen/cpu_hotplug.c
> @@ -0,0 +1,90 @@
> +#include <linux/notifier.h>
> +
> +#include <xen/xenbus.h>
> +
> +#include <asm-x86/xen/hypervisor.h>
> +#include <asm/cpu.h>
> +
> +static void enable_hotplug_cpu(int cpu)
> +{
> +	if (!cpu_present(cpu))
> +		arch_register_cpu(cpu);
> +
> +	cpu_set(cpu, cpu_present_map);
> +}
> +
> +static void disable_hotplug_cpu(int cpu)
> +{
> +	if (cpu_present(cpu))
> +		arch_unregister_cpu(cpu);
> +
> +	cpu_clear(cpu, cpu_present_map);
> +}
> +
> +static void vcpu_hotplug(unsigned int cpu)
> +{
> +	int err;
> +	char dir[32], state[32];
> +
> +	if (!cpu_possible(cpu))
> +		return;
> +
> +	sprintf(dir, "cpu/%u", cpu);
> +	err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
> +	if (err != 1) {
> +		printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
> +		return;
> +	}
> +
> +	if (strcmp(state, "online") == 0) {
> +		enable_hotplug_cpu(cpu);
> +	} else if (strcmp(state, "offline") == 0) {
> +		(void)cpu_down(cpu);
> +		disable_hotplug_cpu(cpu);
> +	} else {
> +		printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
> +		       state, cpu);
> +	}
> +}
> +
> +static void handle_vcpu_hotplug_event(
> +	struct xenbus_watch *watch, const char **vec, unsigned int len)
>   

Fix the formatting here (split the line at a ',').

> +{
> +	unsigned int cpu;
> +	char *cpustr;
> +	const char *node = vec[XS_WATCH_PATH];
> +
> +	cpustr = strstr(node, "cpu/");
> +	if (cpustr != NULL) {
> +		sscanf(cpustr, "cpu/%u", &cpu);
> +		vcpu_hotplug(cpu);
> +	}
> +}
> +
> +static int setup_cpu_watcher(struct notifier_block *notifier,
> +			      unsigned long event, void *data)
> +{
> +	static struct xenbus_watch cpu_watch = {
> +		.node = "cpu",
> +		.callback = handle_vcpu_hotplug_event};
> +
> +	(void)register_xenbus_watch(&cpu_watch);
> +
> +	return NOTIFY_DONE;
> +}
> +
> +static int __init setup_vcpu_hotplug_event(void)
> +{
> +	static struct notifier_block xsn_cpu = {
> +		.notifier_call = setup_cpu_watcher };
> +
> +	if (!is_running_on_xen())
> +		return -ENODEV;
> +
> +	register_xenstore_notifier(&xsn_cpu);
> +
> +	return 0;
> +}
> +
> +arch_initcall(setup_vcpu_hotplug_event);
> +
> diff --git a/drivers/xen/events.c b/drivers/xen/events.c
> index 2a49ffc..63ca861 100644
> --- a/drivers/xen/events.c
> +++ b/drivers/xen/events.c
> @@ -358,6 +358,10 @@ static void unbind_from_irq(unsigned int irq)
>  			per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
>  				[index_from_irq(irq)] = -1;
>  			break;
> +		case IRQT_IPI:
> +			per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn))
> +				[index_from_irq(irq)] = -1;
> +			break;
>  		default:
>  			break;
>  		}
>   


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2008-08-21 18:37 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-21 18:04 [PATCH 1/7] x86/paravirt: Add hooks for CPU hotplugging Alex Nixon
2008-08-21 18:04 ` [PATCH 2/7] x86/paravirt: Add paravirt hook for wbinvd_halt Alex Nixon
2008-08-21 18:04   ` [PATCH 3/7] Xen: Add Xen implementation of wbinvd_halt Alex Nixon
2008-08-21 18:04     ` [PATCH 4/7] x86_32: Clean up play_dead Alex Nixon
2008-08-21 18:04       ` [PATCH 5/7] x86: Unify x86_32 and x86_64 play_dead into one function Alex Nixon
2008-08-21 18:04         ` [PATCH 6/7] x86: Separate generic cpu disabling code from APIC writes in cpu_disable Alex Nixon
2008-08-21 18:04           ` [PATCH 7/7] Xen: Implement CPU hotplugging Alex Nixon
2008-08-21 18:37             ` Jeremy Fitzhardinge
2008-08-21 18:16   ` [PATCH 2/7] x86/paravirt: Add paravirt hook for wbinvd_halt Jeremy Fitzhardinge
2008-08-21 18:19 ` [PATCH 1/7] x86/paravirt: Add hooks for CPU hotplugging Jeremy Fitzhardinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox