2018-05-07 20:52:29 +03:00
// SPDX-License-Identifier: GPL-2.0
2013-07-03 23:35:39 +04:00
/*
* of - thermal . c - Generic Thermal Management device tree support .
*
* Copyright ( C ) 2013 Texas Instruments
* Copyright ( C ) 2013 Eduardo Valentin < eduardo . valentin @ ti . com >
*/
2019-02-24 10:10:58 +03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2013-07-03 23:35:39 +04:00
# include <linux/err.h>
# include <linux/export.h>
2020-05-11 15:24:59 +03:00
# include <linux/of_device.h>
# include <linux/of_platform.h>
# include <linux/slab.h>
# include <linux/thermal.h>
# include <linux/types.h>
2013-07-03 23:35:39 +04:00
# include <linux/string.h>
# include "thermal_core.h"
/*** Private data structures to represent thermal device tree data ***/
/**
2018-08-08 10:08:14 +03:00
* struct __thermal_cooling_bind_param - a cooling device for a trip point
2013-07-03 23:35:39 +04:00
* @ cooling_device : a pointer to identify the referred cooling device
* @ min : minimum cooling state used at this trip point
* @ max : maximum cooling state used at this trip point
*/
2018-08-08 10:08:14 +03:00
struct __thermal_cooling_bind_param {
2013-07-03 23:35:39 +04:00
struct device_node * cooling_device ;
unsigned long min ;
unsigned long max ;
} ;
2018-08-08 10:08:14 +03:00
/**
* struct __thermal_bind_param - a match between trip and cooling device
* @ tcbp : a pointer to an array of cooling devices
* @ count : number of elements in array
* @ trip_id : the trip point index
* @ usage : the percentage ( from 0 to 100 ) of cooling contribution
*/
struct __thermal_bind_params {
struct __thermal_cooling_bind_param * tcbp ;
unsigned int count ;
unsigned int trip_id ;
unsigned int usage ;
} ;
2013-07-03 23:35:39 +04:00
/**
* struct __thermal_zone - internal representation of a thermal zone
* @ mode : current thermal zone device mode ( enabled / disabled )
* @ passive_delay : polling interval while passive cooling is activated
* @ polling_delay : zone polling interval
2015-05-12 05:48:09 +03:00
* @ slope : slope of the temperature adjustment curve
* @ offset : offset of the temperature adjustment curve
2013-07-03 23:35:39 +04:00
* @ ntrips : number of trip points
* @ trips : an array of trip points ( 0. . ntrips - 1 )
* @ num_tbps : number of thermal bind params
* @ tbps : an array of thermal bind params ( 0. . num_tbps - 1 )
* @ sensor_data : sensor private data used while reading temperature and trend
2014-11-08 04:24:39 +03:00
* @ ops : set of callbacks to handle the thermal zone based on DT
2013-07-03 23:35:39 +04:00
*/
struct __thermal_zone {
enum thermal_device_mode mode ;
int passive_delay ;
int polling_delay ;
2015-05-12 05:48:09 +03:00
int slope ;
int offset ;
2013-07-03 23:35:39 +04:00
/* trip data */
int ntrips ;
2014-12-08 20:04:19 +03:00
struct thermal_trip * trips ;
2013-07-03 23:35:39 +04:00
/* cooling binding data */
int num_tbps ;
struct __thermal_bind_params * tbps ;
/* sensor interface */
void * sensor_data ;
2014-11-08 04:24:39 +03:00
const struct thermal_zone_of_device_ops * ops ;
2013-07-03 23:35:39 +04:00
} ;
/*** DT thermal zone device callbacks ***/
static int of_thermal_get_temp ( struct thermal_zone_device * tz ,
2015-07-24 09:12:54 +03:00
int * temp )
2013-07-03 23:35:39 +04:00
{
struct __thermal_zone * data = tz - > devdata ;
2014-11-08 04:24:39 +03:00
if ( ! data - > ops - > get_temp )
2013-07-03 23:35:39 +04:00
return - EINVAL ;
2014-11-08 04:24:39 +03:00
return data - > ops - > get_temp ( data - > sensor_data , temp ) ;
2013-07-03 23:35:39 +04:00
}
2016-06-22 11:42:02 +03:00
static int of_thermal_set_trips ( struct thermal_zone_device * tz ,
int low , int high )
{
struct __thermal_zone * data = tz - > devdata ;
if ( ! data - > ops | | ! data - > ops - > set_trips )
return - EINVAL ;
return data - > ops - > set_trips ( data - > sensor_data , low , high ) ;
}
2014-12-08 20:04:17 +03:00
/**
* of_thermal_get_ntrips - function to export number of available trip
* points .
* @ tz : pointer to a thermal zone
*
* This function is a globally visible wrapper to get number of trip points
* stored in the local struct __thermal_zone
*
* Return : number of available trip points , - ENODEV when data not available
*/
int of_thermal_get_ntrips ( struct thermal_zone_device * tz )
{
struct __thermal_zone * data = tz - > devdata ;
if ( ! data | | IS_ERR ( data ) )
return - ENODEV ;
return data - > ntrips ;
}
EXPORT_SYMBOL_GPL ( of_thermal_get_ntrips ) ;
2014-12-08 20:04:18 +03:00
/**
* of_thermal_is_trip_valid - function to check if trip point is valid
*
* @ tz : pointer to a thermal zone
* @ trip : trip point to evaluate
*
* This function is responsible for checking if passed trip point is valid
*
* Return : true if trip point is valid , false otherwise
*/
bool of_thermal_is_trip_valid ( struct thermal_zone_device * tz , int trip )
{
struct __thermal_zone * data = tz - > devdata ;
if ( ! data | | trip > = data - > ntrips | | trip < 0 )
return false ;
return true ;
}
EXPORT_SYMBOL_GPL ( of_thermal_is_trip_valid ) ;
2014-12-08 20:04:20 +03:00
/**
* of_thermal_get_trip_points - function to get access to a globally exported
* trip points
*
* @ tz : pointer to a thermal zone
*
* This function provides a pointer to trip points table
*
* Return : pointer to trip points table , NULL otherwise
*/
2015-01-04 00:56:56 +03:00
const struct thermal_trip *
2014-12-08 20:04:20 +03:00
of_thermal_get_trip_points ( struct thermal_zone_device * tz )
{
struct __thermal_zone * data = tz - > devdata ;
if ( ! data )
return NULL ;
return data - > trips ;
}
EXPORT_SYMBOL_GPL ( of_thermal_get_trip_points ) ;
2014-12-08 20:04:21 +03:00
/**
* of_thermal_set_emul_temp - function to set emulated temperature
*
* @ tz : pointer to a thermal zone
* @ temp : temperature to set
*
* This function gives the ability to set emulated value of temperature ,
* which is handy for debugging
*
* Return : zero on success , error code otherwise
*/
static int of_thermal_set_emul_temp ( struct thermal_zone_device * tz ,
2015-07-24 09:12:54 +03:00
int temp )
2014-12-08 20:04:21 +03:00
{
struct __thermal_zone * data = tz - > devdata ;
return data - > ops - > set_emul_temp ( data - > sensor_data , temp ) ;
}
2013-07-03 23:35:39 +04:00
static int of_thermal_get_trend ( struct thermal_zone_device * tz , int trip ,
enum thermal_trend * trend )
{
struct __thermal_zone * data = tz - > devdata ;
2014-11-08 04:24:39 +03:00
if ( ! data - > ops - > get_trend )
2013-07-03 23:35:39 +04:00
return - EINVAL ;
2016-06-22 11:42:03 +03:00
return data - > ops - > get_trend ( data - > sensor_data , trip , trend ) ;
2013-07-03 23:35:39 +04:00
}
static int of_thermal_bind ( struct thermal_zone_device * thermal ,
struct thermal_cooling_device * cdev )
{
struct __thermal_zone * data = thermal - > devdata ;
2018-08-08 10:08:14 +03:00
struct __thermal_bind_params * tbp ;
struct __thermal_cooling_bind_param * tcbp ;
int i , j ;
2013-07-03 23:35:39 +04:00
if ( ! data | | IS_ERR ( data ) )
return - ENODEV ;
/* find where to bind */
for ( i = 0 ; i < data - > num_tbps ; i + + ) {
2018-08-08 10:08:14 +03:00
tbp = data - > tbps + i ;
2013-07-03 23:35:39 +04:00
2018-08-08 10:08:14 +03:00
for ( j = 0 ; j < tbp - > count ; j + + ) {
tcbp = tbp - > tcbp + j ;
2013-07-03 23:35:39 +04:00
2018-08-08 10:08:14 +03:00
if ( tcbp - > cooling_device = = cdev - > np ) {
int ret ;
ret = thermal_zone_bind_cooling_device ( thermal ,
2013-07-03 23:35:39 +04:00
tbp - > trip_id , cdev ,
2018-08-08 10:08:14 +03:00
tcbp - > max ,
tcbp - > min ,
2015-02-18 19:04:21 +03:00
tbp - > usage ) ;
2018-08-08 10:08:14 +03:00
if ( ret )
return ret ;
}
2013-07-03 23:35:39 +04:00
}
}
return 0 ;
}
static int of_thermal_unbind ( struct thermal_zone_device * thermal ,
struct thermal_cooling_device * cdev )
{
struct __thermal_zone * data = thermal - > devdata ;
2018-08-08 10:08:14 +03:00
struct __thermal_bind_params * tbp ;
struct __thermal_cooling_bind_param * tcbp ;
int i , j ;
2013-07-03 23:35:39 +04:00
if ( ! data | | IS_ERR ( data ) )
return - ENODEV ;
/* find where to unbind */
for ( i = 0 ; i < data - > num_tbps ; i + + ) {
2018-08-08 10:08:14 +03:00
tbp = data - > tbps + i ;
for ( j = 0 ; j < tbp - > count ; j + + ) {
tcbp = tbp - > tcbp + j ;
2013-07-03 23:35:39 +04:00
2018-08-08 10:08:14 +03:00
if ( tcbp - > cooling_device = = cdev - > np ) {
int ret ;
2013-07-03 23:35:39 +04:00
2018-08-08 10:08:14 +03:00
ret = thermal_zone_unbind_cooling_device ( thermal ,
tbp - > trip_id , cdev ) ;
if ( ret )
return ret ;
}
2013-07-03 23:35:39 +04:00
}
}
return 0 ;
}
static int of_thermal_get_mode ( struct thermal_zone_device * tz ,
enum thermal_device_mode * mode )
{
struct __thermal_zone * data = tz - > devdata ;
* mode = data - > mode ;
return 0 ;
}
static int of_thermal_set_mode ( struct thermal_zone_device * tz ,
enum thermal_device_mode mode )
{
struct __thermal_zone * data = tz - > devdata ;
mutex_lock ( & tz - > lock ) ;
2018-07-30 19:56:49 +03:00
if ( mode = = THERMAL_DEVICE_ENABLED ) {
2013-07-03 23:35:39 +04:00
tz - > polling_delay = data - > polling_delay ;
2018-07-30 19:56:49 +03:00
tz - > passive_delay = data - > passive_delay ;
} else {
2013-07-03 23:35:39 +04:00
tz - > polling_delay = 0 ;
2018-07-30 19:56:49 +03:00
tz - > passive_delay = 0 ;
}
2013-07-03 23:35:39 +04:00
mutex_unlock ( & tz - > lock ) ;
data - > mode = mode ;
2016-08-27 02:21:16 +03:00
thermal_zone_device_update ( tz , THERMAL_EVENT_UNSPECIFIED ) ;
2013-07-03 23:35:39 +04:00
return 0 ;
}
static int of_thermal_get_trip_type ( struct thermal_zone_device * tz , int trip ,
enum thermal_trip_type * type )
{
struct __thermal_zone * data = tz - > devdata ;
if ( trip > = data - > ntrips | | trip < 0 )
return - EDOM ;
* type = data - > trips [ trip ] . type ;
return 0 ;
}
static int of_thermal_get_trip_temp ( struct thermal_zone_device * tz , int trip ,
2015-07-24 09:12:54 +03:00
int * temp )
2013-07-03 23:35:39 +04:00
{
struct __thermal_zone * data = tz - > devdata ;
if ( trip > = data - > ntrips | | trip < 0 )
return - EDOM ;
* temp = data - > trips [ trip ] . temperature ;
return 0 ;
}
static int of_thermal_set_trip_temp ( struct thermal_zone_device * tz , int trip ,
2015-07-24 09:12:54 +03:00
int temp )
2013-07-03 23:35:39 +04:00
{
struct __thermal_zone * data = tz - > devdata ;
if ( trip > = data - > ntrips | | trip < 0 )
return - EDOM ;
2016-03-29 13:29:17 +03:00
if ( data - > ops - > set_trip_temp ) {
int ret ;
ret = data - > ops - > set_trip_temp ( data - > sensor_data , trip , temp ) ;
if ( ret )
return ret ;
}
2013-07-03 23:35:39 +04:00
/* thermal framework should take care of data->mask & (1 << trip) */
data - > trips [ trip ] . temperature = temp ;
return 0 ;
}
static int of_thermal_get_trip_hyst ( struct thermal_zone_device * tz , int trip ,
2015-07-24 09:12:54 +03:00
int * hyst )
2013-07-03 23:35:39 +04:00
{
struct __thermal_zone * data = tz - > devdata ;
if ( trip > = data - > ntrips | | trip < 0 )
return - EDOM ;
* hyst = data - > trips [ trip ] . hysteresis ;
return 0 ;
}
static int of_thermal_set_trip_hyst ( struct thermal_zone_device * tz , int trip ,
2015-07-24 09:12:54 +03:00
int hyst )
2013-07-03 23:35:39 +04:00
{
struct __thermal_zone * data = tz - > devdata ;
if ( trip > = data - > ntrips | | trip < 0 )
return - EDOM ;
/* thermal framework should take care of data->mask & (1 << trip) */
data - > trips [ trip ] . hysteresis = hyst ;
return 0 ;
}
static int of_thermal_get_crit_temp ( struct thermal_zone_device * tz ,
2015-07-24 09:12:54 +03:00
int * temp )
2013-07-03 23:35:39 +04:00
{
struct __thermal_zone * data = tz - > devdata ;
int i ;
for ( i = 0 ; i < data - > ntrips ; i + + )
if ( data - > trips [ i ] . type = = THERMAL_TRIP_CRITICAL ) {
* temp = data - > trips [ i ] . temperature ;
return 0 ;
}
return - EINVAL ;
}
static struct thermal_zone_device_ops of_thermal_ops = {
. get_mode = of_thermal_get_mode ,
. set_mode = of_thermal_set_mode ,
. get_trip_type = of_thermal_get_trip_type ,
. get_trip_temp = of_thermal_get_trip_temp ,
. set_trip_temp = of_thermal_set_trip_temp ,
. get_trip_hyst = of_thermal_get_trip_hyst ,
. set_trip_hyst = of_thermal_set_trip_hyst ,
. get_crit_temp = of_thermal_get_crit_temp ,
. bind = of_thermal_bind ,
. unbind = of_thermal_unbind ,
} ;
/*** sensor API ***/
static struct thermal_zone_device *
thermal_zone_of_add_sensor ( struct device_node * zone ,
struct device_node * sensor , void * data ,
2014-11-08 04:24:39 +03:00
const struct thermal_zone_of_device_ops * ops )
2013-07-03 23:35:39 +04:00
{
struct thermal_zone_device * tzd ;
struct __thermal_zone * tz ;
tzd = thermal_zone_get_zone_by_name ( zone - > name ) ;
if ( IS_ERR ( tzd ) )
return ERR_PTR ( - EPROBE_DEFER ) ;
tz = tzd - > devdata ;
2014-11-08 04:24:39 +03:00
if ( ! ops )
return ERR_PTR ( - EINVAL ) ;
2013-07-03 23:35:39 +04:00
mutex_lock ( & tzd - > lock ) ;
2014-11-08 04:24:39 +03:00
tz - > ops = ops ;
2013-07-03 23:35:39 +04:00
tz - > sensor_data = data ;
tzd - > ops - > get_temp = of_thermal_get_temp ;
tzd - > ops - > get_trend = of_thermal_get_trend ;
2016-06-22 11:42:02 +03:00
/*
* The thermal zone core will calculate the window if they have set the
* optional set_trips pointer .
*/
if ( ops - > set_trips )
tzd - > ops - > set_trips = of_thermal_set_trips ;
2016-06-02 11:54:50 +03:00
if ( ops - > set_emul_temp )
tzd - > ops - > set_emul_temp = of_thermal_set_emul_temp ;
2013-07-03 23:35:39 +04:00
mutex_unlock ( & tzd - > lock ) ;
return tzd ;
}
2020-02-22 03:08:49 +03:00
/**
* thermal_zone_of_get_sensor_id - get sensor ID from a DT thermal zone
* @ tz_np : a valid thermal zone device node .
* @ sensor_np : a sensor node of a valid sensor device .
* @ id : the sensor ID returned if success .
*
* This function will get sensor ID from a given thermal zone node and
* the sensor node must match the temperature provider @ sensor_np .
*
* Return : 0 on success , proper error code otherwise .
*/
int thermal_zone_of_get_sensor_id ( struct device_node * tz_np ,
struct device_node * sensor_np ,
u32 * id )
{
struct of_phandle_args sensor_specs ;
int ret ;
ret = of_parse_phandle_with_args ( tz_np ,
" thermal-sensors " ,
" #thermal-sensor-cells " ,
0 ,
& sensor_specs ) ;
if ( ret )
return ret ;
if ( sensor_specs . np ! = sensor_np ) {
of_node_put ( sensor_specs . np ) ;
return - ENODEV ;
}
if ( sensor_specs . args_count > 1 )
pr_warn ( " %pOFn: too many cells in sensor specifier %d \n " ,
sensor_specs . np , sensor_specs . args_count ) ;
* id = sensor_specs . args_count ? sensor_specs . args [ 0 ] : 0 ;
of_node_put ( sensor_specs . np ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( thermal_zone_of_get_sensor_id ) ;
2013-07-03 23:35:39 +04:00
/**
* thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone
* @ dev : a valid struct device pointer of a sensor device . Must contain
* a valid . of_node , for the sensor node .
* @ sensor_id : a sensor identifier , in case the sensor IP has more
* than one sensors
* @ data : a private pointer ( owned by the caller ) that will be passed
* back , when a temperature reading is needed .
2014-11-08 04:24:39 +03:00
* @ ops : struct thermal_zone_of_device_ops * . Must contain at least . get_temp .
2013-07-03 23:35:39 +04:00
*
* This function will search the list of thermal zones described in device
* tree and look for the zone that refer to the sensor device pointed by
* @ dev - > of_node as temperature providers . For the zone pointing to the
* sensor node , the sensor will be added to the DT thermal zone device .
*
* The thermal zone temperature is provided by the @ get_temp function
* pointer . When called , it will have the private pointer @ data back .
*
* The thermal zone temperature trend is provided by the @ get_trend function
* pointer . When called , it will have the private pointer @ data back .
*
* TODO :
* 01 - This function must enqueue the new sensor instead of using
* it as the only source of temperature values .
*
* 02 - There must be a way to match the sensor with all thermal zones
* that refer to it .
*
* Return : On success returns a valid struct thermal_zone_device ,
* otherwise , it returns a corresponding ERR_PTR ( ) . Caller must
* check the return value with help of IS_ERR ( ) helper .
*/
struct thermal_zone_device *
2014-11-08 04:24:39 +03:00
thermal_zone_of_sensor_register ( struct device * dev , int sensor_id , void * data ,
const struct thermal_zone_of_device_ops * ops )
2013-07-03 23:35:39 +04:00
{
struct device_node * np , * child , * sensor_np ;
2014-09-29 03:47:46 +04:00
struct thermal_zone_device * tzd = ERR_PTR ( - ENODEV ) ;
2013-07-03 23:35:39 +04:00
np = of_find_node_by_name ( NULL , " thermal-zones " ) ;
if ( ! np )
return ERR_PTR ( - ENODEV ) ;
2014-09-29 03:47:46 +04:00
if ( ! dev | | ! dev - > of_node ) {
of_node_put ( np ) ;
2019-08-27 17:39:52 +03:00
return ERR_PTR ( - ENODEV ) ;
2014-09-29 03:47:46 +04:00
}
2013-07-03 23:35:39 +04:00
2014-09-29 03:47:46 +04:00
sensor_np = of_node_get ( dev - > of_node ) ;
2013-07-03 23:35:39 +04:00
2016-02-08 16:28:34 +03:00
for_each_available_child_of_node ( np , child ) {
2013-07-03 23:35:39 +04:00
int ret , id ;
/* For now, thermal framework supports only 1 sensor per zone */
2020-02-22 03:08:49 +03:00
ret = thermal_zone_of_get_sensor_id ( child , sensor_np , & id ) ;
2013-07-03 23:35:39 +04:00
if ( ret )
continue ;
2020-02-22 03:08:49 +03:00
if ( id = = sensor_id ) {
2014-09-29 03:47:46 +04:00
tzd = thermal_zone_of_add_sensor ( child , sensor_np ,
2014-11-08 04:24:39 +03:00
data , ops ) ;
2015-01-19 14:44:04 +03:00
if ( ! IS_ERR ( tzd ) )
tzd - > ops - > set_mode ( tzd , THERMAL_DEVICE_ENABLED ) ;
2014-09-29 03:47:46 +04:00
of_node_put ( child ) ;
goto exit ;
2013-07-03 23:35:39 +04:00
}
}
2014-09-29 03:47:46 +04:00
exit :
of_node_put ( sensor_np ) ;
2013-07-03 23:35:39 +04:00
of_node_put ( np ) ;
2014-09-29 03:47:46 +04:00
return tzd ;
2013-07-03 23:35:39 +04:00
}
EXPORT_SYMBOL_GPL ( thermal_zone_of_sensor_register ) ;
/**
* thermal_zone_of_sensor_unregister - unregisters a sensor from a DT thermal zone
* @ dev : a valid struct device pointer of a sensor device . Must contain
* a valid . of_node , for the sensor node .
* @ tzd : a pointer to struct thermal_zone_device where the sensor is registered .
*
* This function removes the sensor callbacks and private data from the
* thermal zone device registered with thermal_zone_of_sensor_register ( )
* API . It will also silent the zone by remove the . get_temp ( ) and . get_trend ( )
* thermal zone device callbacks .
*
* TODO : When the support to several sensors per zone is added , this
* function must search the sensor list based on @ dev parameter .
*
*/
void thermal_zone_of_sensor_unregister ( struct device * dev ,
struct thermal_zone_device * tzd )
{
struct __thermal_zone * tz ;
if ( ! dev | | ! tzd | | ! tzd - > devdata )
return ;
tz = tzd - > devdata ;
/* no __thermal_zone, nothing to be done */
if ( ! tz )
return ;
mutex_lock ( & tzd - > lock ) ;
tzd - > ops - > get_temp = NULL ;
tzd - > ops - > get_trend = NULL ;
2014-12-08 20:04:21 +03:00
tzd - > ops - > set_emul_temp = NULL ;
2013-07-03 23:35:39 +04:00
2014-11-08 04:24:39 +03:00
tz - > ops = NULL ;
2013-07-03 23:35:39 +04:00
tz - > sensor_data = NULL ;
mutex_unlock ( & tzd - > lock ) ;
}
EXPORT_SYMBOL_GPL ( thermal_zone_of_sensor_unregister ) ;
2016-03-09 16:10:06 +03:00
static void devm_thermal_zone_of_sensor_release ( struct device * dev , void * res )
{
thermal_zone_of_sensor_unregister ( dev ,
* ( struct thermal_zone_device * * ) res ) ;
}
static int devm_thermal_zone_of_sensor_match ( struct device * dev , void * res ,
void * data )
{
struct thermal_zone_device * * r = res ;
if ( WARN_ON ( ! r | | ! * r ) )
return 0 ;
return * r = = data ;
}
/**
* devm_thermal_zone_of_sensor_register - Resource managed version of
* thermal_zone_of_sensor_register ( )
* @ dev : a valid struct device pointer of a sensor device . Must contain
* a valid . of_node , for the sensor node .
* @ sensor_id : a sensor identifier , in case the sensor IP has more
* than one sensors
* @ data : a private pointer ( owned by the caller ) that will be passed
* back , when a temperature reading is needed .
* @ ops : struct thermal_zone_of_device_ops * . Must contain at least . get_temp .
*
* Refer thermal_zone_of_sensor_register ( ) for more details .
*
* Return : On success returns a valid struct thermal_zone_device ,
* otherwise , it returns a corresponding ERR_PTR ( ) . Caller must
* check the return value with help of IS_ERR ( ) helper .
2016-08-22 10:48:11 +03:00
* Registered thermal_zone_device device will automatically be
2016-03-09 16:10:06 +03:00
* released when device is unbounded .
*/
struct thermal_zone_device * devm_thermal_zone_of_sensor_register (
struct device * dev , int sensor_id ,
void * data , const struct thermal_zone_of_device_ops * ops )
{
struct thermal_zone_device * * ptr , * tzd ;
ptr = devres_alloc ( devm_thermal_zone_of_sensor_release , sizeof ( * ptr ) ,
GFP_KERNEL ) ;
if ( ! ptr )
return ERR_PTR ( - ENOMEM ) ;
tzd = thermal_zone_of_sensor_register ( dev , sensor_id , data , ops ) ;
if ( IS_ERR ( tzd ) ) {
devres_free ( ptr ) ;
return tzd ;
}
* ptr = tzd ;
devres_add ( dev , ptr ) ;
return tzd ;
}
EXPORT_SYMBOL_GPL ( devm_thermal_zone_of_sensor_register ) ;
/**
* devm_thermal_zone_of_sensor_unregister - Resource managed version of
* thermal_zone_of_sensor_unregister ( ) .
* @ dev : Device for which which resource was allocated .
* @ tzd : a pointer to struct thermal_zone_device where the sensor is registered .
*
* This function removes the sensor callbacks and private data from the
* thermal zone device registered with devm_thermal_zone_of_sensor_register ( )
* API . It will also silent the zone by remove the . get_temp ( ) and . get_trend ( )
* thermal zone device callbacks .
* Normally this function will not need to be called and the resource
* management code will ensure that the resource is freed .
*/
void devm_thermal_zone_of_sensor_unregister ( struct device * dev ,
struct thermal_zone_device * tzd )
{
WARN_ON ( devres_release ( dev , devm_thermal_zone_of_sensor_release ,
devm_thermal_zone_of_sensor_match , tzd ) ) ;
}
EXPORT_SYMBOL_GPL ( devm_thermal_zone_of_sensor_unregister ) ;
2013-07-03 23:35:39 +04:00
/*** functions parsing device tree nodes ***/
/**
* thermal_of_populate_bind_params - parse and fill cooling map data
* @ np : DT node containing a cooling - map node
* @ __tbp : data structure to be filled with cooling map info
* @ trips : array of thermal zone trip points
* @ ntrips : number of trip points inside trips .
*
* This function parses a cooling - map type of node represented by
* @ np parameter and fills the read data into @ __tbp data structure .
* It needs the already parsed array of trip points of the thermal zone
* in consideration .
*
* Return : 0 on success , proper error code otherwise
*/
static int thermal_of_populate_bind_params ( struct device_node * np ,
struct __thermal_bind_params * __tbp ,
2014-12-08 20:04:19 +03:00
struct thermal_trip * trips ,
2013-07-03 23:35:39 +04:00
int ntrips )
{
struct of_phandle_args cooling_spec ;
2018-08-08 10:08:14 +03:00
struct __thermal_cooling_bind_param * __tcbp ;
2013-07-03 23:35:39 +04:00
struct device_node * trip ;
2018-08-08 10:08:14 +03:00
int ret , i , count ;
2013-07-03 23:35:39 +04:00
u32 prop ;
/* Default weight. Usage is optional */
2015-02-18 19:04:21 +03:00
__tbp - > usage = THERMAL_WEIGHT_DEFAULT ;
2013-07-03 23:35:39 +04:00
ret = of_property_read_u32 ( np , " contribution " , & prop ) ;
if ( ret = = 0 )
__tbp - > usage = prop ;
trip = of_parse_phandle ( np , " trip " , 0 ) ;
if ( ! trip ) {
pr_err ( " missing trip property \n " ) ;
return - ENODEV ;
}
/* match using device_node */
for ( i = 0 ; i < ntrips ; i + + )
if ( trip = = trips [ i ] . np ) {
__tbp - > trip_id = i ;
break ;
}
if ( i = = ntrips ) {
ret = - ENODEV ;
goto end ;
}
2018-08-08 10:08:14 +03:00
count = of_count_phandle_with_args ( np , " cooling-device " ,
" #cooling-cells " ) ;
if ( ! count ) {
pr_err ( " Add a cooling_device property with at least one device \n " ) ;
2013-07-03 23:35:39 +04:00
goto end ;
}
2018-08-08 10:08:14 +03:00
__tcbp = kcalloc ( count , sizeof ( * __tcbp ) , GFP_KERNEL ) ;
if ( ! __tcbp )
goto end ;
for ( i = 0 ; i < count ; i + + ) {
ret = of_parse_phandle_with_args ( np , " cooling-device " ,
" #cooling-cells " , i , & cooling_spec ) ;
if ( ret < 0 ) {
pr_err ( " Invalid cooling-device entry \n " ) ;
goto free_tcbp ;
}
__tcbp [ i ] . cooling_device = cooling_spec . np ;
if ( cooling_spec . args_count > = 2 ) { /* at least min and max */
__tcbp [ i ] . min = cooling_spec . args [ 0 ] ;
__tcbp [ i ] . max = cooling_spec . args [ 1 ] ;
} else {
pr_err ( " wrong reference to cooling device, missing limits \n " ) ;
}
2013-07-03 23:35:39 +04:00
}
2018-08-08 10:08:14 +03:00
__tbp - > tcbp = __tcbp ;
__tbp - > count = count ;
goto end ;
free_tcbp :
for ( i = i - 1 ; i > = 0 ; i - - )
of_node_put ( __tcbp [ i ] . cooling_device ) ;
kfree ( __tcbp ) ;
2013-07-03 23:35:39 +04:00
end :
of_node_put ( trip ) ;
return ret ;
}
2019-11-20 18:45:10 +03:00
/*
2013-07-03 23:35:39 +04:00
* It maps ' enum thermal_trip_type ' found in include / linux / thermal . h
* into the device tree binding of ' trip ' , property type .
*/
static const char * const trip_types [ ] = {
[ THERMAL_TRIP_ACTIVE ] = " active " ,
[ THERMAL_TRIP_PASSIVE ] = " passive " ,
[ THERMAL_TRIP_HOT ] = " hot " ,
[ THERMAL_TRIP_CRITICAL ] = " critical " ,
} ;
/**
* thermal_of_get_trip_type - Get phy mode for given device_node
* @ np : Pointer to the given device_node
* @ type : Pointer to resulting trip type
*
* The function gets trip type string from property ' type ' ,
* and store its index in trip_types table in @ type ,
*
* Return : 0 on success , or errno in error case .
*/
static int thermal_of_get_trip_type ( struct device_node * np ,
enum thermal_trip_type * type )
{
const char * t ;
int err , i ;
err = of_property_read_string ( np , " type " , & t ) ;
if ( err < 0 )
return err ;
for ( i = 0 ; i < ARRAY_SIZE ( trip_types ) ; i + + )
if ( ! strcasecmp ( t , trip_types [ i ] ) ) {
* type = i ;
return 0 ;
}
return - ENODEV ;
}
/**
* thermal_of_populate_trip - parse and fill one trip point data
* @ np : DT node containing a trip point node
* @ trip : trip point data structure to be filled up
*
* This function parses a trip point type of node represented by
* @ np parameter and fills the read data into @ trip data structure .
*
* Return : 0 on success , proper error code otherwise
*/
static int thermal_of_populate_trip ( struct device_node * np ,
2014-12-08 20:04:19 +03:00
struct thermal_trip * trip )
2013-07-03 23:35:39 +04:00
{
int prop ;
int ret ;
ret = of_property_read_u32 ( np , " temperature " , & prop ) ;
if ( ret < 0 ) {
pr_err ( " missing temperature property \n " ) ;
return ret ;
}
trip - > temperature = prop ;
ret = of_property_read_u32 ( np , " hysteresis " , & prop ) ;
if ( ret < 0 ) {
pr_err ( " missing hysteresis property \n " ) ;
return ret ;
}
trip - > hysteresis = prop ;
ret = thermal_of_get_trip_type ( np , & trip - > type ) ;
if ( ret < 0 ) {
pr_err ( " wrong trip type property \n " ) ;
return ret ;
}
/* Required for cooling map matching */
trip - > np = np ;
2014-09-29 03:47:46 +04:00
of_node_get ( np ) ;
2013-07-03 23:35:39 +04:00
return 0 ;
}
/**
* thermal_of_build_thermal_zone - parse and fill one thermal zone data
* @ np : DT node containing a thermal zone node
*
* This function parses a thermal zone type of node represented by
* @ np parameter and fills the read data into a __thermal_zone data structure
* and return this pointer .
*
2015-05-12 05:48:09 +03:00
* TODO : Missing properties to parse : thermal - sensor - names
2013-07-03 23:35:39 +04:00
*
* Return : On success returns a valid struct __thermal_zone ,
* otherwise , it returns a corresponding ERR_PTR ( ) . Caller must
* check the return value with help of IS_ERR ( ) helper .
*/
2016-04-19 15:33:32 +03:00
static struct __thermal_zone
__init * thermal_of_build_thermal_zone ( struct device_node * np )
2013-07-03 23:35:39 +04:00
{
struct device_node * child = NULL , * gchild ;
struct __thermal_zone * tz ;
int ret , i ;
2015-05-12 05:48:09 +03:00
u32 prop , coef [ 2 ] ;
2013-07-03 23:35:39 +04:00
if ( ! np ) {
pr_err ( " no thermal zone np \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
tz = kzalloc ( sizeof ( * tz ) , GFP_KERNEL ) ;
if ( ! tz )
return ERR_PTR ( - ENOMEM ) ;
ret = of_property_read_u32 ( np , " polling-delay-passive " , & prop ) ;
if ( ret < 0 ) {
2019-01-21 12:42:22 +03:00
pr_err ( " %pOFn: missing polling-delay-passive property \n " , np ) ;
2013-07-03 23:35:39 +04:00
goto free_tz ;
}
tz - > passive_delay = prop ;
ret = of_property_read_u32 ( np , " polling-delay " , & prop ) ;
if ( ret < 0 ) {
2019-01-21 12:42:22 +03:00
pr_err ( " %pOFn: missing polling-delay property \n " , np ) ;
2013-07-03 23:35:39 +04:00
goto free_tz ;
}
tz - > polling_delay = prop ;
2015-05-12 05:48:09 +03:00
/*
* REVIST : for now , the thermal framework supports only
* one sensor per thermal zone . Thus , we are considering
* only the first two values as slope and offset .
*/
ret = of_property_read_u32_array ( np , " coefficients " , coef , 2 ) ;
if ( ret = = 0 ) {
tz - > slope = coef [ 0 ] ;
tz - > offset = coef [ 1 ] ;
} else {
tz - > slope = 1 ;
tz - > offset = 0 ;
}
2013-07-03 23:35:39 +04:00
/* trips */
child = of_get_child_by_name ( np , " trips " ) ;
/* No trips provided */
if ( ! child )
goto finish ;
tz - > ntrips = of_get_child_count ( child ) ;
if ( tz - > ntrips = = 0 ) /* must have at least one child */
goto finish ;
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:03:40 +03:00
tz - > trips = kcalloc ( tz - > ntrips , sizeof ( * tz - > trips ) , GFP_KERNEL ) ;
2013-07-03 23:35:39 +04:00
if ( ! tz - > trips ) {
ret = - ENOMEM ;
goto free_tz ;
}
i = 0 ;
for_each_child_of_node ( child , gchild ) {
ret = thermal_of_populate_trip ( gchild , & tz - > trips [ i + + ] ) ;
if ( ret )
goto free_trips ;
}
of_node_put ( child ) ;
/* cooling-maps */
child = of_get_child_by_name ( np , " cooling-maps " ) ;
/* cooling-maps not provided */
if ( ! child )
goto finish ;
tz - > num_tbps = of_get_child_count ( child ) ;
if ( tz - > num_tbps = = 0 )
goto finish ;
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:03:40 +03:00
tz - > tbps = kcalloc ( tz - > num_tbps , sizeof ( * tz - > tbps ) , GFP_KERNEL ) ;
2013-07-03 23:35:39 +04:00
if ( ! tz - > tbps ) {
ret = - ENOMEM ;
goto free_trips ;
}
i = 0 ;
2014-06-19 03:32:08 +04:00
for_each_child_of_node ( child , gchild ) {
2013-07-03 23:35:39 +04:00
ret = thermal_of_populate_bind_params ( gchild , & tz - > tbps [ i + + ] ,
tz - > trips , tz - > ntrips ) ;
if ( ret )
goto free_tbps ;
2014-06-19 03:32:08 +04:00
}
2013-07-03 23:35:39 +04:00
finish :
of_node_put ( child ) ;
tz - > mode = THERMAL_DEVICE_DISABLED ;
return tz ;
free_tbps :
2018-08-08 10:08:14 +03:00
for ( i = i - 1 ; i > = 0 ; i - - ) {
struct __thermal_bind_params * tbp = tz - > tbps + i ;
int j ;
for ( j = 0 ; j < tbp - > count ; j + + )
of_node_put ( tbp - > tcbp [ j ] . cooling_device ) ;
kfree ( tbp - > tcbp ) ;
}
2013-07-03 23:35:39 +04:00
kfree ( tz - > tbps ) ;
free_trips :
2014-09-29 03:47:46 +04:00
for ( i = 0 ; i < tz - > ntrips ; i + + )
of_node_put ( tz - > trips [ i ] . np ) ;
2013-07-03 23:35:39 +04:00
kfree ( tz - > trips ) ;
2014-09-29 03:47:46 +04:00
of_node_put ( gchild ) ;
2013-07-03 23:35:39 +04:00
free_tz :
kfree ( tz ) ;
of_node_put ( child ) ;
return ERR_PTR ( ret ) ;
}
2019-12-20 01:21:53 +03:00
static __init void of_thermal_free_zone ( struct __thermal_zone * tz )
2013-07-03 23:35:39 +04:00
{
2018-08-08 10:08:14 +03:00
struct __thermal_bind_params * tbp ;
int i , j ;
for ( i = 0 ; i < tz - > num_tbps ; i + + ) {
tbp = tz - > tbps + i ;
for ( j = 0 ; j < tbp - > count ; j + + )
of_node_put ( tbp - > tcbp [ j ] . cooling_device ) ;
kfree ( tbp - > tcbp ) ;
}
2014-09-29 03:47:46 +04:00
2013-07-03 23:35:39 +04:00
kfree ( tz - > tbps ) ;
2014-09-29 03:47:46 +04:00
for ( i = 0 ; i < tz - > ntrips ; i + + )
of_node_put ( tz - > trips [ i ] . np ) ;
2013-07-03 23:35:39 +04:00
kfree ( tz - > trips ) ;
kfree ( tz ) ;
}
2019-12-20 01:21:52 +03:00
/**
* of_thermal_destroy_zones - remove all zones parsed and allocated resources
*
* Finds all zones parsed and added to the thermal framework and remove them
* from the system , together with their resources .
*
*/
static __init void of_thermal_destroy_zones ( void )
{
struct device_node * np , * child ;
np = of_find_node_by_name ( NULL , " thermal-zones " ) ;
if ( ! np ) {
pr_debug ( " unable to find thermal zones \n " ) ;
return ;
}
for_each_available_child_of_node ( np , child ) {
struct thermal_zone_device * zone ;
zone = thermal_zone_get_zone_by_name ( child - > name ) ;
if ( IS_ERR ( zone ) )
continue ;
thermal_zone_device_unregister ( zone ) ;
kfree ( zone - > tzp ) ;
kfree ( zone - > ops ) ;
of_thermal_free_zone ( zone - > devdata ) ;
}
of_node_put ( np ) ;
}
2013-07-03 23:35:39 +04:00
/**
* of_parse_thermal_zones - parse device tree thermal data
*
* Initialization function that can be called by machine initialization
* code to parse thermal data and populate the thermal framework
* with hardware thermal zones info . This function only parses thermal zones .
* Cooling devices and sensor devices nodes are supposed to be parsed
* by their respective drivers .
*
* Return : 0 on success , proper error code otherwise
*
*/
int __init of_parse_thermal_zones ( void )
{
struct device_node * np , * child ;
struct __thermal_zone * tz ;
struct thermal_zone_device_ops * ops ;
np = of_find_node_by_name ( NULL , " thermal-zones " ) ;
if ( ! np ) {
pr_debug ( " unable to find thermal zones \n " ) ;
return 0 ; /* Run successfully on systems without thermal DT */
}
2016-02-08 16:28:34 +03:00
for_each_available_child_of_node ( np , child ) {
2013-07-03 23:35:39 +04:00
struct thermal_zone_device * zone ;
struct thermal_zone_params * tzp ;
2015-03-03 13:43:04 +03:00
int i , mask = 0 ;
2015-02-26 22:00:32 +03:00
u32 prop ;
2013-07-03 23:35:39 +04:00
tz = thermal_of_build_thermal_zone ( child ) ;
if ( IS_ERR ( tz ) ) {
2018-08-28 04:52:46 +03:00
pr_err ( " failed to build thermal zone %pOFn: %ld \n " ,
child ,
2013-07-03 23:35:39 +04:00
PTR_ERR ( tz ) ) ;
continue ;
}
ops = kmemdup ( & of_thermal_ops , sizeof ( * ops ) , GFP_KERNEL ) ;
if ( ! ops )
goto exit_free ;
tzp = kzalloc ( sizeof ( * tzp ) , GFP_KERNEL ) ;
if ( ! tzp ) {
kfree ( ops ) ;
goto exit_free ;
}
/* No hwmon because there might be hwmon drivers registering */
tzp - > no_hwmon = true ;
2015-02-26 22:00:32 +03:00
if ( ! of_property_read_u32 ( child , " sustainable-power " , & prop ) )
tzp - > sustainable_power = prop ;
2015-03-03 13:43:04 +03:00
for ( i = 0 ; i < tz - > ntrips ; i + + )
mask | = 1 < < i ;
2015-05-12 05:48:09 +03:00
/* these two are left for temperature drivers to use */
tzp - > slope = tz - > slope ;
tzp - > offset = tz - > offset ;
2013-07-03 23:35:39 +04:00
zone = thermal_zone_device_register ( child - > name , tz - > ntrips ,
2015-03-03 13:43:04 +03:00
mask , tz ,
2013-07-03 23:35:39 +04:00
ops , tzp ,
tz - > passive_delay ,
tz - > polling_delay ) ;
if ( IS_ERR ( zone ) ) {
2018-08-28 04:52:46 +03:00
pr_err ( " Failed to build %pOFn zone %ld \n " , child ,
2013-07-03 23:35:39 +04:00
PTR_ERR ( zone ) ) ;
kfree ( tzp ) ;
kfree ( ops ) ;
of_thermal_free_zone ( tz ) ;
/* attempting to build remaining zones still */
}
}
2014-09-29 03:47:46 +04:00
of_node_put ( np ) ;
2013-07-03 23:35:39 +04:00
return 0 ;
exit_free :
2014-09-29 03:47:46 +04:00
of_node_put ( child ) ;
of_node_put ( np ) ;
2013-07-03 23:35:39 +04:00
of_thermal_free_zone ( tz ) ;
/* no memory available, so free what we have built */
of_thermal_destroy_zones ( ) ;
return - ENOMEM ;
}