@ -6,6 +6,7 @@
# include <stdio.h>
# include <sys/sysinfo.h>
# include <netlink/genl/genl.h>
# include <netlink/genl/family.h>
# include <netlink/genl/ctrl.h>
@ -14,8 +15,62 @@
cpumask_t thermal_banned_cpus ;
# define INVALID_NL_FD -1
# define MAX_RECV_ERRS 2
/* Events of thermal_genl_family */
enum thermal_genl_event {
THERMAL_GENL_EVENT_UNSPEC ,
THERMAL_GENL_EVENT_TZ_CREATE , /* Thermal zone creation */
THERMAL_GENL_EVENT_TZ_DELETE , /* Thermal zone deletion */
THERMAL_GENL_EVENT_TZ_DISABLE , /* Thermal zone disabled */
THERMAL_GENL_EVENT_TZ_ENABLE , /* Thermal zone enabled */
THERMAL_GENL_EVENT_TZ_TRIP_UP , /* Trip point crossed the way up */
THERMAL_GENL_EVENT_TZ_TRIP_DOWN , /* Trip point crossed the way down */
THERMAL_GENL_EVENT_TZ_TRIP_CHANGE , /* Trip point changed */
THERMAL_GENL_EVENT_TZ_TRIP_ADD , /* Trip point added */
THERMAL_GENL_EVENT_TZ_TRIP_DELETE , /* Trip point deleted */
THERMAL_GENL_EVENT_CDEV_ADD , /* Cdev bound to the thermal zone */
THERMAL_GENL_EVENT_CDEV_DELETE , /* Cdev unbound */
THERMAL_GENL_EVENT_CDEV_STATE_UPDATE , /* Cdev state updated */
THERMAL_GENL_EVENT_TZ_GOV_CHANGE , /* Governor policy changed */
THERMAL_GENL_EVENT_CAPACITY_CHANGE , /* CPU capacity changed */
__THERMAL_GENL_EVENT_MAX ,
} ;
# define THERMAL_GENL_EVENT_MAX (__THERMAL_GENL_EVENT_MAX - 1)
/* Attributes of thermal_genl_family */
enum thermal_genl_attr {
THERMAL_GENL_ATTR_UNSPEC ,
THERMAL_GENL_ATTR_TZ ,
THERMAL_GENL_ATTR_TZ_ID ,
THERMAL_GENL_ATTR_TZ_TEMP ,
THERMAL_GENL_ATTR_TZ_TRIP ,
THERMAL_GENL_ATTR_TZ_TRIP_ID ,
THERMAL_GENL_ATTR_TZ_TRIP_TYPE ,
THERMAL_GENL_ATTR_TZ_TRIP_TEMP ,
THERMAL_GENL_ATTR_TZ_TRIP_HYST ,
THERMAL_GENL_ATTR_TZ_MODE ,
THERMAL_GENL_ATTR_TZ_NAME ,
THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT ,
THERMAL_GENL_ATTR_TZ_GOV ,
THERMAL_GENL_ATTR_TZ_GOV_NAME ,
THERMAL_GENL_ATTR_CDEV ,
THERMAL_GENL_ATTR_CDEV_ID ,
THERMAL_GENL_ATTR_CDEV_CUR_STATE ,
THERMAL_GENL_ATTR_CDEV_MAX_STATE ,
THERMAL_GENL_ATTR_CDEV_NAME ,
THERMAL_GENL_ATTR_GOV_NAME ,
THERMAL_GENL_ATTR_CAPACITY ,
THERMAL_GENL_ATTR_CAPACITY_CPU_COUNT ,
THERMAL_GENL_ATTR_CAPACITY_CPU_ID ,
THERMAL_GENL_ATTR_CAPACITY_CPU_PERF ,
THERMAL_GENL_ATTR_CAPACITY_CPU_EFF ,
__THERMAL_GENL_ATTR_MAX ,
} ;
# define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)
# define INVALID_NL_FD -1
# define MAX_RECV_ERRS 2
# define SYSCONF_ERR -1
# define INVALID_EVENT_VALUE -1
# define THERMAL_GENL_FAMILY_NAME "thermal"
# define THERMAL_GENL_EVENT_GROUP_NAME "event"
@ -254,17 +309,115 @@ err_out:
return error ;
}
static int handle_thermal_event ( struct nl_msg * msg __attribute__ ( ( unused ) ) ,
void * arg __attribute__ ( ( unused ) ) )
enum {
INDEX_CPUNUM ,
INDEX_PERF ,
INDEX_EFFI ,
INDEX_MAX
} ;
/*
* Single netlink notification is not guaranteed to fully deliver all of
* the CPU updates per thermal event , due to the implementation choice in
* the kernel code . So , this function is intended to manage a CPU list in a
* stream of relevant notifications .
*/
static void update_banned_cpus ( int cur_cpuidx , gboolean need_to_ban )
{
log ( TO_ALL , LOG_ERR , " thermal: not yet implemented to process thermal event. \n " ) ;
return NL_SKIP ;
static cpumask_t banmask = { 0 } , itrmask = { 0 } ;
long max_cpunum = sysconf ( _SC_NPROCESSORS_ONLN ) ;
if ( need_to_ban )
cpu_set ( cur_cpuidx , banmask ) ;
cpu_set ( cur_cpuidx , itrmask ) ;
if ( cpus_weight ( itrmask ) < max_cpunum )
return ;
if ( cpus_equal ( thermal_banned_cpus , banmask ) )
goto out ;
cpus_copy ( thermal_banned_cpus , banmask ) ;
need_rescan = 1 ;
out :
cpus_clear ( banmask ) ;
cpus_clear ( itrmask ) ;
}
static int handle_thermal_event ( struct nl_msg * msg , void * arg __attribute__ ( ( unused ) ) )
{
int event_data [ INDEX_MAX ] = { INVALID_EVENT_VALUE } ;
struct nlattr * attrs [ THERMAL_GENL_ATTR_MAX + 1 ] ;
struct genlmsghdr * genlhdr ;
struct nlmsghdr * msnlh ;
struct nlattr * cap ;
int i , remain , rc ;
void * pos ;
/* get actual netlink message header */
msnlh = nlmsg_hdr ( msg ) ;
/* get a pointer to generic netlink header */
genlhdr = genlmsg_hdr ( msnlh ) ;
if ( genlhdr - > cmd ! = THERMAL_GENL_EVENT_CAPACITY_CHANGE ) {
log ( TO_ALL , LOG_DEBUG , " thermal: no CPU capacity change. \n " ) ;
return NL_SKIP ;
}
/* parse generic netlink message including attributes */
rc = genlmsg_parse (
msnlh , /* a pointer to netlink message header */
0 , /* length of user header */
attrs , /* array to store parsed attributes */
THERMAL_GENL_ATTR_MAX , /* maximum attribute id as expected */
NULL ) ; /* validation policy */
if ( rc ) {
log ( TO_ALL , LOG_ERR , " thermal: failed to parse message for thermal event. \n " ) ;
return NL_SKIP ;
}
/* get start and length of payload section */
cap = attrs [ THERMAL_GENL_ATTR_CAPACITY ] ;
pos = nla_data ( cap ) ;
remain = nla_len ( cap ) ;
for ( i = 0 ; nla_ok ( pos , remain ) ; pos = nla_next ( pos , & remain ) , i + + ) {
gboolean valid_event = TRUE , need_to_ban ;
unsigned int value = nla_get_u32 ( pos ) ;
int idx = i % INDEX_MAX ;
int cur_cpuidx ;
event_data [ idx ] = value ;
if ( idx ! = INDEX_EFFI )
continue ;
cur_cpuidx = event_data [ INDEX_CPUNUM ] ;
valid_event = ! ! ( cur_cpuidx < = NR_CPUS ) ;
if ( ! valid_event ) {
log ( TO_ALL , LOG_WARNING , " thermal: invalid event - CPU %d \n " ,
cur_cpuidx ) ;
continue ;
}
/*
* A CPU with no performance and no efficiency cannot
* handle IRQs :
*/
need_to_ban = ! ! ( ! event_data [ INDEX_PERF ] & & ! event_data [ INDEX_EFFI ] ) ;
update_banned_cpus ( cur_cpuidx , need_to_ban ) ;
log ( TO_ALL , LOG_DEBUG , " thermal: event - CPU %d, efficiency %d, perf %d. \n " ,
cur_cpuidx , event_data [ INDEX_PERF ] , event_data [ INDEX_EFFI ] ) ;
}
return NL_OK ;
}
static int handler_for_debug ( struct nl_msg * msg __attribute__ ( ( unused ) ) ,
void * arg __attribute__ ( ( unused ) ) )
{
return NL_SKIP ;
return NL_ OK ;
}
/*
@ -274,6 +427,11 @@ static gboolean register_netlink_handler(void)
{
int rc ;
if ( sysconf ( _SC_NPROCESSORS_ONLN ) = = SYSCONF_ERR ) {
log ( TO_ALL , LOG_ERR , " thermal: _SC_NPROCESSORS_ONLN not available. \n " ) ;
return TRUE ;
}
rc = nl_cb_set ( callback , NL_CB_SEQ_CHECK , NL_CB_CUSTOM , handler_for_debug , NULL ) ;
if ( rc ) {
log ( TO_ALL , LOG_ERR , " thermal: debug handler registration failed. \n " ) ;