2008-12-25 13:39:50 +01:00
/*
* Copyright IBM Corp . 2008
* Author ( s ) : Martin Schwidefsky ( schwidefsky @ de . ibm . com )
*/
# define KMSG_COMPONENT "cpu"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2016-05-07 12:15:34 +02:00
# include <linux/cpufeature.h>
2008-12-25 13:39:50 +01:00
# include <linux/kernel.h>
2017-02-01 19:08:20 +01:00
# include <linux/sched/mm.h>
2008-12-25 13:39:50 +01:00
# include <linux/init.h>
# include <linux/seq_file.h>
2017-02-04 00:16:44 +01:00
# include <linux/mm_types.h>
2008-12-25 13:39:50 +01:00
# include <linux/delay.h>
2011-01-05 12:48:17 +01:00
# include <linux/cpu.h>
2017-02-01 19:08:20 +01:00
2015-08-20 17:28:44 +02:00
# include <asm/diag.h>
2016-04-14 12:35:22 +02:00
# include <asm/facility.h>
2008-12-25 13:39:50 +01:00
# include <asm/elf.h>
# include <asm/lowcore.h>
# include <asm/param.h>
2015-01-28 07:43:56 +01:00
# include <asm/smp.h>
2008-12-25 13:39:50 +01:00
2016-04-14 12:35:22 +02:00
struct cpu_info {
unsigned int cpu_mhz_dynamic ;
unsigned int cpu_mhz_static ;
struct cpuid cpu_id ;
} ;
static DEFINE_PER_CPU ( struct cpu_info , cpu_info ) ;
static bool machine_has_cpu_mhz ;
void __init cpu_detect_mhz_feature ( void )
{
if ( test_facility ( 34 ) & & __ecag ( ECAG_CPU_ATTRIBUTE , 0 ) ! = - 1UL )
2017-01-02 09:59:40 +01:00
machine_has_cpu_mhz = true ;
2016-04-14 12:35:22 +02:00
}
static void update_cpu_mhz ( void * arg )
{
unsigned long mhz ;
struct cpu_info * c ;
mhz = __ecag ( ECAG_CPU_ATTRIBUTE , 0 ) ;
c = this_cpu_ptr ( & cpu_info ) ;
c - > cpu_mhz_dynamic = mhz > > 32 ;
c - > cpu_mhz_static = mhz & 0xffffffff ;
}
void s390_update_cpu_mhz ( void )
{
s390_adjust_jiffies ( ) ;
if ( machine_has_cpu_mhz )
on_each_cpu ( update_cpu_mhz , NULL , 0 ) ;
}
2010-05-17 10:00:00 +02:00
2016-10-25 11:03:11 +02:00
void notrace cpu_relax_yield ( void )
2015-01-28 07:43:56 +01:00
{
2015-08-20 17:28:44 +02:00
if ( ! smp_cpu_mtid & & MACHINE_HAS_DIAG44 ) {
diag_stat_inc ( DIAG_STAT_X044 ) ;
2015-01-28 07:43:56 +01:00
asm volatile ( " diag 0,0,0x44 " ) ;
2015-08-20 17:28:44 +02:00
}
2015-01-28 07:43:56 +01:00
barrier ( ) ;
}
2016-10-25 11:03:11 +02:00
EXPORT_SYMBOL ( cpu_relax_yield ) ;
2015-01-28 07:43:56 +01:00
2010-05-17 10:00:00 +02:00
/*
* cpu_init - initializes state that is per - CPU .
*/
2013-06-18 17:04:52 -04:00
void cpu_init ( void )
2010-05-17 10:00:00 +02:00
{
2016-04-14 12:35:22 +02:00
struct cpuid * id = this_cpu_ptr ( & cpu_info . cpu_id ) ;
2010-05-17 10:00:00 +02:00
get_cpu_id ( id ) ;
2016-04-14 12:35:22 +02:00
if ( machine_has_cpu_mhz )
update_cpu_mhz ( NULL ) ;
2017-02-27 14:30:07 -08:00
mmgrab ( & init_mm ) ;
2010-05-17 10:00:00 +02:00
current - > active_mm = & init_mm ;
BUG_ON ( current - > mm ) ;
enter_lazy_tlb ( & init_mm , current ) ;
}
2015-02-19 12:22:02 +01:00
/*
* cpu_have_feature - Test CPU features on module initialization
*/
int cpu_have_feature ( unsigned int num )
{
return elf_hwcap & ( 1UL < < num ) ;
}
EXPORT_SYMBOL ( cpu_have_feature ) ;
2016-04-14 08:57:19 +02:00
static void show_cpu_summary ( struct seq_file * m , void * v )
2008-12-25 13:39:50 +01:00
{
2012-08-29 14:54:38 +02:00
static const char * hwcap_str [ ] = {
2008-12-25 13:39:50 +01:00
" esan3 " , " zarch " , " stfle " , " msa " , " ldisp " , " eimm " , " dfp " ,
2016-03-31 09:55:17 +02:00
" edat " , " etf3eh " , " highgprs " , " te " , " vx " , " vxd " , " vxe "
2008-12-25 13:39:50 +01:00
} ;
2015-02-24 15:54:47 +01:00
static const char * const int_hwcap_str [ ] = {
" sie "
} ;
2016-04-14 08:57:19 +02:00
int i , cpu ;
seq_printf ( m , " vendor_id : IBM/S390 \n "
" # processors : %i \n "
" bogomips per cpu: %lu.%02lu \n " ,
num_online_cpus ( ) , loops_per_jiffy / ( 500000 / HZ ) ,
( loops_per_jiffy / ( 5000 / HZ ) ) % 100 ) ;
2016-06-27 13:19:22 +02:00
seq_printf ( m , " max thread id : %d \n " , smp_cpu_mtid ) ;
2016-04-14 08:57:19 +02:00
seq_puts ( m , " features \t : " ) ;
for ( i = 0 ; i < ARRAY_SIZE ( hwcap_str ) ; i + + )
if ( hwcap_str [ i ] & & ( elf_hwcap & ( 1UL < < i ) ) )
seq_printf ( m , " %s " , hwcap_str [ i ] ) ;
for ( i = 0 ; i < ARRAY_SIZE ( int_hwcap_str ) ; i + + )
if ( int_hwcap_str [ i ] & & ( int_hwcap & ( 1UL < < i ) ) )
seq_printf ( m , " %s " , int_hwcap_str [ i ] ) ;
seq_puts ( m , " \n " ) ;
show_cacheinfo ( m ) ;
for_each_online_cpu ( cpu ) {
2016-04-14 12:35:22 +02:00
struct cpuid * id = & per_cpu ( cpu_info . cpu_id , cpu ) ;
2016-04-14 08:57:19 +02:00
seq_printf ( m , " processor %d: "
2009-03-26 15:24:42 +01:00
" version = %02X, "
" identification = %06X, "
" machine = %04X \n " ,
2016-04-14 08:57:19 +02:00
cpu , id - > version , id - > ident , id - > machine ) ;
2009-03-26 15:24:42 +01:00
}
2016-04-14 08:57:19 +02:00
}
2016-04-14 12:35:22 +02:00
static void show_cpu_mhz ( struct seq_file * m , unsigned long n )
{
struct cpu_info * c = per_cpu_ptr ( & cpu_info , n ) ;
seq_printf ( m , " cpu MHz dynamic : %d \n " , c - > cpu_mhz_dynamic ) ;
seq_printf ( m , " cpu MHz static : %d \n " , c - > cpu_mhz_static ) ;
}
2016-04-14 08:57:19 +02:00
/*
* show_cpuinfo - Get information on one CPU for use by procfs .
*/
static int show_cpuinfo ( struct seq_file * m , void * v )
{
unsigned long n = ( unsigned long ) v - 1 ;
if ( ! n )
show_cpu_summary ( m , v ) ;
2016-04-14 12:35:22 +02:00
if ( ! machine_has_cpu_mhz )
return 0 ;
2016-06-21 11:05:05 +02:00
seq_printf ( m , " \n cpu number : %ld \n " , n ) ;
2016-04-14 12:35:22 +02:00
show_cpu_mhz ( m , n ) ;
2009-03-26 15:24:42 +01:00
return 0 ;
2008-12-25 13:39:50 +01:00
}
2016-04-13 14:49:12 +02:00
static inline void * c_update ( loff_t * pos )
{
if ( * pos )
* pos = cpumask_next ( * pos - 1 , cpu_online_mask ) ;
return * pos < nr_cpu_ids ? ( void * ) * pos + 1 : NULL ;
}
2008-12-25 13:39:50 +01:00
static void * c_start ( struct seq_file * m , loff_t * pos )
{
2016-04-13 14:49:12 +02:00
get_online_cpus ( ) ;
return c_update ( pos ) ;
2008-12-25 13:39:50 +01:00
}
static void * c_next ( struct seq_file * m , void * v , loff_t * pos )
{
+ + * pos ;
2016-04-13 14:49:12 +02:00
return c_update ( pos ) ;
2008-12-25 13:39:50 +01:00
}
static void c_stop ( struct seq_file * m , void * v )
{
2016-04-13 14:49:12 +02:00
put_online_cpus ( ) ;
2008-12-25 13:39:50 +01:00
}
const struct seq_operations cpuinfo_op = {
. start = c_start ,
. next = c_next ,
. stop = c_stop ,
. show = show_cpuinfo ,
} ;