2007-06-03 01:41:44 +04:00
/* sysfs.c: Toplogy sysfs support code for sparc64.
*
* Copyright ( C ) 2007 David S . Miller < davem @ davemloft . net >
*/
# include <linux/sysdev.h>
# include <linux/cpu.h>
# include <linux/smp.h>
# include <linux/percpu.h>
# include <linux/init.h>
2007-06-04 10:38:09 +04:00
# include <asm/hypervisor.h>
# include <asm/spitfire.h>
static DEFINE_PER_CPU ( struct hv_mmu_statistics , mmu_stats ) __attribute__ ( ( aligned ( 64 ) ) ) ;
2007-06-03 01:41:44 +04:00
2007-06-04 10:38:09 +04:00
# define SHOW_MMUSTAT_ULONG(NAME) \
2008-07-01 20:48:41 +04:00
static ssize_t show_ # # NAME ( struct sys_device * dev , \
struct sysdev_attribute * attr , char * buf ) \
2007-06-03 07:46:36 +04:00
{ \
2007-06-04 10:38:09 +04:00
struct hv_mmu_statistics * p = & per_cpu ( mmu_stats , dev - > id ) ; \
return sprintf ( buf , " %lu \n " , p - > NAME ) ; \
} \
static SYSDEV_ATTR ( NAME , 0444 , show_ # # NAME , NULL )
SHOW_MMUSTAT_ULONG ( immu_tsb_hits_ctx0_8k_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_ticks_ctx0_8k_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_hits_ctx0_64k_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_ticks_ctx0_64k_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_hits_ctx0_4mb_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_ticks_ctx0_4mb_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_hits_ctx0_256mb_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_ticks_ctx0_256mb_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_hits_ctxnon0_8k_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_ticks_ctxnon0_8k_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_hits_ctxnon0_64k_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_ticks_ctxnon0_64k_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_hits_ctxnon0_4mb_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_ticks_ctxnon0_4mb_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_hits_ctxnon0_256mb_tte ) ;
SHOW_MMUSTAT_ULONG ( immu_tsb_ticks_ctxnon0_256mb_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_hits_ctx0_8k_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_ticks_ctx0_8k_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_hits_ctx0_64k_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_ticks_ctx0_64k_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_hits_ctx0_4mb_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_ticks_ctx0_4mb_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_hits_ctx0_256mb_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_ticks_ctx0_256mb_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_hits_ctxnon0_8k_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_ticks_ctxnon0_8k_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_hits_ctxnon0_64k_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_ticks_ctxnon0_64k_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_hits_ctxnon0_4mb_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_ticks_ctxnon0_4mb_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_hits_ctxnon0_256mb_tte ) ;
SHOW_MMUSTAT_ULONG ( dmmu_tsb_ticks_ctxnon0_256mb_tte ) ;
static struct attribute * mmu_stat_attrs [ ] = {
& attr_immu_tsb_hits_ctx0_8k_tte . attr ,
& attr_immu_tsb_ticks_ctx0_8k_tte . attr ,
& attr_immu_tsb_hits_ctx0_64k_tte . attr ,
& attr_immu_tsb_ticks_ctx0_64k_tte . attr ,
& attr_immu_tsb_hits_ctx0_4mb_tte . attr ,
& attr_immu_tsb_ticks_ctx0_4mb_tte . attr ,
& attr_immu_tsb_hits_ctx0_256mb_tte . attr ,
& attr_immu_tsb_ticks_ctx0_256mb_tte . attr ,
& attr_immu_tsb_hits_ctxnon0_8k_tte . attr ,
& attr_immu_tsb_ticks_ctxnon0_8k_tte . attr ,
& attr_immu_tsb_hits_ctxnon0_64k_tte . attr ,
& attr_immu_tsb_ticks_ctxnon0_64k_tte . attr ,
& attr_immu_tsb_hits_ctxnon0_4mb_tte . attr ,
& attr_immu_tsb_ticks_ctxnon0_4mb_tte . attr ,
& attr_immu_tsb_hits_ctxnon0_256mb_tte . attr ,
& attr_immu_tsb_ticks_ctxnon0_256mb_tte . attr ,
& attr_dmmu_tsb_hits_ctx0_8k_tte . attr ,
& attr_dmmu_tsb_ticks_ctx0_8k_tte . attr ,
& attr_dmmu_tsb_hits_ctx0_64k_tte . attr ,
& attr_dmmu_tsb_ticks_ctx0_64k_tte . attr ,
& attr_dmmu_tsb_hits_ctx0_4mb_tte . attr ,
& attr_dmmu_tsb_ticks_ctx0_4mb_tte . attr ,
& attr_dmmu_tsb_hits_ctx0_256mb_tte . attr ,
& attr_dmmu_tsb_ticks_ctx0_256mb_tte . attr ,
& attr_dmmu_tsb_hits_ctxnon0_8k_tte . attr ,
& attr_dmmu_tsb_ticks_ctxnon0_8k_tte . attr ,
& attr_dmmu_tsb_hits_ctxnon0_64k_tte . attr ,
& attr_dmmu_tsb_ticks_ctxnon0_64k_tte . attr ,
& attr_dmmu_tsb_hits_ctxnon0_4mb_tte . attr ,
& attr_dmmu_tsb_ticks_ctxnon0_4mb_tte . attr ,
& attr_dmmu_tsb_hits_ctxnon0_256mb_tte . attr ,
& attr_dmmu_tsb_ticks_ctxnon0_256mb_tte . attr ,
NULL ,
} ;
static struct attribute_group mmu_stat_group = {
. attrs = mmu_stat_attrs ,
. name = " mmu_stats " ,
} ;
/* XXX convert to rusty's on_one_cpu */
static unsigned long run_on_cpu ( unsigned long cpu ,
unsigned long ( * func ) ( unsigned long ) ,
unsigned long arg )
{
cpumask_t old_affinity = current - > cpus_allowed ;
unsigned long ret ;
/* should return -EINVAL to userspace */
if ( set_cpus_allowed ( current , cpumask_of_cpu ( cpu ) ) )
return 0 ;
ret = func ( arg ) ;
set_cpus_allowed ( current , old_affinity ) ;
return ret ;
}
static unsigned long read_mmustat_enable ( unsigned long junk )
{
unsigned long ra = 0 ;
sun4v_mmustat_info ( & ra ) ;
return ra ! = 0 ;
}
static unsigned long write_mmustat_enable ( unsigned long val )
{
unsigned long ra , orig_ra ;
if ( val )
ra = __pa ( & per_cpu ( mmu_stats , smp_processor_id ( ) ) ) ;
else
ra = 0UL ;
return sun4v_mmustat_conf ( ra , & orig_ra ) ;
}
2008-07-01 20:48:41 +04:00
static ssize_t show_mmustat_enable ( struct sys_device * s ,
struct sysdev_attribute * attr , char * buf )
2007-06-04 10:38:09 +04:00
{
unsigned long val = run_on_cpu ( s - > id , read_mmustat_enable , 0 ) ;
return sprintf ( buf , " %lx \n " , val ) ;
}
2008-07-01 20:48:41 +04:00
static ssize_t store_mmustat_enable ( struct sys_device * s ,
struct sysdev_attribute * attr , const char * buf ,
size_t count )
2007-06-04 10:38:09 +04:00
{
unsigned long val , err ;
int ret = sscanf ( buf , " %ld " , & val ) ;
if ( ret ! = 1 )
return - EINVAL ;
err = run_on_cpu ( s - > id , write_mmustat_enable , val ) ;
if ( err )
return - EIO ;
return count ;
}
static SYSDEV_ATTR ( mmustat_enable , 0644 , show_mmustat_enable , store_mmustat_enable ) ;
static int mmu_stats_supported ;
static int register_mmu_stats ( struct sys_device * s )
{
if ( ! mmu_stats_supported )
return 0 ;
sysdev_create_file ( s , & attr_mmustat_enable ) ;
return sysfs_create_group ( & s - > kobj , & mmu_stat_group ) ;
}
# ifdef CONFIG_HOTPLUG_CPU
static void unregister_mmu_stats ( struct sys_device * s )
{
if ( ! mmu_stats_supported )
return ;
sysfs_remove_group ( & s - > kobj , & mmu_stat_group ) ;
sysdev_remove_file ( s , & attr_mmustat_enable ) ;
}
# endif
# define SHOW_CPUDATA_ULONG_NAME(NAME, MEMBER) \
2008-07-01 20:48:41 +04:00
static ssize_t show_ # # NAME ( struct sys_device * dev , \
struct sysdev_attribute * attr , char * buf ) \
2007-06-04 10:38:09 +04:00
{ \
cpuinfo_sparc * c = & cpu_data ( dev - > id ) ; \
2007-06-03 07:46:36 +04:00
return sprintf ( buf , " %lu \n " , c - > MEMBER ) ; \
}
2007-06-04 10:38:09 +04:00
# define SHOW_CPUDATA_UINT_NAME(NAME, MEMBER) \
2008-07-01 20:48:41 +04:00
static ssize_t show_ # # NAME ( struct sys_device * dev , \
struct sysdev_attribute * attr , char * buf ) \
2007-06-03 07:46:36 +04:00
{ \
2007-06-04 10:38:09 +04:00
cpuinfo_sparc * c = & cpu_data ( dev - > id ) ; \
2007-06-03 07:46:36 +04:00
return sprintf ( buf , " %u \n " , c - > MEMBER ) ; \
}
2007-06-04 10:38:09 +04:00
SHOW_CPUDATA_ULONG_NAME ( clock_tick , clock_tick ) ;
SHOW_CPUDATA_UINT_NAME ( l1_dcache_size , dcache_size ) ;
SHOW_CPUDATA_UINT_NAME ( l1_dcache_line_size , dcache_line_size ) ;
SHOW_CPUDATA_UINT_NAME ( l1_icache_size , icache_size ) ;
SHOW_CPUDATA_UINT_NAME ( l1_icache_line_size , icache_line_size ) ;
SHOW_CPUDATA_UINT_NAME ( l2_cache_size , ecache_size ) ;
SHOW_CPUDATA_UINT_NAME ( l2_cache_line_size , ecache_line_size ) ;
2007-06-03 07:46:36 +04:00
static struct sysdev_attribute cpu_core_attrs [ ] = {
_SYSDEV_ATTR ( clock_tick , 0444 , show_clock_tick , NULL ) ,
_SYSDEV_ATTR ( l1_dcache_size , 0444 , show_l1_dcache_size , NULL ) ,
_SYSDEV_ATTR ( l1_dcache_line_size , 0444 , show_l1_dcache_line_size , NULL ) ,
_SYSDEV_ATTR ( l1_icache_size , 0444 , show_l1_icache_size , NULL ) ,
_SYSDEV_ATTR ( l1_icache_line_size , 0444 , show_l1_icache_line_size , NULL ) ,
_SYSDEV_ATTR ( l2_cache_size , 0444 , show_l2_cache_size , NULL ) ,
_SYSDEV_ATTR ( l2_cache_line_size , 0444 , show_l2_cache_line_size , NULL ) ,
} ;
2007-06-04 10:38:09 +04:00
static DEFINE_PER_CPU ( struct cpu , cpu_devices ) ;
2007-06-03 07:46:36 +04:00
static void register_cpu_online ( unsigned int cpu )
{
struct cpu * c = & per_cpu ( cpu_devices , cpu ) ;
struct sys_device * s = & c - > sysdev ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( cpu_core_attrs ) ; i + + )
sysdev_create_file ( s , & cpu_core_attrs [ i ] ) ;
2007-06-04 10:38:09 +04:00
register_mmu_stats ( s ) ;
2007-06-03 07:46:36 +04:00
}
# ifdef CONFIG_HOTPLUG_CPU
static void unregister_cpu_online ( unsigned int cpu )
{
struct cpu * c = & per_cpu ( cpu_devices , cpu ) ;
struct sys_device * s = & c - > sysdev ;
int i ;
2007-06-04 10:38:09 +04:00
unregister_mmu_stats ( s ) ;
2007-06-03 07:46:36 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( cpu_core_attrs ) ; i + + )
sysdev_remove_file ( s , & cpu_core_attrs [ i ] ) ;
}
# endif
static int __cpuinit sysfs_cpu_notify ( struct notifier_block * self ,
unsigned long action , void * hcpu )
{
unsigned int cpu = ( unsigned int ) ( long ) hcpu ;
switch ( action ) {
case CPU_ONLINE :
case CPU_ONLINE_FROZEN :
register_cpu_online ( cpu ) ;
break ;
# ifdef CONFIG_HOTPLUG_CPU
case CPU_DEAD :
case CPU_DEAD_FROZEN :
unregister_cpu_online ( cpu ) ;
break ;
# endif
}
return NOTIFY_OK ;
}
static struct notifier_block __cpuinitdata sysfs_cpu_nb = {
. notifier_call = sysfs_cpu_notify ,
} ;
2007-06-04 10:38:09 +04:00
static void __init check_mmu_stats ( void )
{
unsigned long dummy1 , err ;
if ( tlb_type ! = hypervisor )
return ;
err = sun4v_mmustat_info ( & dummy1 ) ;
if ( ! err )
mmu_stats_supported = 1 ;
}
2008-04-23 16:40:25 +04:00
static void register_nodes ( void )
{
# ifdef CONFIG_NUMA
int i ;
for ( i = 0 ; i < MAX_NUMNODES ; i + + )
register_one_node ( i ) ;
# endif
}
2007-06-03 01:41:44 +04:00
static int __init topology_init ( void )
{
int cpu ;
2008-04-23 16:40:25 +04:00
register_nodes ( ) ;
2007-06-04 10:38:09 +04:00
check_mmu_stats ( ) ;
2007-06-03 07:46:36 +04:00
register_cpu_notifier ( & sysfs_cpu_nb ) ;
2007-06-03 01:41:44 +04:00
for_each_possible_cpu ( cpu ) {
struct cpu * c = & per_cpu ( cpu_devices , cpu ) ;
register_cpu ( c , cpu ) ;
2007-06-03 07:46:36 +04:00
if ( cpu_online ( cpu ) )
register_cpu_online ( cpu ) ;
2007-06-03 01:41:44 +04:00
}
return 0 ;
}
subsys_initcall ( topology_init ) ;