2005-04-17 02:20:36 +04:00
/*
* drivers / base / cpu . c - basic CPU class support
*/
# include <linux/sysdev.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/cpu.h>
# include <linux/topology.h>
# include <linux/device.h>
2005-10-13 20:54:41 +04:00
# include "base.h"
2005-04-17 02:20:36 +04:00
struct sysdev_class cpu_sysdev_class = {
set_kset_name ( " cpu " ) ,
} ;
EXPORT_SYMBOL ( cpu_sysdev_class ) ;
2005-10-31 01:59:49 +03:00
static struct sys_device * cpu_sys_devices [ NR_CPUS ] ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_HOTPLUG_CPU
static ssize_t show_online ( struct sys_device * dev , char * buf )
{
struct cpu * cpu = container_of ( dev , struct cpu , sysdev ) ;
return sprintf ( buf , " %u \n " , ! ! cpu_online ( cpu - > sysdev . id ) ) ;
}
static ssize_t store_online ( struct sys_device * dev , const char * buf ,
size_t count )
{
struct cpu * cpu = container_of ( dev , struct cpu , sysdev ) ;
ssize_t ret ;
switch ( buf [ 0 ] ) {
case ' 0 ' :
ret = cpu_down ( cpu - > sysdev . id ) ;
if ( ! ret )
2005-11-16 11:00:00 +03:00
kobject_uevent ( & dev - > kobj , KOBJ_OFFLINE ) ;
2005-04-17 02:20:36 +04:00
break ;
case ' 1 ' :
2006-03-25 14:08:18 +03:00
ret = cpu_up ( cpu - > sysdev . id ) ;
2005-06-26 01:55:05 +04:00
if ( ! ret )
2005-11-16 11:00:00 +03:00
kobject_uevent ( & dev - > kobj , KOBJ_ONLINE ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
ret = - EINVAL ;
}
if ( ret > = 0 )
ret = count ;
return ret ;
}
static SYSDEV_ATTR ( online , 0600 , show_online , store_online ) ;
static void __devinit register_cpu_control ( struct cpu * cpu )
{
sysdev_create_file ( & cpu - > sysdev , & attr_online ) ;
}
void unregister_cpu ( struct cpu * cpu , struct node * root )
{
2005-10-31 01:59:49 +03:00
int logical_cpu = cpu - > sysdev . id ;
2005-04-17 02:20:36 +04:00
if ( root )
sysfs_remove_link ( & root - > sysdev . kobj ,
kobject_name ( & cpu - > sysdev . kobj ) ) ;
sysdev_remove_file ( & cpu - > sysdev , & attr_online ) ;
sysdev_unregister ( & cpu - > sysdev ) ;
2005-10-31 01:59:49 +03:00
cpu_sys_devices [ logical_cpu ] = NULL ;
2005-04-17 02:20:36 +04:00
return ;
}
# else /* ... !CONFIG_HOTPLUG_CPU */
static inline void register_cpu_control ( struct cpu * cpu )
{
}
# endif /* CONFIG_HOTPLUG_CPU */
2006-01-10 07:51:42 +03:00
# ifdef CONFIG_KEXEC
# include <linux/kexec.h>
static ssize_t show_crash_notes ( struct sys_device * dev , char * buf )
{
struct cpu * cpu = container_of ( dev , struct cpu , sysdev ) ;
ssize_t rc ;
unsigned long long addr ;
int cpunum ;
cpunum = cpu - > sysdev . id ;
/*
* Might be reading other cpu ' s data based on which cpu read thread
* has been scheduled . But cpu data ( memory ) is allocated once during
* boot up and this data does not change there after . Hence this
* operation should be safe . No locking required .
*/
addr = __pa ( per_cpu_ptr ( crash_notes , cpunum ) ) ;
rc = sprintf ( buf , " %Lx \n " , addr ) ;
return rc ;
}
static SYSDEV_ATTR ( crash_notes , 0400 , show_crash_notes , NULL ) ;
# endif
2005-04-17 02:20:36 +04:00
/*
* register_cpu - Setup a driverfs device for a CPU .
* @ cpu - Callers can set the cpu - > no_control field to 1 , to indicate not to
* generate a control file in sysfs for this CPU .
* @ num - CPU number to use when creating the device .
*
* Initialize and register the CPU device .
*/
int __devinit register_cpu ( struct cpu * cpu , int num , struct node * root )
{
int error ;
cpu - > node_id = cpu_to_node ( num ) ;
cpu - > sysdev . id = num ;
cpu - > sysdev . cls = & cpu_sysdev_class ;
error = sysdev_register ( & cpu - > sysdev ) ;
if ( ! error & & root )
error = sysfs_create_link ( & root - > sysdev . kobj ,
& cpu - > sysdev . kobj ,
kobject_name ( & cpu - > sysdev . kobj ) ) ;
if ( ! error & & ! cpu - > no_control )
register_cpu_control ( cpu ) ;
2005-10-31 01:59:49 +03:00
if ( ! error )
cpu_sys_devices [ num ] = & cpu - > sysdev ;
2006-01-10 07:51:42 +03:00
# ifdef CONFIG_KEXEC
if ( ! error )
error = sysdev_create_file ( & cpu - > sysdev , & attr_crash_notes ) ;
# endif
2005-04-17 02:20:36 +04:00
return error ;
}
2006-03-08 10:53:25 +03:00
struct sys_device * get_cpu_sysdev ( unsigned cpu )
2005-10-31 01:59:49 +03:00
{
if ( cpu < NR_CPUS )
return cpu_sys_devices [ cpu ] ;
else
return NULL ;
}
EXPORT_SYMBOL_GPL ( get_cpu_sysdev ) ;
2005-04-17 02:20:36 +04:00
int __init cpu_dev_init ( void )
{
return sysdev_class_register ( & cpu_sysdev_class ) ;
}