This patch add hypercall to xen hypervisor to expose physical CPU information. It also make some changes to current cpu online/offline logic: 1) Firstly, cpu online/offline will trigger a vIRQ to dom0 for status changes notification. 2) It also add an interface to platform operation to online/offline physical CPU. Currently the cpu online/offline interface is in sysctl, which can't be triggered in kernel. With this change, it is possible to trigger cpu online/offline in dom0 through sysfs interface. Signed-off-by: Jiang, Yunhong diff -r bd60c77071eb xen/arch/x86/platform_hypercall.c --- a/xen/arch/x86/platform_hypercall.c Tue Nov 03 12:41:54 2009 +0000 +++ b/xen/arch/x86/platform_hypercall.c Fri Nov 06 01:29:00 2009 +0800 @@ -39,6 +39,8 @@ DEFINE_SPINLOCK(xenpf_lock); # define copy_to_compat copy_to_guest # undef guest_from_compat_handle # define guest_from_compat_handle(x,y) ((x)=(y)) +# undef compat_handle_is_null +# define compat_handle_is_null guest_handle_is_null #else extern spinlock_t xenpf_lock; #endif @@ -51,6 +53,12 @@ static long cpu_frequency_change_helper( static long cpu_frequency_change_helper(void *data) { return cpu_frequency_change(this_cpu(freq)); +} + +static long cpu_down_helper(void *data) +{ + int cpu = (unsigned long)data; + return cpu_down(cpu); } ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) @@ -385,7 +393,100 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe break; } break; - + + case XENPF_get_cpuinfo: + { + int ncpu = num_present_cpus(), cpu, i; + struct xen_physical_cpuinfo *pcpus, *pcpu; + struct xenpf_pcpu_info *g_info; + + ret = -EINVAL; + g_info = &op->u.pcpu_info; + + if (op->u.pcpu_info.ncpus <= 0) + goto done; + + if ( compat_handle_is_null(g_info->info) ) + { + ret = -EINVAL; + goto out; + } + + ncpu = min(ncpu, (int)op->u.pcpu_info.ncpus); + pcpus = xmalloc_array(struct xen_physical_cpuinfo, ncpu); + ret = -ENOMEM; + if (pcpus == NULL) + goto out; + + memset(pcpus, 0, sizeof(struct xen_physical_cpuinfo) * ncpu); + + pcpu = pcpus; + + i = 0; + spin_lock(&cpu_add_remove_lock); + for_each_present_cpu(cpu) + { + pcpu->xen_cpuid = cpu; + pcpu->apic_id = x86_cpu_to_apicid[cpu]; + pcpu->acpi_id = acpi_get_processor_id(cpu); + ASSERT(pcpu->apic_id != BAD_APICID); + if (cpu_online(cpu)) + pcpu->flags |= XEN_PCPU_FLAGS_ONLINE; + pcpu++; + if (i++ == ncpu) + break; + } + spin_unlock(&cpu_add_remove_lock); + ret = -EFAULT; + if( copy_to_compat(g_info->info, pcpus, ncpu)) + goto out; + xfree(pcpus); +done: + op->u.pcpu_info.max_cpus = num_possible_cpus(); + op->u.pcpu_info.ncpus = ncpu; + ret = copy_to_guest(u_xenpf_op, op, 1) ? -EFAULT : 0; + } + break; + + case XENPF_resource_hotplug: + { + int cpu; + + switch ( op->u.resource.sub_cmd) + { + case XEN_CPU_online: + cpu = op->u.resource.u.cpu_ol.cpuid; + if (!cpu_present(cpu)) + { + ret = -EINVAL; + break; + } + else if (cpu_online(cpu)) + { + ret = 0; + break; + } + + ret = cpu_up(cpu); + break; + case XEN_CPU_offline: + cpu = op->u.resource.u.cpu_ol.cpuid; + if (!cpu_present(cpu)) + { + ret = -EINVAL; + break; + } else if (!cpu_online(cpu)) + { + ret = 0; + break; + } + ret = continue_hypercall_on_cpu( + 0, cpu_down_helper, (void *)(unsigned long)cpu); + break; + } + } + break; + default: ret = -ENOSYS; break; diff -r bd60c77071eb xen/arch/x86/smpboot.c --- a/xen/arch/x86/smpboot.c Tue Nov 03 12:41:54 2009 +0000 +++ b/xen/arch/x86/smpboot.c Fri Nov 06 01:29:00 2009 +0800 @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -104,7 +105,7 @@ DEFINE_PER_CPU(int, cpu_state) = { 0 }; DEFINE_PER_CPU(int, cpu_state) = { 0 }; static void *stack_base[NR_CPUS]; -static DEFINE_SPINLOCK(cpu_add_remove_lock); +DEFINE_SPINLOCK(cpu_add_remove_lock); /* * The bootstrap kernel entry code has set these up. Save them for @@ -1342,6 +1343,8 @@ int cpu_down(unsigned int cpu) cpu_mcheck_distribute_cmci(); out: + if (!err) + send_guest_global_virq(dom0, VIRQ_PCPU_STATE); spin_unlock(&cpu_add_remove_lock); return err; } @@ -1362,6 +1365,8 @@ int cpu_up(unsigned int cpu) goto out; out: + if (!err) + send_guest_global_virq(dom0, VIRQ_PCPU_STATE); spin_unlock(&cpu_add_remove_lock); return err; } diff -r bd60c77071eb xen/arch/x86/x86_64/platform_hypercall.c --- a/xen/arch/x86/x86_64/platform_hypercall.c Tue Nov 03 12:41:54 2009 +0000 +++ b/xen/arch/x86/x86_64/platform_hypercall.c Fri Nov 06 00:29:38 2009 +0800 @@ -23,6 +23,11 @@ DEFINE_XEN_GUEST_HANDLE(compat_platform_ #define xen_processor_power_t compat_processor_power_t #define set_cx_pminfo compat_set_cx_pminfo +#define xen_physical_cpuinfo compat_physical_cpuinfo +#define xen_physical_cpuinfo_ compat_physical_cpuinfo_t +#define xenpf_pcpu_info compat_pf_pcpu_info +#define xenpf_pcpu_info_t compat_pf_pcpu_info_t + #define xenpf_enter_acpi_sleep compat_pf_enter_acpi_sleep #define COMPAT diff -r bd60c77071eb xen/include/asm-x86/smp.h --- a/xen/include/asm-x86/smp.h Tue Nov 03 12:41:54 2009 +0000 +++ b/xen/include/asm-x86/smp.h Fri Nov 06 01:29:00 2009 +0800 @@ -56,6 +56,7 @@ extern u32 cpu_2_logical_apicid[]; #define CPU_ONLINE 0x0002 /* CPU is up */ #define CPU_DEAD 0x0004 /* CPU is dead */ DECLARE_PER_CPU(int, cpu_state); +extern spinlock_t(cpu_add_remove_lock); #ifdef CONFIG_HOTPLUG_CPU #define cpu_is_offline(cpu) unlikely(!cpu_online(cpu)) diff -r bd60c77071eb xen/include/public/platform.h --- a/xen/include/public/platform.h Tue Nov 03 12:41:54 2009 +0000 +++ b/xen/include/public/platform.h Fri Nov 06 01:29:00 2009 +0800 @@ -312,6 +312,44 @@ typedef struct xenpf_set_processor_pminf typedef struct xenpf_set_processor_pminfo xenpf_set_processor_pminfo_t; DEFINE_XEN_GUEST_HANDLE(xenpf_set_processor_pminfo_t); +#define XENPF_get_cpuinfo 55 +struct xen_physical_cpuinfo { + uint32_t xen_cpuid; + uint32_t apic_id; + uint32_t acpi_id; +#define XEN_PCPU_FLAGS_ONLINE 1 + uint32_t flags; +}; +typedef struct xen_physical_cpuinfo xen_physical_cpuinfo_t; +DEFINE_XEN_GUEST_HANDLE(xen_physical_cpuinfo_t); + +struct xenpf_pcpu_info +{ + /* IN/OUT */ + uint32_t ncpus; + /* OUT */ + /* The possible CPU */ + uint32_t max_cpus; + XEN_GUEST_HANDLE(xen_physical_cpuinfo_t) info; +}; +typedef struct xenpf_pcpu_info xenpf_pcpu_info_t; +DEFINE_XEN_GUEST_HANDLE(xenpf_pcpu_info_t); + +struct xenpf_cpu_ol +{ + uint32_t cpuid; +}; + +#define XENPF_resource_hotplug 56 +struct xenpf_resource_hotplug { + uint32_t sub_cmd; +#define XEN_CPU_online 1 +#define XEN_CPU_offline 2 + union { + struct xenpf_cpu_ol cpu_ol; + }u; +}; + struct xen_platform_op { uint32_t cmd; uint32_t interface_version; /* XENPF_INTERFACE_VERSION */ @@ -327,6 +365,8 @@ struct xen_platform_op { struct xenpf_change_freq change_freq; struct xenpf_getidletime getidletime; struct xenpf_set_processor_pminfo set_pminfo; + struct xenpf_pcpu_info pcpu_info; + struct xenpf_resource_hotplug resource; uint8_t pad[128]; } u; }; diff -r bd60c77071eb xen/include/public/xen.h --- a/xen/include/public/xen.h Tue Nov 03 12:41:54 2009 +0000 +++ b/xen/include/public/xen.h Fri Nov 06 00:55:32 2009 +0800 @@ -145,6 +145,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); #define VIRQ_DEBUGGER 6 /* G. (DOM0) A domain has paused for debugging. */ #define VIRQ_XENOPROF 7 /* V. XenOprofile interrupt: new sample available */ #define VIRQ_CON_RING 8 /* G. (DOM0) Bytes received on console */ +#define VIRQ_PCPU_STATE 9 /* G. (DOM0) PCPU state changed */ /* Architecture-specific VIRQ definitions. */ #define VIRQ_ARCH_0 16