2023-08-30 17:31:07 +02:00
// SPDX-License-Identifier: GPL-2.0
/*
* Intel Speed Select - - Enumerate and control features
* Copyright ( c ) 2019 Intel Corporation .
*/
# include <linux/isst_if.h>
# include "isst.h"
struct process_cmd_struct {
char * feature ;
char * command ;
void ( * process_fn ) ( int arg ) ;
int arg ;
} ;
2023-10-24 12:59:35 +02:00
static const char * version_str = " v1.16 " ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
static const int supported_api_ver = 2 ;
2023-08-30 17:31:07 +02:00
static struct isst_if_platform_info isst_platform_info ;
static char * progname ;
static int debug_flag ;
static FILE * outf ;
static int cpu_model ;
static int cpu_stepping ;
# define MAX_CPUS_IN_ONE_REQ 256
static short max_target_cpus ;
static unsigned short target_cpus [ MAX_CPUS_IN_ONE_REQ ] ;
static int topo_max_cpus ;
static size_t present_cpumask_size ;
static cpu_set_t * present_cpumask ;
static size_t target_cpumask_size ;
static cpu_set_t * target_cpumask ;
static int tdp_level = 0xFF ;
static int fact_bucket = 0xFF ;
static int fact_avx = 0xFF ;
static unsigned long long fact_trl ;
static int out_format_json ;
static int cmd_help ;
static int force_online_offline ;
static int auto_mode ;
static int fact_enable_fail ;
2023-10-24 12:59:35 +02:00
static int cgroupv2 ;
2023-08-30 17:31:07 +02:00
/* clos related */
static int current_clos = - 1 ;
static int clos_epp = - 1 ;
static int clos_prop_prio = - 1 ;
static int clos_min = - 1 ;
static int clos_max = - 1 ;
static int clos_desired = - 1 ;
static int clos_priority_type ;
struct _cpu_map {
unsigned short core_id ;
unsigned short pkg_id ;
unsigned short die_id ;
2023-10-24 12:59:35 +02:00
unsigned short punit_id ;
2023-08-30 17:31:07 +02:00
unsigned short punit_cpu ;
unsigned short punit_cpu_core ;
unsigned short initialized ;
} ;
struct _cpu_map * cpu_map ;
struct cpu_topology {
short cpu ;
short core_id ;
short pkg_id ;
short die_id ;
} ;
FILE * get_output_file ( void )
{
return outf ;
}
2023-10-24 12:59:35 +02:00
int is_debug_enabled ( void )
{
return debug_flag ;
}
2023-08-30 17:31:07 +02:00
void debug_printf ( const char * format , . . . )
{
va_list args ;
va_start ( args , format ) ;
if ( debug_flag )
vprintf ( format , args ) ;
va_end ( args ) ;
}
int is_clx_n_platform ( void )
{
if ( cpu_model = = 0x55 )
if ( cpu_stepping = = 0x6 | | cpu_stepping = = 0x7 )
return 1 ;
return 0 ;
}
int is_skx_based_platform ( void )
{
if ( cpu_model = = 0x55 )
return 1 ;
return 0 ;
}
int is_spr_platform ( void )
{
2023-10-24 12:59:35 +02:00
if ( cpu_model = = 0x8F )
return 1 ;
return 0 ;
}
int is_emr_platform ( void )
{
if ( cpu_model = = 0xCF )
2023-08-30 17:31:07 +02:00
return 1 ;
return 0 ;
}
2023-10-24 12:59:35 +02:00
2023-08-30 17:31:07 +02:00
int is_icx_platform ( void )
{
if ( cpu_model = = 0x6A | | cpu_model = = 0x6C )
return 1 ;
return 0 ;
}
static int update_cpu_model ( void )
{
unsigned int ebx , ecx , edx ;
unsigned int fms , family ;
__cpuid ( 1 , fms , ebx , ecx , edx ) ;
family = ( fms > > 8 ) & 0xf ;
cpu_model = ( fms > > 4 ) & 0xf ;
if ( family = = 6 | | family = = 0xf )
cpu_model + = ( ( fms > > 16 ) & 0xf ) < < 4 ;
cpu_stepping = fms & 0xf ;
/* only three CascadeLake-N models are supported */
if ( is_clx_n_platform ( ) ) {
FILE * fp ;
size_t n = 0 ;
char * line = NULL ;
int ret = 1 ;
fp = fopen ( " /proc/cpuinfo " , " r " ) ;
if ( ! fp )
err ( - 1 , " cannot open /proc/cpuinfo \n " ) ;
while ( getline ( & line , & n , fp ) > 0 ) {
if ( strstr ( line , " model name " ) ) {
if ( strstr ( line , " 6252N " ) | |
strstr ( line , " 6230N " ) | |
strstr ( line , " 5218N " ) )
ret = 0 ;
break ;
}
}
free ( line ) ;
fclose ( fp ) ;
return ret ;
}
return 0 ;
}
2023-10-24 12:59:35 +02:00
int api_version ( void )
{
return isst_platform_info . api_version ;
}
2023-08-30 17:31:07 +02:00
/* Open a file, and exit on failure */
static FILE * fopen_or_exit ( const char * path , const char * mode )
{
FILE * filep = fopen ( path , mode ) ;
if ( ! filep )
err ( 1 , " %s: open failed " , path ) ;
return filep ;
}
/* Parse a file containing a single int */
static int parse_int_file ( int fatal , const char * fmt , . . . )
{
va_list args ;
char path [ PATH_MAX ] ;
FILE * filep ;
int value ;
va_start ( args , fmt ) ;
vsnprintf ( path , sizeof ( path ) , fmt , args ) ;
va_end ( args ) ;
if ( fatal ) {
filep = fopen_or_exit ( path , " r " ) ;
} else {
filep = fopen ( path , " r " ) ;
if ( ! filep )
return - 1 ;
}
if ( fscanf ( filep , " %d " , & value ) ! = 1 )
err ( 1 , " %s: failed to parse number from file " , path ) ;
fclose ( filep ) ;
return value ;
}
int cpufreq_sysfs_present ( void )
{
DIR * dir ;
dir = opendir ( " /sys/devices/system/cpu/cpu0/cpufreq " ) ;
if ( dir ) {
closedir ( dir ) ;
return 1 ;
}
return 0 ;
}
int out_format_is_json ( void )
{
return out_format_json ;
}
static int get_stored_topology_info ( int cpu , int * core_id , int * pkg_id , int * die_id )
{
const char * pathname = " /var/run/isst_cpu_topology.dat " ;
struct cpu_topology cpu_top ;
FILE * fp ;
int ret ;
fp = fopen ( pathname , " rb " ) ;
if ( ! fp )
return - 1 ;
ret = fseek ( fp , cpu * sizeof ( cpu_top ) , SEEK_SET ) ;
if ( ret )
goto err_ret ;
ret = fread ( & cpu_top , sizeof ( cpu_top ) , 1 , fp ) ;
if ( ret ! = 1 ) {
ret = - 1 ;
goto err_ret ;
}
* pkg_id = cpu_top . pkg_id ;
* core_id = cpu_top . core_id ;
* die_id = cpu_top . die_id ;
ret = 0 ;
err_ret :
fclose ( fp ) ;
return ret ;
}
static void store_cpu_topology ( void )
{
const char * pathname = " /var/run/isst_cpu_topology.dat " ;
FILE * fp ;
int i ;
fp = fopen ( pathname , " rb " ) ;
if ( fp ) {
/* Mapping already exists */
fclose ( fp ) ;
return ;
}
fp = fopen ( pathname , " wb " ) ;
if ( ! fp ) {
fprintf ( stderr , " Can't create file:%s \n " , pathname ) ;
return ;
}
fprintf ( stderr , " Caching topology information \n " ) ;
for ( i = 0 ; i < topo_max_cpus ; + + i ) {
struct cpu_topology cpu_top ;
cpu_top . core_id = parse_int_file ( 0 ,
" /sys/devices/system/cpu/cpu%d/topology/core_id " , i ) ;
if ( cpu_top . core_id < 0 )
cpu_top . core_id = - 1 ;
cpu_top . pkg_id = parse_int_file ( 0 ,
" /sys/devices/system/cpu/cpu%d/topology/physical_package_id " , i ) ;
if ( cpu_top . pkg_id < 0 )
cpu_top . pkg_id = - 1 ;
cpu_top . die_id = parse_int_file ( 0 ,
" /sys/devices/system/cpu/cpu%d/topology/die_id " , i ) ;
if ( cpu_top . die_id < 0 )
cpu_top . die_id = - 1 ;
cpu_top . cpu = i ;
if ( fwrite ( & cpu_top , sizeof ( cpu_top ) , 1 , fp ) ! = 1 ) {
fprintf ( stderr , " Can't write to:%s \n " , pathname ) ;
break ;
}
}
fclose ( fp ) ;
}
static int get_physical_package_id ( int cpu )
{
int ret ;
if ( cpu < 0 )
return - 1 ;
if ( cpu_map & & cpu_map [ cpu ] . initialized )
return cpu_map [ cpu ] . pkg_id ;
ret = parse_int_file ( 0 ,
" /sys/devices/system/cpu/cpu%d/topology/physical_package_id " ,
cpu ) ;
if ( ret < 0 ) {
int core_id , pkg_id , die_id ;
ret = get_stored_topology_info ( cpu , & core_id , & pkg_id , & die_id ) ;
if ( ! ret )
return pkg_id ;
}
return ret ;
}
static int get_physical_core_id ( int cpu )
{
int ret ;
if ( cpu < 0 )
return - 1 ;
if ( cpu_map & & cpu_map [ cpu ] . initialized )
return cpu_map [ cpu ] . core_id ;
ret = parse_int_file ( 0 ,
" /sys/devices/system/cpu/cpu%d/topology/core_id " ,
cpu ) ;
if ( ret < 0 ) {
int core_id , pkg_id , die_id ;
ret = get_stored_topology_info ( cpu , & core_id , & pkg_id , & die_id ) ;
if ( ! ret )
return core_id ;
}
return ret ;
}
static int get_physical_die_id ( int cpu )
{
int ret ;
if ( cpu < 0 )
return - 1 ;
if ( cpu_map & & cpu_map [ cpu ] . initialized )
return cpu_map [ cpu ] . die_id ;
ret = parse_int_file ( 0 ,
" /sys/devices/system/cpu/cpu%d/topology/die_id " ,
cpu ) ;
if ( ret < 0 ) {
int core_id , pkg_id , die_id ;
ret = get_stored_topology_info ( cpu , & core_id , & pkg_id , & die_id ) ;
if ( ! ret ) {
if ( die_id < 0 )
die_id = 0 ;
return die_id ;
}
}
if ( ret < 0 )
ret = 0 ;
return ret ;
}
2023-10-24 12:59:35 +02:00
static int get_physical_punit_id ( int cpu )
{
if ( cpu < 0 )
return - 1 ;
if ( cpu_map & & cpu_map [ cpu ] . initialized )
return cpu_map [ cpu ] . punit_id ;
return - 1 ;
}
2023-08-30 17:31:07 +02:00
void set_isst_id ( struct isst_id * id , int cpu )
{
id - > cpu = cpu ;
id - > pkg = get_physical_package_id ( cpu ) ;
if ( id - > pkg > = MAX_PACKAGE_COUNT )
id - > pkg = - 1 ;
id - > die = get_physical_die_id ( cpu ) ;
if ( id - > die > = MAX_DIE_PER_PACKAGE )
id - > die = - 1 ;
2023-10-24 12:59:35 +02:00
id - > punit = get_physical_punit_id ( cpu ) ;
if ( id - > punit > = MAX_PUNIT_PER_DIE )
id - > punit = - 1 ;
2023-08-30 17:31:07 +02:00
}
int is_cpu_in_power_domain ( int cpu , struct isst_id * id )
{
struct isst_id tid ;
set_isst_id ( & tid , cpu ) ;
2023-10-24 12:59:35 +02:00
if ( id - > pkg = = tid . pkg & & id - > die = = tid . die & & id - > punit = = tid . punit )
2023-08-30 17:31:07 +02:00
return 1 ;
return 0 ;
}
int get_cpufreq_base_freq ( int cpu )
{
return parse_int_file ( 0 , " /sys/devices/system/cpu/cpu%d/cpufreq/base_frequency " , cpu ) ;
}
int get_topo_max_cpus ( void )
{
return topo_max_cpus ;
}
static unsigned int is_cpu_online ( int cpu )
{
char buffer [ 128 ] ;
int fd , ret ;
unsigned char online ;
snprintf ( buffer , sizeof ( buffer ) ,
" /sys/devices/system/cpu/cpu%d/online " , cpu ) ;
fd = open ( buffer , O_RDONLY ) ;
if ( fd < 0 )
return fd ;
ret = read ( fd , & online , sizeof ( online ) ) ;
close ( fd ) ;
if ( ret = = - 1 )
return ret ;
if ( online = = ' 1 ' )
online = 1 ;
else
online = 0 ;
return online ;
}
void set_cpu_online_offline ( int cpu , int state )
{
char buffer [ 128 ] ;
int fd , ret ;
snprintf ( buffer , sizeof ( buffer ) ,
" /sys/devices/system/cpu/cpu%d/online " , cpu ) ;
fd = open ( buffer , O_WRONLY ) ;
if ( fd < 0 ) {
if ( ! cpu & & state ) {
fprintf ( stderr , " This system is not configured for CPU 0 online/offline \n " ) ;
fprintf ( stderr , " Ignoring online request for CPU 0 as this is already online \n " ) ;
return ;
}
err ( - 1 , " %s open failed " , buffer ) ;
}
if ( state )
ret = write ( fd , " 1 \n " , 2 ) ;
else
ret = write ( fd , " 0 \n " , 2 ) ;
if ( ret = = - 1 )
perror ( " Online/Offline: Operation failed \n " ) ;
close ( fd ) ;
}
static void force_all_cpus_online ( void )
{
int i ;
fprintf ( stderr , " Forcing all CPUs online \n " ) ;
for ( i = 0 ; i < topo_max_cpus ; + + i )
set_cpu_online_offline ( i , 1 ) ;
unlink ( " /var/run/isst_cpu_topology.dat " ) ;
}
2023-10-24 12:59:35 +02:00
void for_each_online_power_domain_in_set ( void ( * callback ) ( struct isst_id * , void * , void * ,
2023-08-30 17:31:07 +02:00
void * , void * ) ,
void * arg1 , void * arg2 , void * arg3 ,
void * arg4 )
{
struct isst_id id ;
2023-10-24 12:59:35 +02:00
int cpus [ MAX_PACKAGE_COUNT ] [ MAX_DIE_PER_PACKAGE ] [ MAX_PUNIT_PER_DIE ] ;
int valid_mask [ MAX_PACKAGE_COUNT ] [ MAX_DIE_PER_PACKAGE ] = { 0 } ;
int i , j , k ;
memset ( cpus , - 1 , sizeof ( cpus ) ) ;
2023-08-30 17:31:07 +02:00
for ( i = 0 ; i < topo_max_cpus ; + + i ) {
2023-10-24 12:59:35 +02:00
int online ;
2023-08-30 17:31:07 +02:00
if ( ! CPU_ISSET_S ( i , present_cpumask_size , present_cpumask ) )
continue ;
2023-10-24 12:59:35 +02:00
online = parse_int_file (
i ! = 0 , " /sys/devices/system/cpu/cpu%d/online " , i ) ;
if ( online < 0 )
online = 1 ; /* online entry for CPU 0 needs some special configs */
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
if ( ! online )
2023-08-30 17:31:07 +02:00
continue ;
2023-10-24 12:59:35 +02:00
set_isst_id ( & id , i ) ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
if ( id . pkg < 0 | | id . die < 0 | | id . punit < 0 )
continue ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
valid_mask [ id . pkg ] [ id . die ] = 1 ;
if ( cpus [ id . pkg ] [ id . die ] [ id . punit ] = = - 1 )
cpus [ id . pkg ] [ id . die ] [ id . punit ] = i ;
}
for ( i = 0 ; i < MAX_PACKAGE_COUNT ; i + + ) {
for ( j = 0 ; j < MAX_DIE_PER_PACKAGE ; j + + ) {
/*
* Fix me :
* How to check a non - cpu die for a package / die with all cpu offlined ?
*/
if ( ! valid_mask [ i ] [ j ] )
continue ;
for ( k = 0 ; k < MAX_PUNIT_PER_DIE ; k + + ) {
id . cpu = cpus [ i ] [ j ] [ k ] ;
id . pkg = i ;
id . die = j ;
id . punit = k ;
if ( isst_is_punit_valid ( & id ) )
callback ( & id , arg1 , arg2 , arg3 , arg4 ) ;
}
2023-08-30 17:31:07 +02:00
}
}
}
static void for_each_online_target_cpu_in_set (
void ( * callback ) ( struct isst_id * , void * , void * , void * , void * ) , void * arg1 ,
void * arg2 , void * arg3 , void * arg4 )
{
int i , found = 0 ;
struct isst_id id ;
for ( i = 0 ; i < topo_max_cpus ; + + i ) {
int online ;
if ( ! CPU_ISSET_S ( i , target_cpumask_size , target_cpumask ) )
continue ;
if ( i )
online = parse_int_file (
1 , " /sys/devices/system/cpu/cpu%d/online " , i ) ;
else
online =
1 ; /* online entry for CPU 0 needs some special configs */
set_isst_id ( & id , i ) ;
if ( online & & callback ) {
callback ( & id , arg1 , arg2 , arg3 , arg4 ) ;
found = 1 ;
}
}
if ( ! found )
fprintf ( stderr , " No valid CPU in the list \n " ) ;
}
# define BITMASK_SIZE 32
static void set_max_cpu_num ( void )
{
FILE * filep ;
unsigned long dummy ;
int i ;
topo_max_cpus = 0 ;
for ( i = 0 ; i < 256 ; + + i ) {
char path [ 256 ] ;
snprintf ( path , sizeof ( path ) ,
" /sys/devices/system/cpu/cpu%d/topology/thread_siblings " , i ) ;
filep = fopen ( path , " r " ) ;
if ( filep )
break ;
}
if ( ! filep ) {
fprintf ( stderr , " Can't get max cpu number \n " ) ;
exit ( 0 ) ;
}
while ( fscanf ( filep , " %lx, " , & dummy ) = = 1 )
topo_max_cpus + = BITMASK_SIZE ;
fclose ( filep ) ;
debug_printf ( " max cpus %d \n " , topo_max_cpus ) ;
}
size_t alloc_cpu_set ( cpu_set_t * * cpu_set )
{
cpu_set_t * _cpu_set ;
size_t size ;
_cpu_set = CPU_ALLOC ( ( topo_max_cpus + 1 ) ) ;
if ( _cpu_set = = NULL )
err ( 3 , " CPU_ALLOC " ) ;
size = CPU_ALLOC_SIZE ( ( topo_max_cpus + 1 ) ) ;
CPU_ZERO_S ( size , _cpu_set ) ;
* cpu_set = _cpu_set ;
return size ;
}
void free_cpu_set ( cpu_set_t * cpu_set )
{
CPU_FREE ( cpu_set ) ;
}
2023-10-24 12:59:35 +02:00
static int cpu_cnt [ MAX_PACKAGE_COUNT ] [ MAX_DIE_PER_PACKAGE ] [ MAX_PUNIT_PER_DIE ] ;
2023-08-30 17:31:07 +02:00
int get_max_punit_core_id ( struct isst_id * id )
{
int max_id = 0 ;
int i ;
for ( i = 0 ; i < topo_max_cpus ; + + i )
{
if ( ! CPU_ISSET_S ( i , present_cpumask_size , present_cpumask ) )
continue ;
if ( is_cpu_in_power_domain ( i , id ) & &
cpu_map [ i ] . punit_cpu_core > max_id )
max_id = cpu_map [ i ] . punit_cpu_core ;
}
return max_id ;
}
int get_cpu_count ( struct isst_id * id )
{
2023-10-24 12:59:35 +02:00
if ( id - > pkg < 0 | | id - > die < 0 | | id - > punit < 0 )
2023-08-30 17:31:07 +02:00
return 0 ;
2023-10-24 12:59:35 +02:00
return cpu_cnt [ id - > pkg ] [ id - > die ] [ id - > punit ] ;
}
static void update_punit_cpu_info ( __u32 physical_cpu , struct _cpu_map * cpu_map )
{
if ( api_version ( ) > 1 ) {
/*
* MSR 0x54 format
* [ 15 : 11 ] PM_DOMAIN_ID
* [ 10 : 3 ] MODULE_ID ( aka IDI_AGENT_ID )
* [ 2 : 0 ] LP_ID ( We don ' t care about these bits we only
* care die and core id
* For Atom :
* [ 2 ] Always 0
* [ 1 : 0 ] core ID within module
* For Core
* [ 2 : 1 ] Always 0
* [ 0 ] thread ID
*/
cpu_map - > punit_id = ( physical_cpu > > 11 ) & 0x1f ;
cpu_map - > punit_cpu_core = ( physical_cpu > > 3 ) & 0xff ;
cpu_map - > punit_cpu = physical_cpu & 0x7ff ;
} else {
int punit_id ;
/*
* MSR 0x53 format
* Format
* Bit 0 – thread ID
* Bit 8 : 1 – core ID
* Bit 13 : 9 – punit ID
*/
cpu_map - > punit_cpu = physical_cpu & 0x1ff ;
cpu_map - > punit_cpu_core = ( cpu_map - > punit_cpu > > 1 ) ; // shift to get core id
punit_id = ( physical_cpu > > 9 ) & 0x1f ;
if ( punit_id > = MAX_PUNIT_PER_DIE )
punit_id = 0 ;
cpu_map - > punit_id = punit_id ;
}
2023-08-30 17:31:07 +02:00
}
static void create_cpu_map ( void )
{
const char * pathname = " /dev/isst_interface " ;
size_t size ;
DIR * dir ;
int i , fd = 0 ;
struct isst_if_cpu_maps map ;
/* Use calloc to make sure the memory is initialized to Zero */
cpu_map = calloc ( topo_max_cpus , sizeof ( * cpu_map ) ) ;
if ( ! cpu_map )
err ( 3 , " cpumap " ) ;
fd = open ( pathname , O_RDWR ) ;
if ( fd < 0 & & ! is_clx_n_platform ( ) )
err ( - 1 , " %s open failed " , pathname ) ;
size = alloc_cpu_set ( & present_cpumask ) ;
present_cpumask_size = size ;
for ( i = 0 ; i < topo_max_cpus ; + + i ) {
char buffer [ 256 ] ;
2023-10-24 12:59:35 +02:00
int pkg_id , die_id , core_id , punit_id ;
2023-08-30 17:31:07 +02:00
/* check if CPU is online */
snprintf ( buffer , sizeof ( buffer ) ,
" /sys/devices/system/cpu/cpu%d " , i ) ;
dir = opendir ( buffer ) ;
if ( ! dir )
continue ;
closedir ( dir ) ;
CPU_SET_S ( i , size , present_cpumask ) ;
pkg_id = get_physical_package_id ( i ) ;
die_id = get_physical_die_id ( i ) ;
core_id = get_physical_core_id ( i ) ;
if ( pkg_id < 0 | | die_id < 0 | | core_id < 0 )
continue ;
cpu_map [ i ] . pkg_id = pkg_id ;
cpu_map [ i ] . die_id = die_id ;
cpu_map [ i ] . core_id = core_id ;
2023-10-24 12:59:35 +02:00
punit_id = 0 ;
if ( fd > = 0 ) {
map . cmd_count = 1 ;
map . cpu_map [ 0 ] . logical_cpu = i ;
debug_printf ( " map logical_cpu:%d \n " ,
map . cpu_map [ 0 ] . logical_cpu ) ;
if ( ioctl ( fd , ISST_IF_GET_PHY_ID , & map ) = = - 1 ) {
perror ( " ISST_IF_GET_PHY_ID " ) ;
fprintf ( outf , " Error: map logical_cpu:%d \n " ,
map . cpu_map [ 0 ] . logical_cpu ) ;
} else {
update_punit_cpu_info ( map . cpu_map [ 0 ] . physical_cpu , & cpu_map [ i ] ) ;
}
2023-08-30 17:31:07 +02:00
}
2023-10-24 12:59:35 +02:00
cpu_map [ i ] . initialized = 1 ;
cpu_cnt [ pkg_id ] [ die_id ] [ punit_id ] + + ;
2023-08-30 17:31:07 +02:00
debug_printf (
2023-10-24 12:59:35 +02:00
" map logical_cpu:%d core: %d die:%d pkg:%d punit:%d punit_cpu:%d punit_core:%d \n " ,
2023-08-30 17:31:07 +02:00
i , cpu_map [ i ] . core_id , cpu_map [ i ] . die_id ,
2023-10-24 12:59:35 +02:00
cpu_map [ i ] . pkg_id , cpu_map [ i ] . punit_id ,
cpu_map [ i ] . punit_cpu , cpu_map [ i ] . punit_cpu_core ) ;
2023-08-30 17:31:07 +02:00
}
if ( fd > = 0 )
close ( fd ) ;
size = alloc_cpu_set ( & target_cpumask ) ;
target_cpumask_size = size ;
for ( i = 0 ; i < max_target_cpus ; + + i ) {
if ( ! CPU_ISSET_S ( target_cpus [ i ] , present_cpumask_size ,
present_cpumask ) )
continue ;
CPU_SET_S ( target_cpus [ i ] , size , target_cpumask ) ;
}
}
void set_cpu_mask_from_punit_coremask ( struct isst_id * id , unsigned long long core_mask ,
size_t core_cpumask_size ,
cpu_set_t * core_cpumask , int * cpu_cnt )
{
int i , cnt = 0 ;
2023-10-24 12:59:35 +02:00
if ( id - > cpu < 0 )
return ;
2023-08-30 17:31:07 +02:00
* cpu_cnt = 0 ;
for ( i = 0 ; i < 64 ; + + i ) {
if ( core_mask & BIT_ULL ( i ) ) {
int j ;
for ( j = 0 ; j < topo_max_cpus ; + + j ) {
if ( ! CPU_ISSET_S ( j , present_cpumask_size , present_cpumask ) )
continue ;
if ( is_cpu_in_power_domain ( j , id ) & &
cpu_map [ j ] . punit_cpu_core = = i ) {
CPU_SET_S ( j , core_cpumask_size ,
core_cpumask ) ;
+ + cnt ;
}
}
}
}
* cpu_cnt = cnt ;
}
int find_phy_core_num ( int logical_cpu )
{
if ( logical_cpu < topo_max_cpus )
return cpu_map [ logical_cpu ] . punit_cpu_core ;
return - EINVAL ;
}
2023-10-24 12:59:35 +02:00
int use_cgroupv2 ( void )
2023-08-30 17:31:07 +02:00
{
2023-10-24 12:59:35 +02:00
return cgroupv2 ;
}
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
int enable_cpuset_controller ( void )
{
int fd , ret ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
fd = open ( " /sys/fs/cgroup/cgroup.subtree_control " , O_RDWR , 0 ) ;
if ( fd < 0 ) {
debug_printf ( " Can't activate cpuset controller \n " ) ;
debug_printf ( " Either you are not root user or CGroup v2 is not supported \n " ) ;
return fd ;
2023-08-30 17:31:07 +02:00
}
2023-10-24 12:59:35 +02:00
ret = write ( fd , " +cpuset " , strlen ( " +cpuset " ) ) ;
close ( fd ) ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
if ( ret = = - 1 ) {
debug_printf ( " Can't activate cpuset controller: Write failed \n " ) ;
return ret ;
2023-08-30 17:31:07 +02:00
}
return 0 ;
}
2023-10-24 12:59:35 +02:00
int isolate_cpus ( struct isst_id * id , int mask_size , cpu_set_t * cpu_mask , int level )
2023-08-30 17:31:07 +02:00
{
2023-10-24 12:59:35 +02:00
int i , first , curr_index , index , ret , fd ;
static char str [ 512 ] , dir_name [ 64 ] ;
static char cpuset_cpus [ 128 ] ;
int str_len = sizeof ( str ) ;
DIR * dir ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
snprintf ( dir_name , sizeof ( dir_name ) , " /sys/fs/cgroup/%d-%d-%d " , id - > pkg , id - > die , id - > punit ) ;
dir = opendir ( dir_name ) ;
if ( ! dir ) {
ret = mkdir ( dir_name , 0744 ) ;
if ( ret ) {
debug_printf ( " Can't create dir:%s errno:%d \n " , dir_name , errno ) ;
return ret ;
}
}
closedir ( dir ) ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
if ( ! level ) {
sprintf ( cpuset_cpus , " %s/cpuset.cpus.partition " , dir_name ) ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
fd = open ( cpuset_cpus , O_RDWR , 0 ) ;
if ( fd < 0 ) {
return fd ;
2023-08-30 17:31:07 +02:00
}
2023-10-24 12:59:35 +02:00
ret = write ( fd , " member " , strlen ( " member " ) ) ;
if ( ret = = - 1 ) {
printf ( " Can't update to member \n " ) ;
return ret ;
2023-08-30 17:31:07 +02:00
}
2023-10-24 12:59:35 +02:00
return 0 ;
}
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
if ( ! CPU_COUNT_S ( mask_size , cpu_mask ) ) {
return - 1 ;
}
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
curr_index = 0 ;
first = 1 ;
str [ 0 ] = ' \0 ' ;
for ( i = 0 ; i < get_topo_max_cpus ( ) ; + + i ) {
if ( ! is_cpu_in_power_domain ( i , id ) )
continue ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
if ( CPU_ISSET_S ( i , mask_size , cpu_mask ) )
continue ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
if ( ! first ) {
index = snprintf ( & str [ curr_index ] ,
str_len - curr_index , " , " ) ;
curr_index + = index ;
if ( curr_index > = str_len )
break ;
2023-08-30 17:31:07 +02:00
}
2023-10-24 12:59:35 +02:00
index = snprintf ( & str [ curr_index ] , str_len - curr_index , " %d " ,
i ) ;
curr_index + = index ;
if ( curr_index > = str_len )
break ;
first = 0 ;
}
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
debug_printf ( " isolated CPUs list: package:%d curr_index:%d [%s] \n " , id - > pkg , curr_index , str ) ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
snprintf ( cpuset_cpus , sizeof ( cpuset_cpus ) , " %s/cpuset.cpus " , dir_name ) ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
fd = open ( cpuset_cpus , O_RDWR , 0 ) ;
if ( fd < 0 ) {
return fd ;
2023-08-30 17:31:07 +02:00
}
2023-10-24 12:59:35 +02:00
ret = write ( fd , str , strlen ( str ) ) ;
close ( fd ) ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
if ( ret = = - 1 ) {
debug_printf ( " Can't activate cpuset controller: Write failed \n " ) ;
return ret ;
}
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
snprintf ( cpuset_cpus , sizeof ( cpuset_cpus ) , " %s/cpuset.cpus.partition " , dir_name ) ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
fd = open ( cpuset_cpus , O_RDWR , 0 ) ;
if ( fd < 0 ) {
return fd ;
}
ret = write ( fd , " isolated " , strlen ( " isolated " ) ) ;
if ( ret = = - 1 ) {
debug_printf ( " Can't update to isolated \n " ) ;
ret = write ( fd , " root " , strlen ( " root " ) ) ;
if ( ret = = - 1 )
debug_printf ( " Can't update to root \n " ) ;
2023-08-30 17:31:07 +02:00
}
close ( fd ) ;
2023-10-24 12:59:35 +02:00
if ( ret < 0 )
return ret ;
2023-08-30 17:31:07 +02:00
return 0 ;
}
static int isst_fill_platform_info ( void )
{
const char * pathname = " /dev/isst_interface " ;
int fd ;
2023-10-24 12:59:35 +02:00
if ( is_clx_n_platform ( ) ) {
isst_platform_info . api_version = 1 ;
goto set_platform_ops ;
}
2023-08-30 17:31:07 +02:00
fd = open ( pathname , O_RDWR ) ;
if ( fd < 0 )
err ( - 1 , " %s open failed " , pathname ) ;
if ( ioctl ( fd , ISST_IF_GET_PLATFORM_INFO , & isst_platform_info ) = = - 1 ) {
perror ( " ISST_IF_GET_PLATFORM_INFO " ) ;
close ( fd ) ;
return - 1 ;
}
close ( fd ) ;
if ( isst_platform_info . api_version > supported_api_ver ) {
printf ( " Incompatible API versions; Upgrade of tool is required \n " ) ;
return - 1 ;
}
2023-10-24 12:59:35 +02:00
set_platform_ops :
if ( isst_set_platform_ops ( isst_platform_info . api_version ) ) {
fprintf ( stderr , " Failed to set platform callbacks \n " ) ;
exit ( 0 ) ;
}
2023-08-30 17:31:07 +02:00
return 0 ;
}
2023-10-24 12:59:35 +02:00
void get_isst_status ( struct isst_id * id , void * arg1 , void * arg2 , void * arg3 , void * arg4 )
2023-08-30 17:31:07 +02:00
{
struct isst_pkg_ctdp pkg_dev ;
2023-10-24 12:59:35 +02:00
struct isst_id * tid = ( struct isst_id * ) arg2 ;
int * mask = ( int * ) arg3 ;
int * max_level = ( int * ) arg4 ;
int j , ret ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
/* Only check the first cpu power domain */
if ( id - > cpu < 0 | | tid - > cpu > = 0 )
2023-08-30 17:31:07 +02:00
return ;
2023-10-24 12:59:35 +02:00
ret = isst_get_ctdp_levels ( id , & pkg_dev ) ;
2023-08-30 17:31:07 +02:00
if ( ret )
return ;
2023-10-24 12:59:35 +02:00
if ( pkg_dev . enabled )
* mask | = BIT ( 0 ) ;
2023-08-30 17:31:07 +02:00
if ( pkg_dev . locked )
2023-10-24 12:59:35 +02:00
* mask | = BIT ( 1 ) ;
if ( * max_level < pkg_dev . levels )
* max_level = pkg_dev . levels ;
2023-08-30 17:31:07 +02:00
for ( j = 0 ; j < = pkg_dev . levels ; + + j ) {
2023-10-24 12:59:35 +02:00
struct isst_pkg_ctdp_level_info ctdp_level ;
ret = isst_get_ctdp_control ( id , j , & ctdp_level ) ;
2023-08-30 17:31:07 +02:00
if ( ret )
continue ;
2023-10-24 12:59:35 +02:00
if ( ctdp_level . fact_support )
* mask | = BIT ( 2 ) ;
if ( ctdp_level . pbf_support )
* mask | = BIT ( 3 ) ;
}
tid - > cpu = id - > cpu ;
tid - > pkg = id - > pkg ;
tid - > die = id - > die ;
tid - > punit = id - > punit ;
}
static void isst_print_extended_platform_info ( void )
{
int cp_state , cp_cap ;
struct isst_id id ;
int mask = 0 , max_level = 0 ;
id . cpu = - 1 ;
for_each_online_power_domain_in_set ( get_isst_status , NULL , & id , & mask , & max_level ) ;
2023-08-30 17:31:07 +02:00
2023-10-24 12:59:35 +02:00
if ( mask & BIT ( 0 ) ) {
fprintf ( outf , " Intel(R) SST-PP (feature perf-profile) is supported \n " ) ;
} else {
fprintf ( outf , " Intel(R) SST-PP (feature perf-profile) is not supported \n " ) ;
fprintf ( outf , " Only performance level 0 (base level) is present \n " ) ;
2023-08-30 17:31:07 +02:00
}
2023-10-24 12:59:35 +02:00
if ( mask & BIT ( 1 ) )
fprintf ( outf , " TDP level change control is locked \n " ) ;
else
fprintf ( outf , " TDP level change control is unlocked, max level: %d \n " , max_level ) ;
if ( mask & BIT ( 2 ) )
2023-08-30 17:31:07 +02:00
fprintf ( outf , " Intel(R) SST-TF (feature turbo-freq) is supported \n " ) ;
else
fprintf ( outf , " Intel(R) SST-TF (feature turbo-freq) is not supported \n " ) ;
2023-10-24 12:59:35 +02:00
if ( mask & BIT ( 3 ) )
2023-08-30 17:31:07 +02:00
fprintf ( outf , " Intel(R) SST-BF (feature base-freq) is supported \n " ) ;
else
fprintf ( outf , " Intel(R) SST-BF (feature base-freq) is not supported \n " ) ;
2023-10-24 12:59:35 +02:00
if ( isst_read_pm_config ( & id , & cp_state , & cp_cap ) ) {
2023-08-30 17:31:07 +02:00
fprintf ( outf , " Intel(R) SST-CP (feature core-power) status is unknown \n " ) ;
return ;
}
2023-10-24 12:59:35 +02:00
2023-08-30 17:31:07 +02:00
if ( cp_cap )
fprintf ( outf , " Intel(R) SST-CP (feature core-power) is supported \n " ) ;
else
fprintf ( outf , " Intel(R) SST-CP (feature core-power) is not supported \n " ) ;
}
static void isst_print_platform_information ( void )
{
if ( is_clx_n_platform ( ) ) {
fprintf ( stderr , " \n This option in not supported on this platform \n " ) ;
exit ( 0 ) ;
}
/* Early initialization to create working cpu_map */
set_max_cpu_num ( ) ;
create_cpu_map ( ) ;
2023-10-24 12:59:35 +02:00
fprintf ( outf , " Platform: API version : %d \n " ,
isst_platform_info . api_version ) ;
fprintf ( outf , " Platform: Driver version : %d \n " ,
isst_platform_info . driver_version ) ;
fprintf ( outf , " Platform: mbox supported : %d \n " ,
isst_platform_info . mbox_supported ) ;
fprintf ( outf , " Platform: mmio supported : %d \n " ,
isst_platform_info . mmio_supported ) ;
isst_print_extended_platform_info ( ) ;
2023-08-30 17:31:07 +02:00
exit ( 0 ) ;
}
static char * local_str0 , * local_str1 ;
static void exec_on_get_ctdp_cpu ( struct isst_id * id , void * arg1 , void * arg2 , void * arg3 ,
void * arg4 )
{
int ( * fn_ptr ) ( struct isst_id * id , void * arg ) ;
int ret ;
fn_ptr = arg1 ;
ret = fn_ptr ( id , arg2 ) ;
if ( ret )
isst_display_error_info_message ( 1 , " get_tdp_* failed " , 0 , 0 ) ;
else
isst_ctdp_display_core_info ( id , outf , arg3 ,
* ( unsigned int * ) arg4 ,
local_str0 , local_str1 ) ;
}
# define _get_tdp_level(desc, suffix, object, help, str0, str1) \
static void get_tdp_ # # object ( int arg ) \
{ \
struct isst_pkg_ctdp ctdp ; \
\
if ( cmd_help ) { \
fprintf ( stderr , \
" Print %s [No command arguments are required] \n " , \
help ) ; \
exit ( 0 ) ; \
} \
local_str0 = str0 ; \
local_str1 = str1 ; \
isst_ctdp_display_information_start ( outf ) ; \
if ( max_target_cpus ) \
for_each_online_target_cpu_in_set ( \
exec_on_get_ctdp_cpu , isst_get_ctdp_ # # suffix , \
& ctdp , desc , & ctdp . object ) ; \
else \
2023-10-24 12:59:35 +02:00
for_each_online_power_domain_in_set ( exec_on_get_ctdp_cpu , \
2023-08-30 17:31:07 +02:00
isst_get_ctdp_ # # suffix , \
& ctdp , desc , \
& ctdp . object ) ; \
isst_ctdp_display_information_end ( outf ) ; \
}
_get_tdp_level ( " get-config-levels " , levels , levels , " Max TDP level " , NULL , NULL ) ;
_get_tdp_level ( " get-config-version " , levels , version , " TDP version " , NULL , NULL ) ;
_get_tdp_level ( " get-config-enabled " , levels , enabled , " perf-profile enable status " , " disabled " , " enabled " ) ;
_get_tdp_level ( " get-config-current_level " , levels , current_level ,
" Current TDP Level " , NULL , NULL ) ;
_get_tdp_level ( " get-lock-status " , levels , locked , " TDP lock status " , " unlocked " , " locked " ) ;
struct isst_pkg_ctdp clx_n_pkg_dev ;
static int clx_n_get_base_ratio ( void )
{
FILE * fp ;
char * begin , * end , * line = NULL ;
char number [ 5 ] ;
float value = 0 ;
size_t n = 0 ;
fp = fopen ( " /proc/cpuinfo " , " r " ) ;
if ( ! fp )
err ( - 1 , " cannot open /proc/cpuinfo \n " ) ;
while ( getline ( & line , & n , fp ) > 0 ) {
if ( strstr ( line , " model name " ) ) {
/* this is true for CascadeLake-N */
begin = strstr ( line , " @ " ) + 2 ;
end = strstr ( line , " GHz " ) ;
strncpy ( number , begin , end - begin ) ;
value = atof ( number ) * 10 ;
break ;
}
}
free ( line ) ;
fclose ( fp ) ;
return ( int ) ( value ) ;
}
static int clx_n_config ( struct isst_id * id )
{
int i , ret ;
unsigned long cpu_bf ;
struct isst_pkg_ctdp_level_info * ctdp_level ;
struct isst_pbf_info * pbf_info ;
ctdp_level = & clx_n_pkg_dev . ctdp_level [ 0 ] ;
pbf_info = & ctdp_level - > pbf_info ;
ctdp_level - > core_cpumask_size =
alloc_cpu_set ( & ctdp_level - > core_cpumask ) ;
/* find the frequency base ratio */
ctdp_level - > tdp_ratio = clx_n_get_base_ratio ( ) ;
if ( ctdp_level - > tdp_ratio = = 0 ) {
debug_printf ( " CLX: cn base ratio is zero \n " ) ;
ret = - 1 ;
goto error_ret ;
}
/* find the high and low priority frequencies */
pbf_info - > p1_high = 0 ;
pbf_info - > p1_low = ~ 0 ;
for ( i = 0 ; i < topo_max_cpus ; i + + ) {
if ( ! CPU_ISSET_S ( i , present_cpumask_size , present_cpumask ) )
continue ;
if ( ! is_cpu_in_power_domain ( i , id ) )
continue ;
CPU_SET_S ( i , ctdp_level - > core_cpumask_size ,
ctdp_level - > core_cpumask ) ;
cpu_bf = parse_int_file ( 1 ,
" /sys/devices/system/cpu/cpu%d/cpufreq/base_frequency " ,
i ) ;
if ( cpu_bf > pbf_info - > p1_high )
pbf_info - > p1_high = cpu_bf ;
if ( cpu_bf < pbf_info - > p1_low )
pbf_info - > p1_low = cpu_bf ;
}
if ( pbf_info - > p1_high = = ~ 0UL ) {
debug_printf ( " CLX: maximum base frequency not set \n " ) ;
ret = - 1 ;
goto error_ret ;
}
if ( pbf_info - > p1_low = = 0 ) {
debug_printf ( " CLX: minimum base frequency not set \n " ) ;
ret = - 1 ;
goto error_ret ;
}
/* convert frequencies back to ratios */
pbf_info - > p1_high = pbf_info - > p1_high / 100000 ;
pbf_info - > p1_low = pbf_info - > p1_low / 100000 ;
/* create high priority cpu mask */
pbf_info - > core_cpumask_size = alloc_cpu_set ( & pbf_info - > core_cpumask ) ;
for ( i = 0 ; i < topo_max_cpus ; i + + ) {
if ( ! CPU_ISSET_S ( i , present_cpumask_size , present_cpumask ) )
continue ;
if ( ! is_cpu_in_power_domain ( i , id ) )
continue ;
cpu_bf = parse_int_file ( 1 ,
" /sys/devices/system/cpu/cpu%d/cpufreq/base_frequency " ,
i ) ;
cpu_bf = cpu_bf / 100000 ;
if ( cpu_bf = = pbf_info - > p1_high )
CPU_SET_S ( i , pbf_info - > core_cpumask_size ,
pbf_info - > core_cpumask ) ;
}
/* extra ctdp & pbf struct parameters */
ctdp_level - > processed = 1 ;
ctdp_level - > pbf_support = 1 ; /* PBF is always supported and enabled */
ctdp_level - > pbf_enabled = 1 ;
ctdp_level - > fact_support = 0 ; /* FACT is never supported */
ctdp_level - > fact_enabled = 0 ;
return 0 ;
error_ret :
free_cpu_set ( ctdp_level - > core_cpumask ) ;
return ret ;
}
static void dump_clx_n_config_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 ,
void * arg3 , void * arg4 )
{
int ret ;
if ( tdp_level ! = 0xff & & tdp_level ! = 0 ) {
isst_display_error_info_message ( 1 , " Invalid level " , 1 , tdp_level ) ;
exit ( 0 ) ;
}
ret = clx_n_config ( id ) ;
if ( ret ) {
debug_printf ( " clx_n_config failed " ) ;
} else {
struct isst_pkg_ctdp_level_info * ctdp_level ;
struct isst_pbf_info * pbf_info ;
ctdp_level = & clx_n_pkg_dev . ctdp_level [ 0 ] ;
pbf_info = & ctdp_level - > pbf_info ;
clx_n_pkg_dev . processed = 1 ;
isst_ctdp_display_information ( id , outf , tdp_level , & clx_n_pkg_dev ) ;
free_cpu_set ( ctdp_level - > core_cpumask ) ;
free_cpu_set ( pbf_info - > core_cpumask ) ;
}
}
static void dump_isst_config_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 ,
void * arg3 , void * arg4 )
{
struct isst_pkg_ctdp pkg_dev ;
int ret ;
memset ( & pkg_dev , 0 , sizeof ( pkg_dev ) ) ;
ret = isst_get_process_ctdp ( id , tdp_level , & pkg_dev ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " Failed to get perf-profile info on cpu " , 1 , id - > cpu ) ;
isst_ctdp_display_information_end ( outf ) ;
exit ( 1 ) ;
} else {
isst_ctdp_display_information ( id , outf , tdp_level , & pkg_dev ) ;
isst_get_process_ctdp_complete ( id , & pkg_dev ) ;
}
}
static void dump_isst_config ( int arg )
{
void * fn ;
if ( cmd_help ) {
fprintf ( stderr ,
" Print Intel(R) Speed Select Technology Performance profile configuration \n " ) ;
fprintf ( stderr ,
" including base frequency and turbo frequency configurations \n " ) ;
fprintf ( stderr , " Optional: -l|--level : Specify tdp level \n " ) ;
fprintf ( stderr ,
" \t If no arguments, dump information for all TDP levels \n " ) ;
exit ( 0 ) ;
}
if ( ! is_clx_n_platform ( ) )
fn = dump_isst_config_for_cpu ;
else
fn = dump_clx_n_config_for_cpu ;
isst_ctdp_display_information_start ( outf ) ;
if ( max_target_cpus )
for_each_online_target_cpu_in_set ( fn , NULL , NULL , NULL , NULL ) ;
else
2023-10-24 12:59:35 +02:00
for_each_online_power_domain_in_set ( fn , NULL , NULL , NULL , NULL ) ;
2023-08-30 17:31:07 +02:00
isst_ctdp_display_information_end ( outf ) ;
}
static void adjust_scaling_max_from_base_freq ( int cpu ) ;
static void set_tdp_level_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 , void * arg3 ,
void * arg4 )
{
2023-10-24 12:59:35 +02:00
struct isst_pkg_ctdp pkg_dev ;
2023-08-30 17:31:07 +02:00
int ret ;
2023-10-24 12:59:35 +02:00
ret = isst_get_ctdp_levels ( id , & pkg_dev ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " Get TDP level failed " , 0 , 0 ) ;
isst_ctdp_display_information_end ( outf ) ;
exit ( 1 ) ;
}
if ( pkg_dev . current_level = = tdp_level ) {
debug_printf ( " TDP level already set. Skipped \n " ) ;
goto display_result ;
}
2023-08-30 17:31:07 +02:00
ret = isst_set_tdp_level ( id , tdp_level ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " Set TDP level failed " , 0 , 0 ) ;
isst_ctdp_display_information_end ( outf ) ;
exit ( 1 ) ;
2023-10-24 12:59:35 +02:00
}
display_result :
isst_display_result ( id , outf , " perf-profile " , " set_tdp_level " , ret ) ;
if ( force_online_offline & & id - > cpu > = 0 ) {
struct isst_pkg_ctdp_level_info ctdp_level ;
/* Wait for updated base frequencies */
usleep ( 2000 ) ;
/* Adjusting uncore freq */
isst_adjust_uncore_freq ( id , tdp_level , & ctdp_level ) ;
fprintf ( stderr , " Option is set to online/offline \n " ) ;
ctdp_level . core_cpumask_size =
alloc_cpu_set ( & ctdp_level . core_cpumask ) ;
ret = isst_get_coremask_info ( id , tdp_level , & ctdp_level ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " Can't get coremask, online/offline option is ignored " , 0 , 0 ) ;
goto free_mask ;
}
if ( use_cgroupv2 ( ) ) {
int ret ;
fprintf ( stderr , " Using cgroup v2 in lieu of online/offline \n " ) ;
ret = enable_cpuset_controller ( ) ;
if ( ret )
goto use_offline ;
ret = isolate_cpus ( id , ctdp_level . core_cpumask_size , ctdp_level . core_cpumask , tdp_level ) ;
if ( ret )
goto use_offline ;
goto free_mask ;
}
use_offline :
if ( ctdp_level . cpu_count ) {
int i , max_cpus = get_topo_max_cpus ( ) ;
for ( i = 0 ; i < max_cpus ; + + i ) {
if ( ! is_cpu_in_power_domain ( i , id ) )
continue ;
if ( CPU_ISSET_S ( i , ctdp_level . core_cpumask_size , ctdp_level . core_cpumask ) ) {
fprintf ( stderr , " online cpu %d \n " , i ) ;
set_cpu_online_offline ( i , 1 ) ;
adjust_scaling_max_from_base_freq ( i ) ;
} else {
fprintf ( stderr , " offline cpu %d \n " , i ) ;
set_cpu_online_offline ( i , 0 ) ;
2023-08-30 17:31:07 +02:00
}
}
}
2023-10-24 12:59:35 +02:00
free_mask :
free_cpu_set ( ctdp_level . core_cpumask ) ;
2023-08-30 17:31:07 +02:00
}
}
static void set_tdp_level ( int arg )
{
if ( cmd_help ) {
fprintf ( stderr , " Set Config TDP level \n " ) ;
fprintf ( stderr ,
" \t Arguments: -l|--level : Specify tdp level \n " ) ;
fprintf ( stderr ,
" \t Optional Arguments: -o | online : online/offline for the tdp level \n " ) ;
fprintf ( stderr ,
" \t online/offline operation has limitations, refer to Linux hotplug documentation \n " ) ;
exit ( 0 ) ;
}
if ( tdp_level = = 0xff ) {
isst_display_error_info_message ( 1 , " Invalid command: specify tdp_level " , 0 , 0 ) ;
exit ( 1 ) ;
}
isst_ctdp_display_information_start ( outf ) ;
if ( max_target_cpus )
for_each_online_target_cpu_in_set ( set_tdp_level_for_cpu , NULL ,
NULL , NULL , NULL ) ;
else
2023-10-24 12:59:35 +02:00
for_each_online_power_domain_in_set ( set_tdp_level_for_cpu , NULL ,
2023-08-30 17:31:07 +02:00
NULL , NULL , NULL ) ;
isst_ctdp_display_information_end ( outf ) ;
}
static void clx_n_dump_pbf_config_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 ,
void * arg3 , void * arg4 )
{
int ret ;
ret = clx_n_config ( id ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " clx_n_config failed " , 0 , 0 ) ;
} else {
struct isst_pkg_ctdp_level_info * ctdp_level ;
struct isst_pbf_info * pbf_info ;
ctdp_level = & clx_n_pkg_dev . ctdp_level [ 0 ] ;
pbf_info = & ctdp_level - > pbf_info ;
isst_pbf_display_information ( id , outf , tdp_level , pbf_info ) ;
free_cpu_set ( ctdp_level - > core_cpumask ) ;
free_cpu_set ( pbf_info - > core_cpumask ) ;
}
}
static void dump_pbf_config_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 , void * arg3 ,
void * arg4 )
{
struct isst_pbf_info pbf_info ;
int ret ;
ret = isst_get_pbf_info ( id , tdp_level , & pbf_info ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " Failed to get base-freq info at this level " , 1 , tdp_level ) ;
isst_ctdp_display_information_end ( outf ) ;
exit ( 1 ) ;
} else {
isst_pbf_display_information ( id , outf , tdp_level , & pbf_info ) ;
2023-10-24 12:59:35 +02:00
free_cpu_set ( pbf_info . core_cpumask ) ;
2023-08-30 17:31:07 +02:00
}
}
static void dump_pbf_config ( int arg )
{
void * fn ;
if ( cmd_help ) {
fprintf ( stderr ,
" Print Intel(R) Speed Select Technology base frequency configuration for a TDP level \n " ) ;
fprintf ( stderr ,
" \t Arguments: -l|--level : Specify tdp level \n " ) ;
exit ( 0 ) ;
}
if ( tdp_level = = 0xff ) {
isst_display_error_info_message ( 1 , " Invalid command: specify tdp_level " , 0 , 0 ) ;
exit ( 1 ) ;
}
if ( ! is_clx_n_platform ( ) )
fn = dump_pbf_config_for_cpu ;
else
fn = clx_n_dump_pbf_config_for_cpu ;
isst_ctdp_display_information_start ( outf ) ;
if ( max_target_cpus )
for_each_online_target_cpu_in_set ( fn , NULL , NULL , NULL , NULL ) ;
else
2023-10-24 12:59:35 +02:00
for_each_online_power_domain_in_set ( fn , NULL , NULL , NULL , NULL ) ;
2023-08-30 17:31:07 +02:00
isst_ctdp_display_information_end ( outf ) ;
}
static int set_clos_param ( struct isst_id * id , int clos , int epp , int wt , int min , int max )
{
struct isst_clos_config clos_config ;
int ret ;
ret = isst_pm_get_clos ( id , clos , & clos_config ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " isst_pm_get_clos failed " , 0 , 0 ) ;
return ret ;
}
clos_config . clos_min = min ;
clos_config . clos_max = max ;
clos_config . epp = epp ;
clos_config . clos_prop_prio = wt ;
ret = isst_set_clos ( id , clos , & clos_config ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " isst_set_clos failed " , 0 , 0 ) ;
return ret ;
}
return 0 ;
}
static int set_cpufreq_scaling_min_max ( int cpu , int max , int freq )
{
char buffer [ 128 ] , freq_str [ 16 ] ;
int fd , ret , len ;
if ( max )
snprintf ( buffer , sizeof ( buffer ) ,
" /sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq " , cpu ) ;
else
snprintf ( buffer , sizeof ( buffer ) ,
" /sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq " , cpu ) ;
fd = open ( buffer , O_WRONLY ) ;
if ( fd < 0 )
return fd ;
snprintf ( freq_str , sizeof ( freq_str ) , " %d " , freq ) ;
len = strlen ( freq_str ) ;
ret = write ( fd , freq_str , len ) ;
if ( ret = = - 1 ) {
close ( fd ) ;
return ret ;
}
close ( fd ) ;
return 0 ;
}
static int no_turbo ( void )
{
return parse_int_file ( 0 , " /sys/devices/system/cpu/intel_pstate/no_turbo " ) ;
}
static void adjust_scaling_max_from_base_freq ( int cpu )
{
int base_freq , scaling_max_freq ;
scaling_max_freq = parse_int_file ( 0 , " /sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq " , cpu ) ;
base_freq = get_cpufreq_base_freq ( cpu ) ;
if ( scaling_max_freq < base_freq | | no_turbo ( ) )
set_cpufreq_scaling_min_max ( cpu , 1 , base_freq ) ;
}
static void adjust_scaling_min_from_base_freq ( int cpu )
{
int base_freq , scaling_min_freq ;
scaling_min_freq = parse_int_file ( 0 , " /sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq " , cpu ) ;
base_freq = get_cpufreq_base_freq ( cpu ) ;
if ( scaling_min_freq < base_freq )
set_cpufreq_scaling_min_max ( cpu , 0 , base_freq ) ;
}
static int set_clx_pbf_cpufreq_scaling_min_max ( struct isst_id * id )
{
struct isst_pkg_ctdp_level_info * ctdp_level ;
struct isst_pbf_info * pbf_info ;
int i , freq , freq_high , freq_low ;
int ret ;
ret = clx_n_config ( id ) ;
if ( ret ) {
debug_printf ( " cpufreq_scaling_min_max failed for CLX " ) ;
return ret ;
}
ctdp_level = & clx_n_pkg_dev . ctdp_level [ 0 ] ;
pbf_info = & ctdp_level - > pbf_info ;
freq_high = pbf_info - > p1_high * 100000 ;
freq_low = pbf_info - > p1_low * 100000 ;
for ( i = 0 ; i < get_topo_max_cpus ( ) ; + + i ) {
if ( ! is_cpu_in_power_domain ( i , id ) )
continue ;
if ( CPU_ISSET_S ( i , pbf_info - > core_cpumask_size ,
pbf_info - > core_cpumask ) )
freq = freq_high ;
else
freq = freq_low ;
set_cpufreq_scaling_min_max ( i , 1 , freq ) ;
set_cpufreq_scaling_min_max ( i , 0 , freq ) ;
}
return 0 ;
}
static int set_cpufreq_scaling_min_max_from_cpuinfo ( int cpu , int cpuinfo_max , int scaling_max )
{
char buffer [ 128 ] , min_freq [ 16 ] ;
int fd , ret , len ;
if ( ! CPU_ISSET_S ( cpu , present_cpumask_size , present_cpumask ) )
return - 1 ;
if ( cpuinfo_max )
snprintf ( buffer , sizeof ( buffer ) ,
" /sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq " , cpu ) ;
else
snprintf ( buffer , sizeof ( buffer ) ,
" /sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_min_freq " , cpu ) ;
fd = open ( buffer , O_RDONLY ) ;
if ( fd < 0 )
return fd ;
len = read ( fd , min_freq , sizeof ( min_freq ) ) ;
close ( fd ) ;
if ( len < 0 )
return len ;
if ( scaling_max )
snprintf ( buffer , sizeof ( buffer ) ,
" /sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq " , cpu ) ;
else
snprintf ( buffer , sizeof ( buffer ) ,
" /sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq " , cpu ) ;
fd = open ( buffer , O_WRONLY ) ;
if ( fd < 0 )
return fd ;
min_freq [ 15 ] = ' \0 ' ;
len = strlen ( min_freq ) ;
ret = write ( fd , min_freq , len ) ;
if ( ret = = - 1 ) {
close ( fd ) ;
return ret ;
}
close ( fd ) ;
return 0 ;
}
static void set_scaling_min_to_cpuinfo_max ( struct isst_id * id )
{
int i ;
2023-10-24 12:59:35 +02:00
if ( id - > cpu < 0 )
return ;
2023-08-30 17:31:07 +02:00
for ( i = 0 ; i < get_topo_max_cpus ( ) ; + + i ) {
if ( ! is_cpu_in_power_domain ( i , id ) )
continue ;
if ( is_cpu_online ( i ) ! = 1 )
continue ;
adjust_scaling_max_from_base_freq ( i ) ;
set_cpufreq_scaling_min_max_from_cpuinfo ( i , 1 , 0 ) ;
adjust_scaling_min_from_base_freq ( i ) ;
}
}
static void set_scaling_min_to_cpuinfo_min ( struct isst_id * id )
{
int i ;
2023-10-24 12:59:35 +02:00
if ( id - > cpu < 0 )
return ;
2023-08-30 17:31:07 +02:00
for ( i = 0 ; i < get_topo_max_cpus ( ) ; + + i ) {
if ( ! is_cpu_in_power_domain ( i , id ) )
continue ;
if ( is_cpu_online ( i ) ! = 1 )
continue ;
adjust_scaling_max_from_base_freq ( i ) ;
set_cpufreq_scaling_min_max_from_cpuinfo ( i , 0 , 0 ) ;
}
}
static void set_scaling_max_to_cpuinfo_max ( struct isst_id * id )
{
int i ;
for ( i = 0 ; i < get_topo_max_cpus ( ) ; + + i ) {
if ( ! is_cpu_in_power_domain ( i , id ) )
continue ;
set_cpufreq_scaling_min_max_from_cpuinfo ( i , 1 , 1 ) ;
}
}
static int set_core_priority_and_min ( struct isst_id * id , int mask_size ,
cpu_set_t * cpu_mask , int min_high ,
int min_low )
{
int ret , i ;
if ( ! CPU_COUNT_S ( mask_size , cpu_mask ) )
return - 1 ;
ret = set_clos_param ( id , 0 , 0 , 0 , min_high , 0xff ) ;
if ( ret )
return ret ;
ret = set_clos_param ( id , 1 , 15 , 15 , min_low , 0xff ) ;
if ( ret )
return ret ;
ret = set_clos_param ( id , 2 , 15 , 15 , min_low , 0xff ) ;
if ( ret )
return ret ;
ret = set_clos_param ( id , 3 , 15 , 15 , min_low , 0xff ) ;
if ( ret )
return ret ;
for ( i = 0 ; i < get_topo_max_cpus ( ) ; + + i ) {
int clos ;
struct isst_id tid ;
if ( ! is_cpu_in_power_domain ( i , id ) )
continue ;
if ( CPU_ISSET_S ( i , mask_size , cpu_mask ) )
clos = 0 ;
else
clos = 3 ;
debug_printf ( " Associate cpu: %d clos: %d \n " , i , clos ) ;
set_isst_id ( & tid , i ) ;
ret = isst_clos_associate ( & tid , clos ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " isst_clos_associate failed " , 0 , 0 ) ;
return ret ;
}
}
return 0 ;
}
static int set_pbf_core_power ( struct isst_id * id )
{
struct isst_pbf_info pbf_info ;
struct isst_pkg_ctdp pkg_dev ;
int ret ;
2023-10-24 12:59:35 +02:00
if ( id - > cpu < 0 )
return 0 ;
2023-08-30 17:31:07 +02:00
ret = isst_get_ctdp_levels ( id , & pkg_dev ) ;
if ( ret ) {
debug_printf ( " isst_get_ctdp_levels failed " ) ;
return ret ;
}
debug_printf ( " Current_level: %d \n " , pkg_dev . current_level ) ;
ret = isst_get_pbf_info ( id , pkg_dev . current_level , & pbf_info ) ;
if ( ret ) {
debug_printf ( " isst_get_pbf_info failed " ) ;
return ret ;
}
debug_printf ( " p1_high: %d p1_low: %d \n " , pbf_info . p1_high ,
pbf_info . p1_low ) ;
ret = set_core_priority_and_min ( id , pbf_info . core_cpumask_size ,
pbf_info . core_cpumask ,
pbf_info . p1_high , pbf_info . p1_low ) ;
if ( ret ) {
debug_printf ( " set_core_priority_and_min failed " ) ;
return ret ;
}
ret = isst_pm_qos_config ( id , 1 , 1 ) ;
if ( ret ) {
debug_printf ( " isst_pm_qos_config failed " ) ;
return ret ;
}
return 0 ;
}
static void set_pbf_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 , void * arg3 ,
void * arg4 )
{
struct isst_pkg_ctdp_level_info ctdp_level ;
struct isst_pkg_ctdp pkg_dev ;
int ret ;
int status = * ( int * ) arg4 ;
if ( is_clx_n_platform ( ) ) {
ret = 0 ;
if ( status ) {
set_clx_pbf_cpufreq_scaling_min_max ( id ) ;
} else {
set_scaling_max_to_cpuinfo_max ( id ) ;
set_scaling_min_to_cpuinfo_min ( id ) ;
}
goto disp_result ;
}
ret = isst_get_ctdp_levels ( id , & pkg_dev ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " Failed to get number of levels " , 0 , 0 ) ;
goto disp_result ;
}
ret = isst_get_ctdp_control ( id , pkg_dev . current_level , & ctdp_level ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " Failed to get current level " , 0 , 0 ) ;
goto disp_result ;
}
if ( ! ctdp_level . pbf_support ) {
isst_display_error_info_message ( 1 , " base-freq feature is not present at this level " , 1 , pkg_dev . current_level ) ;
ret = - 1 ;
goto disp_result ;
}
if ( auto_mode & & status ) {
ret = set_pbf_core_power ( id ) ;
if ( ret )
goto disp_result ;
}
ret = isst_set_pbf_fact_status ( id , 1 , status ) ;
if ( ret ) {
debug_printf ( " isst_set_pbf_fact_status failed " ) ;
if ( auto_mode )
isst_pm_qos_config ( id , 0 , 0 ) ;
} else {
if ( auto_mode ) {
if ( status )
set_scaling_min_to_cpuinfo_max ( id ) ;
else
set_scaling_min_to_cpuinfo_min ( id ) ;
}
}
if ( auto_mode & & ! status )
isst_pm_qos_config ( id , 0 , 1 ) ;
disp_result :
if ( status )
isst_display_result ( id , outf , " base-freq " , " enable " ,
ret ) ;
else
isst_display_result ( id , outf , " base-freq " , " disable " ,
ret ) ;
}
static void set_pbf_enable ( int arg )
{
int enable = arg ;
if ( cmd_help ) {
if ( enable ) {
fprintf ( stderr ,
" Enable Intel Speed Select Technology base frequency feature \n " ) ;
if ( is_clx_n_platform ( ) ) {
fprintf ( stderr ,
" \t On this platform this command doesn't enable feature in the hardware. \n " ) ;
fprintf ( stderr ,
" \t It updates the cpufreq scaling_min_freq to match cpufreq base_frequency. \n " ) ;
exit ( 0 ) ;
}
fprintf ( stderr ,
" \t Optional Arguments: -a|--auto : Use priority of cores to set core-power associations \n " ) ;
} else {
if ( is_clx_n_platform ( ) ) {
fprintf ( stderr ,
" \t On this platform this command doesn't disable feature in the hardware. \n " ) ;
fprintf ( stderr ,
" \t It updates the cpufreq scaling_min_freq to match cpuinfo_min_freq \n " ) ;
exit ( 0 ) ;
}
fprintf ( stderr ,
" Disable Intel Speed Select Technology base frequency feature \n " ) ;
fprintf ( stderr ,
" \t Optional Arguments: -a|--auto : Also disable core-power associations \n " ) ;
}
exit ( 0 ) ;
}
isst_ctdp_display_information_start ( outf ) ;
if ( max_target_cpus )
for_each_online_target_cpu_in_set ( set_pbf_for_cpu , NULL , NULL ,
NULL , & enable ) ;
else
2023-10-24 12:59:35 +02:00
for_each_online_power_domain_in_set ( set_pbf_for_cpu , NULL , NULL ,
2023-08-30 17:31:07 +02:00
NULL , & enable ) ;
isst_ctdp_display_information_end ( outf ) ;
}
static void dump_fact_config_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 ,
void * arg3 , void * arg4 )
{
struct isst_fact_info fact_info ;
int ret ;
ret = isst_get_fact_info ( id , tdp_level , fact_bucket , & fact_info ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " Failed to get turbo-freq info at this level " , 1 , tdp_level ) ;
isst_ctdp_display_information_end ( outf ) ;
exit ( 1 ) ;
} else {
isst_fact_display_information ( id , outf , tdp_level , fact_bucket ,
fact_avx , & fact_info ) ;
}
}
static void dump_fact_config ( int arg )
{
if ( cmd_help ) {
fprintf ( stderr ,
" Print complete Intel Speed Select Technology turbo frequency configuration for a TDP level. Other arguments are optional. \n " ) ;
fprintf ( stderr ,
" \t Arguments: -l|--level : Specify tdp level \n " ) ;
fprintf ( stderr ,
" \t Arguments: -b|--bucket : Bucket index to dump \n " ) ;
fprintf ( stderr ,
" \t Arguments: -r|--trl-type : Specify trl type: sse|avx2|avx512 \n " ) ;
exit ( 0 ) ;
}
if ( tdp_level = = 0xff ) {
isst_display_error_info_message ( 1 , " Invalid command: specify tdp_level \n " , 0 , 0 ) ;
exit ( 1 ) ;
}
isst_ctdp_display_information_start ( outf ) ;
if ( max_target_cpus )
for_each_online_target_cpu_in_set ( dump_fact_config_for_cpu ,
NULL , NULL , NULL , NULL ) ;
else
2023-10-24 12:59:35 +02:00
for_each_online_power_domain_in_set ( dump_fact_config_for_cpu , NULL ,
2023-08-30 17:31:07 +02:00
NULL , NULL , NULL ) ;
isst_ctdp_display_information_end ( outf ) ;
}
static void set_fact_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 , void * arg3 ,
void * arg4 )
{
struct isst_pkg_ctdp_level_info ctdp_level ;
struct isst_pkg_ctdp pkg_dev ;
int ret ;
int status = * ( int * ) arg4 ;
if ( status & & no_turbo ( ) ) {
isst_display_error_info_message ( 1 , " Turbo mode is disabled " , 0 , 0 ) ;
ret = - 1 ;
goto disp_results ;
}
ret = isst_get_ctdp_levels ( id , & pkg_dev ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " Failed to get number of levels " , 0 , 0 ) ;
goto disp_results ;
}
ret = isst_get_ctdp_control ( id , pkg_dev . current_level , & ctdp_level ) ;
if ( ret ) {
isst_display_error_info_message ( 1 , " Failed to get current level " , 0 , 0 ) ;
goto disp_results ;
}
if ( ! ctdp_level . fact_support ) {
isst_display_error_info_message ( 1 , " turbo-freq feature is not present at this level " , 1 , pkg_dev . current_level ) ;
ret = - 1 ;
goto disp_results ;
}
if ( status ) {
ret = isst_pm_qos_config ( id , 1 , 1 ) ;
if ( ret )
goto disp_results ;
}
ret = isst_set_pbf_fact_status ( id , 0 , status ) ;
if ( ret ) {
debug_printf ( " isst_set_pbf_fact_status failed " ) ;
if ( auto_mode )
isst_pm_qos_config ( id , 0 , 0 ) ;
goto disp_results ;
}
/* Set TRL */
if ( status ) {
struct isst_pkg_ctdp pkg_dev ;
ret = isst_get_ctdp_levels ( id , & pkg_dev ) ;
2023-10-24 12:59:35 +02:00
if ( ! ret & & id - > cpu > = 0 )
2023-08-30 17:31:07 +02:00
ret = isst_set_trl ( id , fact_trl ) ;
if ( ret & & auto_mode )
isst_pm_qos_config ( id , 0 , 0 ) ;
} else {
if ( auto_mode )
isst_pm_qos_config ( id , 0 , 0 ) ;
}
disp_results :
if ( status ) {
isst_display_result ( id , outf , " turbo-freq " , " enable " , ret ) ;
if ( ret )
fact_enable_fail = ret ;
} else {
/* Since we modified TRL during Fact enable, restore it */
isst_set_trl_from_current_tdp ( id , fact_trl ) ;
isst_display_result ( id , outf , " turbo-freq " , " disable " , ret ) ;
}
}
static void set_fact_enable ( int arg )
{
int i , ret , enable = arg ;
struct isst_id id ;
if ( cmd_help ) {
if ( enable ) {
fprintf ( stderr ,
" Enable Intel Speed Select Technology Turbo frequency feature \n " ) ;
fprintf ( stderr ,
" Optional: -t|--trl : Specify turbo ratio limit \n " ) ;
fprintf ( stderr ,
" \t Optional Arguments: -a|--auto : Designate specified target CPUs with " ) ;
fprintf ( stderr ,
" -C|--cpu option as as high priority using core-power feature \n " ) ;
} else {
fprintf ( stderr ,
" Disable Intel Speed Select Technology turbo frequency feature \n " ) ;
fprintf ( stderr ,
" Optional: -t|--trl : Specify turbo ratio limit \n " ) ;
fprintf ( stderr ,
" \t Optional Arguments: -a|--auto : Also disable core-power associations \n " ) ;
}
exit ( 0 ) ;
}
isst_ctdp_display_information_start ( outf ) ;
if ( max_target_cpus )
for_each_online_target_cpu_in_set ( set_fact_for_cpu , NULL , NULL ,
NULL , & enable ) ;
else
2023-10-24 12:59:35 +02:00
for_each_online_power_domain_in_set ( set_fact_for_cpu , NULL , NULL ,
2023-08-30 17:31:07 +02:00
NULL , & enable ) ;
if ( ! fact_enable_fail & & enable & & auto_mode ) {
/*
* When we adjust CLOS param , we have to set for siblings also .
* So for the each user specified CPU , also add the sibling
* in the present_cpu_mask .
*/
for ( i = 0 ; i < get_topo_max_cpus ( ) ; + + i ) {
char buffer [ 128 ] , sibling_list [ 128 ] , * cpu_str ;
int fd , len ;
if ( ! CPU_ISSET_S ( i , target_cpumask_size , target_cpumask ) )
continue ;
snprintf ( buffer , sizeof ( buffer ) ,
" /sys/devices/system/cpu/cpu%d/topology/thread_siblings_list " , i ) ;
fd = open ( buffer , O_RDONLY ) ;
if ( fd < 0 )
continue ;
len = read ( fd , sibling_list , sizeof ( sibling_list ) ) ;
close ( fd ) ;
if ( len < 0 )
continue ;
sibling_list [ 127 ] = ' \0 ' ;
cpu_str = strtok ( sibling_list , " , " ) ;
while ( cpu_str ! = NULL ) {
int cpu ;
sscanf ( cpu_str , " %d " , & cpu ) ;
CPU_SET_S ( cpu , target_cpumask_size , target_cpumask ) ;
cpu_str = strtok ( NULL , " , " ) ;
}
}
for ( i = 0 ; i < get_topo_max_cpus ( ) ; + + i ) {
int clos ;
if ( ! CPU_ISSET_S ( i , present_cpumask_size , present_cpumask ) )
continue ;
if ( is_cpu_online ( i ) ! = 1 )
continue ;
set_isst_id ( & id , i ) ;
ret = set_clos_param ( & id , 0 , 0 , 0 , 0 , 0xff ) ;
if ( ret )
goto error_disp ;
ret = set_clos_param ( & id , 1 , 15 , 15 , 0 , 0xff ) ;
if ( ret )
goto error_disp ;
ret = set_clos_param ( & id , 2 , 15 , 15 , 0 , 0xff ) ;
if ( ret )
goto error_disp ;
ret = set_clos_param ( & id , 3 , 15 , 15 , 0 , 0xff ) ;
if ( ret )
goto error_disp ;
if ( CPU_ISSET_S ( i , target_cpumask_size , target_cpumask ) )
clos = 0 ;
else
clos = 3 ;
debug_printf ( " Associate cpu: %d clos: %d \n " , i , clos ) ;
ret = isst_clos_associate ( & id , clos ) ;
if ( ret )
goto error_disp ;
}
set_isst_id ( & id , - 1 ) ;
isst_display_result ( & id , outf , " turbo-freq --auto " , " enable " , 0 ) ;
}
2023-10-24 12:59:35 +02:00
isst_ctdp_display_information_end ( outf ) ;
2023-08-30 17:31:07 +02:00
return ;
error_disp :
isst_display_result ( & id , outf , " turbo-freq --auto " , " enable " , ret ) ;
2023-10-24 12:59:35 +02:00
isst_ctdp_display_information_end ( outf ) ;
2023-08-30 17:31:07 +02:00
}
static void enable_clos_qos_config ( struct isst_id * id , void * arg1 , void * arg2 , void * arg3 ,
void * arg4 )
{
int ret ;
int status = * ( int * ) arg4 ;
if ( is_skx_based_platform ( ) )
clos_priority_type = 1 ;
ret = isst_pm_qos_config ( id , status , clos_priority_type ) ;
if ( ret )
isst_display_error_info_message ( 1 , " isst_pm_qos_config failed " , 0 , 0 ) ;
if ( status )
isst_display_result ( id , outf , " core-power " , " enable " ,
ret ) ;
else
isst_display_result ( id , outf , " core-power " , " disable " ,
ret ) ;
}
static void set_clos_enable ( int arg )
{
int enable = arg ;
if ( cmd_help ) {
if ( enable ) {
fprintf ( stderr ,
" Enable core-power for a package/die \n " ) ;
if ( ! is_skx_based_platform ( ) ) {
fprintf ( stderr ,
" \t Clos Enable: Specify priority type with [--priority|-p] \n " ) ;
fprintf ( stderr , " \t \t 0: Proportional, 1: Ordered \n " ) ;
}
} else {
fprintf ( stderr ,
" Disable core-power: [No command arguments are required] \n " ) ;
}
exit ( 0 ) ;
}
if ( enable & & cpufreq_sysfs_present ( ) ) {
fprintf ( stderr ,
" cpufreq subsystem and core-power enable will interfere with each other! \n " ) ;
}
isst_ctdp_display_information_start ( outf ) ;
if ( max_target_cpus )
for_each_online_target_cpu_in_set ( enable_clos_qos_config , NULL ,
NULL , NULL , & enable ) ;
else
2023-10-24 12:59:35 +02:00
for_each_online_power_domain_in_set ( enable_clos_qos_config , NULL ,
2023-08-30 17:31:07 +02:00
NULL , NULL , & enable ) ;
isst_ctdp_display_information_end ( outf ) ;
}
static void dump_clos_config_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 ,
void * arg3 , void * arg4 )
{
struct isst_clos_config clos_config ;
int ret ;
ret = isst_pm_get_clos ( id , current_clos , & clos_config ) ;
if ( ret )
isst_display_error_info_message ( 1 , " isst_pm_get_clos failed " , 0 , 0 ) ;
else
isst_clos_display_information ( id , outf , current_clos ,
& clos_config ) ;
}
static void dump_clos_config ( int arg )
{
if ( cmd_help ) {
fprintf ( stderr ,
" Print Intel Speed Select Technology core power configuration \n " ) ;
fprintf ( stderr ,
" \t Arguments: [-c | --clos]: Specify clos id \n " ) ;
exit ( 0 ) ;
}
if ( current_clos < 0 | | current_clos > 3 ) {
isst_display_error_info_message ( 1 , " Invalid clos id \n " , 0 , 0 ) ;
isst_ctdp_display_information_end ( outf ) ;
exit ( 0 ) ;
}
isst_ctdp_display_information_start ( outf ) ;
if ( max_target_cpus )
for_each_online_target_cpu_in_set ( dump_clos_config_for_cpu ,
NULL , NULL , NULL , NULL ) ;
else
2023-10-24 12:59:35 +02:00
for_each_online_power_domain_in_set ( dump_clos_config_for_cpu , NULL ,
2023-08-30 17:31:07 +02:00
NULL , NULL , NULL ) ;
isst_ctdp_display_information_end ( outf ) ;
}
static void get_clos_info_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 , void * arg3 ,
void * arg4 )
{
int enable , ret , prio_type ;
ret = isst_clos_get_clos_information ( id , & enable , & prio_type ) ;
if ( ret )
isst_display_error_info_message ( 1 , " isst_clos_get_info failed " , 0 , 0 ) ;
else {
int cp_state , cp_cap ;
isst_read_pm_config ( id , & cp_state , & cp_cap ) ;
isst_clos_display_clos_information ( id , outf , enable , prio_type ,
cp_state , cp_cap ) ;
}
}
static void dump_clos_info ( int arg )
{
if ( cmd_help ) {
fprintf ( stderr ,
" Print Intel Speed Select Technology core power information \n " ) ;
fprintf ( stderr , " \t Optionally specify targeted cpu id with [--cpu|-c] \n " ) ;
exit ( 0 ) ;
}
isst_ctdp_display_information_start ( outf ) ;
if ( max_target_cpus )
for_each_online_target_cpu_in_set ( get_clos_info_for_cpu , NULL ,
NULL , NULL , NULL ) ;
else
2023-10-24 12:59:35 +02:00
for_each_online_power_domain_in_set ( get_clos_info_for_cpu , NULL ,
2023-08-30 17:31:07 +02:00
NULL , NULL , NULL ) ;
isst_ctdp_display_information_end ( outf ) ;
}
static void set_clos_config_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 , void * arg3 ,
void * arg4 )
{
struct isst_clos_config clos_config ;
int ret ;
2023-10-24 12:59:35 +02:00
if ( id - > cpu < 0 )
return ;
2023-08-30 17:31:07 +02:00
clos_config . epp = clos_epp ;
clos_config . clos_prop_prio = clos_prop_prio ;
clos_config . clos_min = clos_min ;
clos_config . clos_max = clos_max ;
clos_config . clos_desired = clos_desired ;
ret = isst_set_clos ( id , current_clos , & clos_config ) ;
if ( ret )
isst_display_error_info_message ( 1 , " isst_set_clos failed " , 0 , 0 ) ;
else
isst_display_result ( id , outf , " core-power " , " config " , ret ) ;
}
static void set_clos_config ( int arg )
{
if ( cmd_help ) {
fprintf ( stderr ,
" Set core-power configuration for one of the four clos ids \n " ) ;
fprintf ( stderr ,
" \t Specify targeted clos id with [--clos|-c] \n " ) ;
if ( ! is_skx_based_platform ( ) ) {
fprintf ( stderr , " \t Specify clos EPP with [--epp|-e] \n " ) ;
fprintf ( stderr ,
" \t Specify clos Proportional Priority [--weight|-w] \n " ) ;
}
fprintf ( stderr , " \t Specify clos min in MHz with [--min|-n] \n " ) ;
fprintf ( stderr , " \t Specify clos max in MHz with [--max|-m] \n " ) ;
exit ( 0 ) ;
}
if ( current_clos < 0 | | current_clos > 3 ) {
isst_display_error_info_message ( 1 , " Invalid clos id \n " , 0 , 0 ) ;
exit ( 0 ) ;
}
if ( ! is_skx_based_platform ( ) & & ( clos_epp < 0 | | clos_epp > 0x0F ) ) {
fprintf ( stderr , " clos epp is not specified or invalid, default: 0 \n " ) ;
clos_epp = 0 ;
}
if ( ! is_skx_based_platform ( ) & & ( clos_prop_prio < 0 | | clos_prop_prio > 0x0F ) ) {
fprintf ( stderr ,
" clos frequency weight is not specified or invalid, default: 0 \n " ) ;
clos_prop_prio = 0 ;
}
if ( clos_min < 0 ) {
fprintf ( stderr , " clos min is not specified, default: 0 \n " ) ;
clos_min = 0 ;
}
if ( clos_max < 0 ) {
fprintf ( stderr , " clos max is not specified, default: Max frequency (ratio 0xff) \n " ) ;
clos_max = 0xff ;
}
if ( clos_desired ) {
fprintf ( stderr , " clos desired is not supported on this platform \n " ) ;
clos_desired = 0x00 ;
}
isst_ctdp_display_information_start ( outf ) ;
if ( max_target_cpus )
for_each_online_target_cpu_in_set ( set_clos_config_for_cpu , NULL ,
NULL , NULL , NULL ) ;
else
2023-10-24 12:59:35 +02:00
for_each_online_power_domain_in_set ( set_clos_config_for_cpu , NULL ,
2023-08-30 17:31:07 +02:00
NULL , NULL , NULL ) ;
isst_ctdp_display_information_end ( outf ) ;
}
static void set_clos_assoc_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 , void * arg3 ,
void * arg4 )
{
int ret ;
ret = isst_clos_associate ( id , current_clos ) ;
if ( ret )
debug_printf ( " isst_clos_associate failed " ) ;
else
isst_display_result ( id , outf , " core-power " , " assoc " , ret ) ;
}
static void set_clos_assoc ( int arg )
{
if ( cmd_help ) {
fprintf ( stderr , " Associate a clos id to a CPU \n " ) ;
fprintf ( stderr ,
" \t Specify targeted clos id with [--clos|-c] \n " ) ;
fprintf ( stderr ,
" \t For example to associate clos 1 to CPU 0: issue \n " ) ;
fprintf ( stderr ,
" \t intel-speed-select --cpu 0 core-power assoc --clos 1 \n " ) ;
exit ( 0 ) ;
}
if ( current_clos < 0 | | current_clos > 3 ) {
isst_display_error_info_message ( 1 , " Invalid clos id \n " , 0 , 0 ) ;
exit ( 0 ) ;
}
2023-10-24 12:59:35 +02:00
isst_ctdp_display_information_start ( outf ) ;
2023-08-30 17:31:07 +02:00
if ( max_target_cpus )
for_each_online_target_cpu_in_set ( set_clos_assoc_for_cpu , NULL ,
NULL , NULL , NULL ) ;
else {
isst_display_error_info_message ( 1 , " Invalid target cpu. Specify with [-c|--cpu] " , 0 , 0 ) ;
}
2023-10-24 12:59:35 +02:00
isst_ctdp_display_information_end ( outf ) ;
2023-08-30 17:31:07 +02:00
}
static void get_clos_assoc_for_cpu ( struct isst_id * id , void * arg1 , void * arg2 , void * arg3 ,
void * arg4 )
{
int clos , ret ;
ret = isst_clos_get_assoc_status ( id , & clos ) ;
if ( ret )
isst_display_error_info_message ( 1 , " isst_clos_get_assoc_status failed " , 0 , 0 ) ;
else
isst_clos_display_assoc_information ( id , outf , clos ) ;
}
static void get_clos_assoc ( int arg )
{
if ( cmd_help ) {
fprintf ( stderr , " Get associate clos id to a CPU \n " ) ;
fprintf ( stderr , " \t Specify targeted cpu id with [--cpu|-c] \n " ) ;
exit ( 0 ) ;
}
if ( ! max_target_cpus ) {
isst_display_error_info_message ( 1 , " Invalid target cpu. Specify with [-c|--cpu] " , 0 , 0 ) ;
exit ( 0 ) ;
}
isst_ctdp_display_information_start ( outf ) ;
for_each_online_target_cpu_in_set ( get_clos_assoc_for_cpu , NULL ,
NULL , NULL , NULL ) ;
isst_ctdp_display_information_end ( outf ) ;
}
static void set_turbo_mode_for_cpu ( struct isst_id * id , int status )
{
int base_freq ;
if ( status ) {
base_freq = get_cpufreq_base_freq ( id - > cpu ) ;
set_cpufreq_scaling_min_max ( id - > cpu , 1 , base_freq ) ;
} else {
set_scaling_max_to_cpuinfo_max ( id ) ;
}
if ( status ) {
isst_display_result ( id , outf , " turbo-mode " , " enable " , 0 ) ;
} else {
isst_display_result ( id , outf , " turbo-mode " , " disable " , 0 ) ;
}
}
static void set_turbo_mode ( int arg )
{
int i , enable = arg ;
struct isst_id id ;
if ( cmd_help ) {
if ( enable )
fprintf ( stderr , " Set turbo mode enable \n " ) ;
else
fprintf ( stderr , " Set turbo mode disable \n " ) ;
exit ( 0 ) ;
}
isst_ctdp_display_information_start ( outf ) ;
for ( i = 0 ; i < topo_max_cpus ; + + i ) {
int online ;
if ( i )
online = parse_int_file (
1 , " /sys/devices/system/cpu/cpu%d/online " , i ) ;
else
online =
1 ; /* online entry for CPU 0 needs some special configs */
if ( online ) {
set_isst_id ( & id , i ) ;
set_turbo_mode_for_cpu ( & id , enable ) ;
}
}
isst_ctdp_display_information_end ( outf ) ;
}
static void get_set_trl ( struct isst_id * id , void * arg1 , void * arg2 , void * arg3 ,
void * arg4 )
{
unsigned long long trl ;
int set = * ( int * ) arg4 ;
int ret ;
if ( set & & ! fact_trl ) {
isst_display_error_info_message ( 1 , " Invalid TRL. Specify with [-t|--trl] " , 0 , 0 ) ;
exit ( 0 ) ;
}
if ( set ) {
ret = isst_set_trl ( id , fact_trl ) ;
isst_display_result ( id , outf , " turbo-mode " , " set-trl " , ret ) ;
return ;
}
ret = isst_get_trl ( id , & trl ) ;
if ( ret )
isst_display_result ( id , outf , " turbo-mode " , " get-trl " , ret ) ;
else
isst_trl_display_information ( id , outf , trl ) ;
}
static void process_trl ( int arg )
{
if ( cmd_help ) {
if ( arg ) {
fprintf ( stderr , " Set TRL (turbo ratio limits) \n " ) ;
fprintf ( stderr , " \t t|--trl: Specify turbo ratio limit for setting TRL \n " ) ;
} else {
fprintf ( stderr , " Get TRL (turbo ratio limits) \n " ) ;
}
exit ( 0 ) ;
}
isst_ctdp_display_information_start ( outf ) ;
if ( max_target_cpus )
for_each_online_target_cpu_in_set ( get_set_trl , NULL ,
NULL , NULL , & arg ) ;
else
2023-10-24 12:59:35 +02:00
for_each_online_power_domain_in_set ( get_set_trl , NULL ,
2023-08-30 17:31:07 +02:00
NULL , NULL , & arg ) ;
isst_ctdp_display_information_end ( outf ) ;
}
static struct process_cmd_struct clx_n_cmds [ ] = {
{ " perf-profile " , " info " , dump_isst_config , 0 } ,
{ " base-freq " , " info " , dump_pbf_config , 0 } ,
{ " base-freq " , " enable " , set_pbf_enable , 1 } ,
{ " base-freq " , " disable " , set_pbf_enable , 0 } ,
{ NULL , NULL , NULL , 0 }
} ;
static struct process_cmd_struct isst_cmds [ ] = {
{ " perf-profile " , " get-lock-status " , get_tdp_locked , 0 } ,
{ " perf-profile " , " get-config-levels " , get_tdp_levels , 0 } ,
{ " perf-profile " , " get-config-version " , get_tdp_version , 0 } ,
{ " perf-profile " , " get-config-enabled " , get_tdp_enabled , 0 } ,
{ " perf-profile " , " get-config-current-level " , get_tdp_current_level ,
0 } ,
{ " perf-profile " , " set-config-level " , set_tdp_level , 0 } ,
{ " perf-profile " , " info " , dump_isst_config , 0 } ,
{ " base-freq " , " info " , dump_pbf_config , 0 } ,
{ " base-freq " , " enable " , set_pbf_enable , 1 } ,
{ " base-freq " , " disable " , set_pbf_enable , 0 } ,
{ " turbo-freq " , " info " , dump_fact_config , 0 } ,
{ " turbo-freq " , " enable " , set_fact_enable , 1 } ,
{ " turbo-freq " , " disable " , set_fact_enable , 0 } ,
{ " core-power " , " info " , dump_clos_info , 0 } ,
{ " core-power " , " enable " , set_clos_enable , 1 } ,
{ " core-power " , " disable " , set_clos_enable , 0 } ,
{ " core-power " , " config " , set_clos_config , 0 } ,
{ " core-power " , " get-config " , dump_clos_config , 0 } ,
{ " core-power " , " assoc " , set_clos_assoc , 0 } ,
{ " core-power " , " get-assoc " , get_clos_assoc , 0 } ,
{ " turbo-mode " , " enable " , set_turbo_mode , 0 } ,
{ " turbo-mode " , " disable " , set_turbo_mode , 1 } ,
{ " turbo-mode " , " get-trl " , process_trl , 0 } ,
{ " turbo-mode " , " set-trl " , process_trl , 1 } ,
{ NULL , NULL , NULL }
} ;
/*
* parse cpuset with following syntax
* 1 , 2 , 4. .6 , 8 - 10 and set bits in cpu_subset
*/
void parse_cpu_command ( char * optarg )
{
unsigned int start , end ;
char * next ;
next = optarg ;
while ( next & & * next ) {
if ( * next = = ' - ' ) /* no negative cpu numbers */
goto error ;
start = strtoul ( next , & next , 10 ) ;
if ( max_target_cpus < MAX_CPUS_IN_ONE_REQ )
target_cpus [ max_target_cpus + + ] = start ;
if ( * next = = ' \0 ' )
break ;
if ( * next = = ' , ' ) {
next + = 1 ;
continue ;
}
if ( * next = = ' - ' ) {
next + = 1 ; /* start range */
} else if ( * next = = ' . ' ) {
next + = 1 ;
if ( * next = = ' . ' )
next + = 1 ; /* start range */
else
goto error ;
}
end = strtoul ( next , & next , 10 ) ;
if ( end < = start )
goto error ;
while ( + + start < = end ) {
if ( max_target_cpus < MAX_CPUS_IN_ONE_REQ )
target_cpus [ max_target_cpus + + ] = start ;
}
if ( * next = = ' , ' )
next + = 1 ;
else if ( * next ! = ' \0 ' )
goto error ;
}
# ifdef DEBUG
{
int i ;
for ( i = 0 ; i < max_target_cpus ; + + i )
printf ( " cpu [%d] in arg \n " , target_cpus [ i ] ) ;
}
# endif
return ;
error :
fprintf ( stderr , " \" --cpu %s \" malformed \n " , optarg ) ;
exit ( - 1 ) ;
}
static void parse_cmd_args ( int argc , int start , char * * argv )
{
int opt ;
int option_index ;
static struct option long_options [ ] = {
{ " bucket " , required_argument , 0 , ' b ' } ,
{ " level " , required_argument , 0 , ' l ' } ,
{ " online " , required_argument , 0 , ' o ' } ,
{ " trl-type " , required_argument , 0 , ' r ' } ,
{ " trl " , required_argument , 0 , ' t ' } ,
{ " help " , no_argument , 0 , ' h ' } ,
{ " clos " , required_argument , 0 , ' c ' } ,
{ " desired " , required_argument , 0 , ' d ' } ,
{ " epp " , required_argument , 0 , ' e ' } ,
{ " min " , required_argument , 0 , ' n ' } ,
{ " max " , required_argument , 0 , ' m ' } ,
{ " priority " , required_argument , 0 , ' p ' } ,
{ " weight " , required_argument , 0 , ' w ' } ,
{ " auto " , no_argument , 0 , ' a ' } ,
{ 0 , 0 , 0 , 0 }
} ;
option_index = start ;
optind = start + 1 ;
while ( ( opt = getopt_long ( argc , argv , " b:l:t:c:d:e:n:m:p:w:r:hoa " ,
long_options , & option_index ) ) ! = - 1 ) {
switch ( opt ) {
case ' a ' :
auto_mode = 1 ;
break ;
case ' b ' :
fact_bucket = atoi ( optarg ) ;
break ;
case ' h ' :
cmd_help = 1 ;
break ;
case ' l ' :
tdp_level = atoi ( optarg ) ;
break ;
case ' o ' :
force_online_offline = 1 ;
break ;
case ' t ' :
sscanf ( optarg , " 0x%llx " , & fact_trl ) ;
break ;
case ' r ' :
if ( ! strncmp ( optarg , " sse " , 3 ) ) {
fact_avx = 0x01 ;
} else if ( ! strncmp ( optarg , " avx2 " , 4 ) ) {
fact_avx = 0x02 ;
} else if ( ! strncmp ( optarg , " avx512 " , 6 ) ) {
fact_avx = 0x04 ;
} else {
fprintf ( outf , " Invalid sse,avx options \n " ) ;
exit ( 1 ) ;
}
break ;
/* CLOS related */
case ' c ' :
current_clos = atoi ( optarg ) ;
break ;
case ' d ' :
clos_desired = atoi ( optarg ) ;
2023-10-24 12:59:35 +02:00
clos_desired / = isst_get_disp_freq_multiplier ( ) ;
2023-08-30 17:31:07 +02:00
break ;
case ' e ' :
clos_epp = atoi ( optarg ) ;
if ( is_skx_based_platform ( ) ) {
isst_display_error_info_message ( 1 , " epp can't be specified on this platform " , 0 , 0 ) ;
exit ( 0 ) ;
}
break ;
case ' n ' :
clos_min = atoi ( optarg ) ;
2023-10-24 12:59:35 +02:00
clos_min / = isst_get_disp_freq_multiplier ( ) ;
2023-08-30 17:31:07 +02:00
break ;
case ' m ' :
clos_max = atoi ( optarg ) ;
2023-10-24 12:59:35 +02:00
clos_max / = isst_get_disp_freq_multiplier ( ) ;
2023-08-30 17:31:07 +02:00
break ;
case ' p ' :
clos_priority_type = atoi ( optarg ) ;
if ( is_skx_based_platform ( ) & & ! clos_priority_type ) {
isst_display_error_info_message ( 1 , " Invalid clos priority type: proportional for this platform " , 0 , 0 ) ;
exit ( 0 ) ;
}
break ;
case ' w ' :
clos_prop_prio = atoi ( optarg ) ;
if ( is_skx_based_platform ( ) ) {
isst_display_error_info_message ( 1 , " weight can't be specified on this platform " , 0 , 0 ) ;
exit ( 0 ) ;
}
break ;
default :
printf ( " Unknown option: ignore \n " ) ;
}
}
if ( argv [ optind ] )
printf ( " Garbage at the end of command: ignore \n " ) ;
}
static void isst_help ( void )
{
printf ( " perf-profile: \t An architectural mechanism that allows multiple optimized \n \
performance profiles per system via static and / or dynamic \ n \
adjustment of core count , workload , Tjmax , and \ n \
TDP , etc . \ n " );
printf ( " \n Commands : For feature=perf-profile \n " ) ;
printf ( " \t info \n " ) ;
if ( ! is_clx_n_platform ( ) ) {
printf ( " \t get-lock-status \n " ) ;
printf ( " \t get-config-levels \n " ) ;
printf ( " \t get-config-version \n " ) ;
printf ( " \t get-config-enabled \n " ) ;
printf ( " \t get-config-current-level \n " ) ;
printf ( " \t set-config-level \n " ) ;
}
}
static void pbf_help ( void )
{
printf ( " base-freq: \t Enables users to increase guaranteed base frequency \n \
on certain cores ( high priority cores ) in exchange for lower \ n \
base frequency on remaining cores ( low priority cores ) . \ n " ) ;
printf ( " \t command : info \n " ) ;
printf ( " \t command : enable \n " ) ;
printf ( " \t command : disable \n " ) ;
}
static void fact_help ( void )
{
printf ( " turbo-freq: \t Enables the ability to set different turbo ratio \n \
limits to cores based on priority . \ n " );
printf ( " \n Command: For feature=turbo-freq \n " ) ;
printf ( " \t command : info \n " ) ;
printf ( " \t command : enable \n " ) ;
printf ( " \t command : disable \n " ) ;
}
static void turbo_mode_help ( void )
{
printf ( " turbo-mode: \t Enables users to enable/disable turbo mode by adjusting frequency settings. Also allows to get and set turbo ratio limits (TRL). \n " ) ;
printf ( " \t command : enable \n " ) ;
printf ( " \t command : disable \n " ) ;
printf ( " \t command : get-trl \n " ) ;
printf ( " \t command : set-trl \n " ) ;
}
static void core_power_help ( void )
{
printf ( " core-power: \t Interface that allows user to define per core/tile \n \
priority . \ n " );
printf ( " \n Commands : For feature=core-power \n " ) ;
printf ( " \t info \n " ) ;
printf ( " \t enable \n " ) ;
printf ( " \t disable \n " ) ;
printf ( " \t config \n " ) ;
printf ( " \t get-config \n " ) ;
printf ( " \t assoc \n " ) ;
printf ( " \t get-assoc \n " ) ;
}
struct process_cmd_help_struct {
char * feature ;
void ( * process_fn ) ( void ) ;
} ;
static struct process_cmd_help_struct isst_help_cmds [ ] = {
{ " perf-profile " , isst_help } ,
{ " base-freq " , pbf_help } ,
{ " turbo-freq " , fact_help } ,
{ " core-power " , core_power_help } ,
{ " turbo-mode " , turbo_mode_help } ,
{ NULL , NULL }
} ;
static struct process_cmd_help_struct clx_n_help_cmds [ ] = {
{ " perf-profile " , isst_help } ,
{ " base-freq " , pbf_help } ,
{ NULL , NULL }
} ;
void process_command ( int argc , char * * argv ,
struct process_cmd_help_struct * help_cmds ,
struct process_cmd_struct * cmds )
{
int i = 0 , matched = 0 ;
char * feature = argv [ optind ] ;
char * cmd = argv [ optind + 1 ] ;
if ( ! feature | | ! cmd )
return ;
debug_printf ( " feature name [%s] command [%s] \n " , feature , cmd ) ;
if ( ! strcmp ( cmd , " -h " ) | | ! strcmp ( cmd , " --help " ) ) {
while ( help_cmds [ i ] . feature ) {
if ( ! strcmp ( help_cmds [ i ] . feature , feature ) ) {
help_cmds [ i ] . process_fn ( ) ;
exit ( 0 ) ;
}
+ + i ;
}
}
i = 0 ;
while ( cmds [ i ] . feature ) {
if ( ! strcmp ( cmds [ i ] . feature , feature ) & &
! strcmp ( cmds [ i ] . command , cmd ) ) {
parse_cmd_args ( argc , optind + 1 , argv ) ;
cmds [ i ] . process_fn ( cmds [ i ] . arg ) ;
matched = 1 ;
break ;
}
+ + i ;
}
if ( ! matched )
fprintf ( stderr , " Invalid command \n " ) ;
}
static void usage ( void )
{
if ( is_clx_n_platform ( ) ) {
fprintf ( stderr , " \n There is limited support of Intel Speed Select features on this platform. \n " ) ;
fprintf ( stderr , " Everything is pre-configured using BIOS options, this tool can't enable any feature in the hardware. \n \n " ) ;
}
printf ( " \n Usage: \n " ) ;
printf ( " intel-speed-select [OPTIONS] FEATURE COMMAND COMMAND_ARGUMENTS \n " ) ;
printf ( " \n Use this tool to enumerate and control the Intel Speed Select Technology features: \n " ) ;
if ( is_clx_n_platform ( ) )
printf ( " \n FEATURE : [perf-profile|base-freq] \n " ) ;
else
printf ( " \n FEATURE : [perf-profile|base-freq|turbo-freq|core-power|turbo-mode] \n " ) ;
printf ( " \n For help on each feature, use -h|--help \n " ) ;
printf ( " \t For example: intel-speed-select perf-profile -h \n " ) ;
printf ( " \n For additional help on each command for a feature, use --h|--help \n " ) ;
printf ( " \t For example: intel-speed-select perf-profile get-lock-status -h \n " ) ;
printf ( " \t \t This will print help for the command \" get-lock-status \" for the feature \" perf-profile \" \n " ) ;
printf ( " \n OPTIONS \n " ) ;
printf ( " \t [-c|--cpu] : logical cpu number \n " ) ;
printf ( " \t \t Default: Die scoped for all dies in the system with multiple dies/package \n " ) ;
printf ( " \t \t \t Or Package scoped for all Packages when each package contains one die \n " ) ;
printf ( " \t [-d|--debug] : Debug mode \n " ) ;
printf ( " \t [-f|--format] : output format [json|text]. Default: text \n " ) ;
printf ( " \t [-h|--help] : Print help \n " ) ;
printf ( " \t [-i|--info] : Print platform information \n " ) ;
printf ( " \t [-a|--all-cpus-online] : Force online every CPU in the system \n " ) ;
printf ( " \t [-o|--out] : Output file \n " ) ;
printf ( " \t \t \t Default : stderr \n " ) ;
printf ( " \t [-p|--pause] : Delay between two mail box commands in milliseconds \n " ) ;
printf ( " \t [-r|--retry] : Retry count for mail box commands on failure, default 3 \n " ) ;
printf ( " \t [-v|--version] : Print version \n " ) ;
printf ( " \t [-b|--oob : Start a daemon to process HFI events for perf profile change from Out of Band agent. \n " ) ;
printf ( " \t [-n|--no-daemon : Don't run as daemon. By default --oob will turn on daemon mode \n " ) ;
printf ( " \t [-w|--delay : Delay for reading config level state change in OOB poll mode. \n " ) ;
2023-10-24 12:59:35 +02:00
printf ( " \t [-g|--cgroupv2 : Try to use cgroup v2 CPU isolation instead of CPU online/offline. \n " ) ;
2023-08-30 17:31:07 +02:00
printf ( " \n Result format \n " ) ;
printf ( " \t Result display uses a common format for each command: \n " ) ;
printf ( " \t Results are formatted in text/JSON with \n " ) ;
printf ( " \t \t Package, Die, CPU, and command specific results. \n " ) ;
printf ( " \n Examples \n " ) ;
printf ( " \t To get platform information: \n " ) ;
printf ( " \t \t intel-speed-select --info \n " ) ;
printf ( " \t To get full perf-profile information dump: \n " ) ;
printf ( " \t \t intel-speed-select perf-profile info \n " ) ;
printf ( " \t To get full base-freq information dump: \n " ) ;
printf ( " \t \t intel-speed-select base-freq info -l 0 \n " ) ;
if ( ! is_clx_n_platform ( ) ) {
printf ( " \t To get full turbo-freq information dump: \n " ) ;
printf ( " \t \t intel-speed-select turbo-freq info -l 0 \n " ) ;
}
exit ( 1 ) ;
}
static void print_version ( void )
{
fprintf ( outf , " Version %s \n " , version_str ) ;
exit ( 0 ) ;
}
static void cmdline ( int argc , char * * argv )
{
const char * pathname = " /dev/isst_interface " ;
char * ptr ;
FILE * fp ;
int opt , force_cpus_online = 0 ;
int option_index = 0 ;
int ret ;
int oob_mode = 0 ;
int poll_interval = - 1 ;
int no_daemon = 0 ;
2023-10-24 12:59:35 +02:00
int mbox_delay = 0 , mbox_retries = 3 ;
2023-08-30 17:31:07 +02:00
static struct option long_options [ ] = {
{ " all-cpus-online " , no_argument , 0 , ' a ' } ,
{ " cpu " , required_argument , 0 , ' c ' } ,
{ " debug " , no_argument , 0 , ' d ' } ,
{ " format " , required_argument , 0 , ' f ' } ,
{ " help " , no_argument , 0 , ' h ' } ,
{ " info " , no_argument , 0 , ' i ' } ,
{ " pause " , required_argument , 0 , ' p ' } ,
{ " out " , required_argument , 0 , ' o ' } ,
{ " retry " , required_argument , 0 , ' r ' } ,
{ " version " , no_argument , 0 , ' v ' } ,
{ " oob " , no_argument , 0 , ' b ' } ,
{ " no-daemon " , no_argument , 0 , ' n ' } ,
{ " poll-interval " , required_argument , 0 , ' w ' } ,
2023-10-24 12:59:35 +02:00
{ " cgroupv2 " , required_argument , 0 , ' g ' } ,
2023-08-30 17:31:07 +02:00
{ 0 , 0 , 0 , 0 }
} ;
if ( geteuid ( ) ! = 0 ) {
fprintf ( stderr , " Must run as root \n " ) ;
exit ( 0 ) ;
}
ret = update_cpu_model ( ) ;
if ( ret )
err ( - 1 , " Invalid CPU model (%d) \n " , cpu_model ) ;
printf ( " Intel(R) Speed Select Technology \n " ) ;
printf ( " Executing on CPU model:%d[0x%x] \n " , cpu_model , cpu_model ) ;
if ( ! is_clx_n_platform ( ) ) {
fp = fopen ( pathname , " rb " ) ;
if ( ! fp ) {
fprintf ( stderr , " Intel speed select drivers are not loaded on this system. \n " ) ;
fprintf ( stderr , " Verify that kernel config includes CONFIG_INTEL_SPEED_SELECT_INTERFACE. \n " ) ;
fprintf ( stderr , " If the config is included then this is not a supported platform. \n " ) ;
exit ( 0 ) ;
}
fclose ( fp ) ;
}
2023-10-24 12:59:35 +02:00
ret = isst_fill_platform_info ( ) ;
if ( ret )
goto out ;
2023-08-30 17:31:07 +02:00
progname = argv [ 0 ] ;
2023-10-24 12:59:35 +02:00
while ( ( opt = getopt_long_only ( argc , argv , " +c:df:hio:vabw:ng " , long_options ,
2023-08-30 17:31:07 +02:00
& option_index ) ) ! = - 1 ) {
switch ( opt ) {
case ' a ' :
force_cpus_online = 1 ;
break ;
case ' c ' :
parse_cpu_command ( optarg ) ;
break ;
case ' d ' :
debug_flag = 1 ;
printf ( " Debug Mode ON \n " ) ;
break ;
case ' f ' :
if ( ! strncmp ( optarg , " json " , 4 ) )
out_format_json = 1 ;
break ;
case ' h ' :
usage ( ) ;
break ;
case ' i ' :
isst_print_platform_information ( ) ;
break ;
case ' o ' :
if ( outf )
fclose ( outf ) ;
outf = fopen_or_exit ( optarg , " w " ) ;
break ;
case ' p ' :
ret = strtol ( optarg , & ptr , 10 ) ;
if ( ! ret )
fprintf ( stderr , " Invalid pause interval, ignore \n " ) ;
else
mbox_delay = ret ;
break ;
case ' r ' :
ret = strtol ( optarg , & ptr , 10 ) ;
if ( ! ret )
fprintf ( stderr , " Invalid retry count, ignore \n " ) ;
else
mbox_retries = ret ;
break ;
case ' v ' :
print_version ( ) ;
break ;
case ' b ' :
oob_mode = 1 ;
break ;
case ' n ' :
no_daemon = 1 ;
break ;
case ' w ' :
ret = strtol ( optarg , & ptr , 10 ) ;
if ( ! ret ) {
fprintf ( stderr , " Invalid poll interval count \n " ) ;
exit ( 0 ) ;
}
poll_interval = ret ;
break ;
2023-10-24 12:59:35 +02:00
case ' g ' :
cgroupv2 = 1 ;
break ;
2023-08-30 17:31:07 +02:00
default :
usage ( ) ;
}
}
if ( optind > ( argc - 2 ) & & ! oob_mode ) {
usage ( ) ;
exit ( 0 ) ;
}
2023-10-24 12:59:35 +02:00
isst_update_platform_param ( ISST_PARAM_MBOX_DELAY , mbox_delay ) ;
isst_update_platform_param ( ISST_PARAM_MBOX_RETRIES , mbox_retries ) ;
2023-08-30 17:31:07 +02:00
set_max_cpu_num ( ) ;
if ( force_cpus_online )
force_all_cpus_online ( ) ;
store_cpu_topology ( ) ;
create_cpu_map ( ) ;
if ( oob_mode ) {
if ( debug_flag )
fprintf ( stderr , " OOB mode is enabled in debug mode \n " ) ;
ret = isst_daemon ( debug_flag , poll_interval , no_daemon ) ;
if ( ret )
fprintf ( stderr , " OOB mode enable failed \n " ) ;
goto out ;
}
if ( ! is_clx_n_platform ( ) ) {
process_command ( argc , argv , isst_help_cmds , isst_cmds ) ;
} else {
process_command ( argc , argv , clx_n_help_cmds , clx_n_cmds ) ;
}
out :
free_cpu_set ( present_cpumask ) ;
free_cpu_set ( target_cpumask ) ;
}
int main ( int argc , char * * argv )
{
outf = stderr ;
cmdline ( argc , argv ) ;
return 0 ;
}