2013-06-28 14:21:41 +04:00
# define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
2008-08-22 14:52:15 +04:00
# include <linux/notifier.h>
2009-10-07 02:11:14 +04:00
# include <xen/xen.h>
2008-08-22 14:52:15 +04:00
# include <xen/xenbus.h>
2008-08-18 05:05:42 +04:00
# include <asm/xen/hypervisor.h>
2008-08-22 14:52:15 +04:00
# include <asm/cpu.h>
static void enable_hotplug_cpu ( int cpu )
{
if ( ! cpu_present ( cpu ) )
arch_register_cpu ( cpu ) ;
2009-03-13 07:19:56 +03:00
set_cpu_present ( cpu , true ) ;
2008-08-22 14:52:15 +04:00
}
static void disable_hotplug_cpu ( int cpu )
{
if ( cpu_present ( cpu ) )
arch_unregister_cpu ( cpu ) ;
2009-03-13 07:19:56 +03:00
set_cpu_present ( cpu , false ) ;
2008-08-22 14:52:15 +04:00
}
2009-04-02 16:24:28 +04:00
static int vcpu_online ( unsigned int cpu )
2008-08-22 14:52:15 +04:00
{
int err ;
2013-01-15 17:31:43 +04:00
char dir [ 16 ] , state [ 16 ] ;
2008-08-22 14:52:15 +04:00
sprintf ( dir , " cpu/%u " , cpu ) ;
2013-01-15 17:31:43 +04:00
err = xenbus_scanf ( XBT_NIL , dir , " availability " , " %15s " , state ) ;
2008-08-22 14:52:15 +04:00
if ( err ! = 1 ) {
2012-02-02 01:07:41 +04:00
if ( ! xen_initial_domain ( ) )
2013-06-28 14:21:41 +04:00
pr_err ( " Unable to read cpu state \n " ) ;
2009-04-02 16:24:28 +04:00
return err ;
2008-08-22 14:52:15 +04:00
}
2009-04-02 16:24:28 +04:00
if ( strcmp ( state , " online " ) = = 0 )
return 1 ;
else if ( strcmp ( state , " offline " ) = = 0 )
return 0 ;
2013-06-28 14:21:41 +04:00
pr_err ( " unknown state(%s) on CPU%d \n " , state , cpu ) ;
2009-04-02 16:24:28 +04:00
return - EINVAL ;
}
static void vcpu_hotplug ( unsigned int cpu )
{
if ( ! cpu_possible ( cpu ) )
return ;
switch ( vcpu_online ( cpu ) ) {
case 1 :
2008-08-22 14:52:15 +04:00
enable_hotplug_cpu ( cpu ) ;
2009-04-02 16:24:28 +04:00
break ;
case 0 :
2008-08-22 14:52:15 +04:00
( void ) cpu_down ( cpu ) ;
disable_hotplug_cpu ( cpu ) ;
2009-04-02 16:24:28 +04:00
break ;
default :
break ;
2008-08-22 14:52:15 +04:00
}
}
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 )
{
2009-04-02 16:24:28 +04:00
int cpu ;
2008-08-22 14:52:15 +04:00
static struct xenbus_watch cpu_watch = {
. node = " cpu " ,
. callback = handle_vcpu_hotplug_event } ;
( void ) register_xenbus_watch ( & cpu_watch ) ;
2009-04-02 16:24:28 +04:00
for_each_possible_cpu ( cpu ) {
if ( vcpu_online ( cpu ) = = 0 ) {
( void ) cpu_down ( cpu ) ;
2009-11-03 07:28:38 +03:00
set_cpu_present ( cpu , false ) ;
2009-04-02 16:24:28 +04:00
}
}
2008-08-22 14:52:15 +04:00
return NOTIFY_DONE ;
}
static int __init setup_vcpu_hotplug_event ( void )
{
static struct notifier_block xsn_cpu = {
. notifier_call = setup_cpu_watcher } ;
2008-09-03 17:30:21 +04:00
if ( ! xen_pv_domain ( ) )
2008-08-22 14:52:15 +04:00
return - ENODEV ;
register_xenstore_notifier ( & xsn_cpu ) ;
return 0 ;
}
arch_initcall ( setup_vcpu_hotplug_event ) ;