2005-04-17 02:20:36 +04:00
# include <linux/smp.h>
# include <linux/timex.h>
# include <linux/string.h>
# include <linux/seq_file.h>
2005-12-02 21:43:20 +03:00
# include <linux/cpufreq.h>
2005-04-17 02:20:36 +04:00
/*
* Get CPU information for use by the procfs .
*/
2008-02-20 21:48:02 +03:00
# ifdef CONFIG_X86_32
2008-02-20 21:45:29 +03:00
static void show_cpuinfo_core ( struct seq_file * m , struct cpuinfo_x86 * c ,
unsigned int cpu )
{
# ifdef CONFIG_X86_HT
if ( c - > x86_max_cores * smp_num_siblings > 1 ) {
seq_printf ( m , " physical id \t : %d \n " , c - > phys_proc_id ) ;
seq_printf ( m , " siblings \t : %d \n " ,
cpus_weight ( per_cpu ( cpu_core_map , cpu ) ) ) ;
seq_printf ( m , " core id \t \t : %d \n " , c - > cpu_core_id ) ;
seq_printf ( m , " cpu cores \t : %d \n " , c - > booted_cores ) ;
2008-03-07 00:46:39 +03:00
seq_printf ( m , " apicid \t \t : %d \n " , c - > apicid ) ;
seq_printf ( m , " initial apicid \t : %d \n " , c - > initial_apicid ) ;
2008-02-20 21:45:29 +03:00
}
# endif
}
static void show_cpuinfo_misc ( struct seq_file * m , struct cpuinfo_x86 * c )
{
/*
* We use exception 16 if we have hardware math and we ' ve either seen
* it or the CPU claims it is internal
*/
int fpu_exception = c - > hard_math & & ( ignore_fpu_irq | | cpu_has_fpu ) ;
seq_printf ( m ,
" fdiv_bug \t : %s \n "
" hlt_bug \t \t : %s \n "
" f00f_bug \t : %s \n "
" coma_bug \t : %s \n "
" fpu \t \t : %s \n "
" fpu_exception \t : %s \n "
" cpuid level \t : %d \n "
" wp \t \t : %s \n " ,
c - > fdiv_bug ? " yes " : " no " ,
c - > hlt_works_ok ? " no " : " yes " ,
c - > f00f_bug ? " yes " : " no " ,
c - > coma_bug ? " yes " : " no " ,
c - > hard_math ? " yes " : " no " ,
fpu_exception ? " yes " : " no " ,
c - > cpuid_level ,
c - > wp_works_ok ? " yes " : " no " ) ;
}
2008-02-20 21:48:02 +03:00
# else
static void show_cpuinfo_core ( struct seq_file * m , struct cpuinfo_x86 * c ,
unsigned int cpu )
{
# ifdef CONFIG_SMP
if ( c - > x86_max_cores * smp_num_siblings > 1 ) {
seq_printf ( m , " physical id \t : %d \n " , c - > phys_proc_id ) ;
seq_printf ( m , " siblings \t : %d \n " ,
cpus_weight ( per_cpu ( cpu_core_map , cpu ) ) ) ;
seq_printf ( m , " core id \t \t : %d \n " , c - > cpu_core_id ) ;
seq_printf ( m , " cpu cores \t : %d \n " , c - > booted_cores ) ;
2008-03-06 12:13:34 +03:00
seq_printf ( m , " apicid \t \t : %d \n " , c - > apicid ) ;
2008-03-07 00:46:39 +03:00
seq_printf ( m , " initial apicid \t : %d \n " , c - > initial_apicid ) ;
2008-02-20 21:48:02 +03:00
}
# endif
}
static void show_cpuinfo_misc ( struct seq_file * m , struct cpuinfo_x86 * c )
{
seq_printf ( m ,
" fpu \t \t : yes \n "
" fpu_exception \t : yes \n "
" cpuid level \t : %d \n "
" wp \t \t : yes \n " ,
c - > cpuid_level ) ;
}
# endif
2008-02-20 21:45:29 +03:00
2005-04-17 02:20:36 +04:00
static int show_cpuinfo ( struct seq_file * m , void * v )
{
struct cpuinfo_x86 * c = v ;
2008-02-20 21:45:29 +03:00
unsigned int cpu = 0 ;
int i ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_SMP
2008-02-20 21:45:29 +03:00
cpu = c - > cpu_index ;
2005-04-17 02:20:36 +04:00
# endif
2008-02-20 21:45:29 +03:00
seq_printf ( m , " processor \t : %u \n "
" vendor_id \t : %s \n "
" cpu family \t : %d \n "
" model \t \t : %u \n "
" model name \t : %s \n " ,
cpu ,
c - > x86_vendor_id [ 0 ] ? c - > x86_vendor_id : " unknown " ,
c - > x86 ,
c - > x86_model ,
c - > x86_model_id [ 0 ] ? c - > x86_model_id : " unknown " ) ;
2005-04-17 02:20:36 +04:00
if ( c - > x86_mask | | c - > cpuid_level > = 0 )
seq_printf ( m , " stepping \t : %d \n " , c - > x86_mask ) ;
else
seq_printf ( m , " stepping \t : unknown \n " ) ;
2008-02-20 21:45:29 +03:00
if ( cpu_has ( c , X86_FEATURE_TSC ) ) {
unsigned int freq = cpufreq_quick_get ( cpu ) ;
2005-12-02 21:43:20 +03:00
if ( ! freq )
freq = cpu_khz ;
2005-06-23 11:08:34 +04:00
seq_printf ( m , " cpu MHz \t \t : %u.%03u \n " ,
2008-02-20 21:45:29 +03:00
freq / 1000 , ( freq % 1000 ) ) ;
2005-04-17 02:20:36 +04:00
}
/* Cache size */
if ( c - > x86_cache_size > = 0 )
seq_printf ( m , " cache size \t : %d KB \n " , c - > x86_cache_size ) ;
2008-02-20 21:45:29 +03:00
show_cpuinfo_core ( m , c , cpu ) ;
show_cpuinfo_misc ( m , c ) ;
seq_printf ( m , " flags \t \t : " ) ;
for ( i = 0 ; i < 32 * NCAPINTS ; i + + )
if ( cpu_has ( c , i ) & & x86_cap_flags [ i ] ! = NULL )
2005-04-17 02:20:36 +04:00
seq_printf ( m , " %s " , x86_cap_flags [ i ] ) ;
2008-02-20 21:47:12 +03:00
seq_printf ( m , " \n bogomips \t : %lu.%02lu \n " ,
c - > loops_per_jiffy / ( 500000 / HZ ) ,
( c - > loops_per_jiffy / ( 5000 / HZ ) ) % 100 ) ;
2008-02-20 21:48:02 +03:00
# ifdef CONFIG_X86_64
if ( c - > x86_tlbsize > 0 )
seq_printf ( m , " TLB size \t : %d 4K pages \n " , c - > x86_tlbsize ) ;
# endif
2008-02-20 21:47:12 +03:00
seq_printf ( m , " clflush size \t : %u \n " , c - > x86_clflush_size ) ;
2008-02-20 21:48:02 +03:00
# ifdef CONFIG_X86_64
seq_printf ( m , " cache_alignment \t : %d \n " , c - > x86_cache_alignment ) ;
seq_printf ( m , " address sizes \t : %u bits physical, %u bits virtual \n " ,
c - > x86_phys_bits , c - > x86_virt_bits ) ;
# endif
2008-02-20 21:47:12 +03:00
seq_printf ( m , " power management: " ) ;
for ( i = 0 ; i < 32 ; i + + ) {
2006-01-12 00:42:51 +03:00
if ( c - > x86_power & ( 1 < < i ) ) {
if ( i < ARRAY_SIZE ( x86_power_flags ) & &
x86_power_flags [ i ] )
seq_printf ( m , " %s%s " ,
x86_power_flags [ i ] [ 0 ] ? " " : " " ,
x86_power_flags [ i ] ) ;
else
seq_printf ( m , " [%d] " , i ) ;
}
2008-02-20 21:47:12 +03:00
}
2006-01-12 00:42:51 +03:00
2008-02-20 21:47:12 +03:00
seq_printf ( m , " \n \n " ) ;
2005-04-17 02:25:15 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
static void * c_start ( struct seq_file * m , loff_t * pos )
{
2007-10-19 22:35:04 +04:00
if ( * pos = = 0 ) /* just in case, cpu 0 is not the first */
2007-11-01 21:32:17 +03:00
* pos = first_cpu ( cpu_online_map ) ;
if ( ( * pos ) < NR_CPUS & & cpu_online ( * pos ) )
2007-10-19 22:35:04 +04:00
return & cpu_data ( * pos ) ;
return NULL ;
2005-04-17 02:20:36 +04:00
}
2008-02-20 21:45:29 +03:00
2005-04-17 02:20:36 +04:00
static void * c_next ( struct seq_file * m , void * v , loff_t * pos )
{
2007-11-01 21:32:17 +03:00
* pos = next_cpu ( * pos , cpu_online_map ) ;
2005-04-17 02:20:36 +04:00
return c_start ( m , pos ) ;
}
2008-02-20 21:45:29 +03:00
2005-04-17 02:20:36 +04:00
static void c_stop ( struct seq_file * m , void * v )
{
}
2008-02-20 21:45:29 +03:00
2008-01-30 15:33:32 +03:00
const struct seq_operations cpuinfo_op = {
2005-04-17 02:20:36 +04:00
. start = c_start ,
. next = c_next ,
. stop = c_stop ,
. show = show_cpuinfo ,
} ;