2020#include <linux/err.h>
2121#include <linux/slab.h>
2222#include <linux/string.h>
23+ #include <linux/jiffies.h>
2324
2425#include "thermal_core.h"
2526
@@ -721,6 +722,7 @@ thermal_cooling_device_cur_state_store(struct device *dev,
721722 result = cdev -> ops -> set_cur_state (cdev , state );
722723 if (result )
723724 return result ;
725+ thermal_cooling_device_stats_update (cdev , state );
724726 return count ;
725727}
726728
@@ -745,14 +747,237 @@ static const struct attribute_group cooling_device_attr_group = {
745747
746748static const struct attribute_group * cooling_device_attr_groups [] = {
747749 & cooling_device_attr_group ,
750+ NULL , /* Space allocated for cooling_device_stats_attr_group */
748751 NULL ,
749752};
750753
754+ #ifdef CONFIG_THERMAL_STATISTICS
755+ struct cooling_dev_stats {
756+ spinlock_t lock ;
757+ unsigned int total_trans ;
758+ unsigned long state ;
759+ unsigned long max_states ;
760+ ktime_t last_time ;
761+ ktime_t * time_in_state ;
762+ unsigned int * trans_table ;
763+ };
764+
765+ static void update_time_in_state (struct cooling_dev_stats * stats )
766+ {
767+ ktime_t now = ktime_get (), delta ;
768+
769+ delta = ktime_sub (now , stats -> last_time );
770+ stats -> time_in_state [stats -> state ] =
771+ ktime_add (stats -> time_in_state [stats -> state ], delta );
772+ stats -> last_time = now ;
773+ }
774+
775+ void thermal_cooling_device_stats_update (struct thermal_cooling_device * cdev ,
776+ unsigned long new_state )
777+ {
778+ struct cooling_dev_stats * stats = cdev -> stats ;
779+
780+ spin_lock (& stats -> lock );
781+
782+ if (stats -> state == new_state )
783+ goto unlock ;
784+
785+ update_time_in_state (stats );
786+ stats -> trans_table [stats -> state * stats -> max_states + new_state ]++ ;
787+ stats -> state = new_state ;
788+ stats -> total_trans ++ ;
789+
790+ unlock :
791+ spin_unlock (& stats -> lock );
792+ }
793+
794+ static ssize_t
795+ thermal_cooling_device_total_trans_show (struct device * dev ,
796+ struct device_attribute * attr ,
797+ char * buf )
798+ {
799+ struct thermal_cooling_device * cdev = to_cooling_device (dev );
800+ struct cooling_dev_stats * stats = cdev -> stats ;
801+ int ret ;
802+
803+ spin_lock (& stats -> lock );
804+ ret = sprintf (buf , "%u\n" , stats -> total_trans );
805+ spin_unlock (& stats -> lock );
806+
807+ return ret ;
808+ }
809+
810+ static ssize_t
811+ thermal_cooling_device_time_in_state_show (struct device * dev ,
812+ struct device_attribute * attr ,
813+ char * buf )
814+ {
815+ struct thermal_cooling_device * cdev = to_cooling_device (dev );
816+ struct cooling_dev_stats * stats = cdev -> stats ;
817+ ssize_t len = 0 ;
818+ int i ;
819+
820+ spin_lock (& stats -> lock );
821+ update_time_in_state (stats );
822+
823+ for (i = 0 ; i < stats -> max_states ; i ++ ) {
824+ len += sprintf (buf + len , "state%u\t%llu\n" , i ,
825+ ktime_to_ms (stats -> time_in_state [i ]));
826+ }
827+ spin_unlock (& stats -> lock );
828+
829+ return len ;
830+ }
831+
832+ static ssize_t
833+ thermal_cooling_device_reset_store (struct device * dev ,
834+ struct device_attribute * attr ,
835+ const char * buf , size_t count )
836+ {
837+ struct thermal_cooling_device * cdev = to_cooling_device (dev );
838+ struct cooling_dev_stats * stats = cdev -> stats ;
839+ int i , states = stats -> max_states ;
840+
841+ spin_lock (& stats -> lock );
842+
843+ stats -> total_trans = 0 ;
844+ stats -> last_time = ktime_get ();
845+ memset (stats -> trans_table , 0 ,
846+ states * states * sizeof (* stats -> trans_table ));
847+
848+ for (i = 0 ; i < stats -> max_states ; i ++ )
849+ stats -> time_in_state [i ] = ktime_set (0 , 0 );
850+
851+ spin_unlock (& stats -> lock );
852+
853+ return count ;
854+ }
855+
856+ static ssize_t
857+ thermal_cooling_device_trans_table_show (struct device * dev ,
858+ struct device_attribute * attr ,
859+ char * buf )
860+ {
861+ struct thermal_cooling_device * cdev = to_cooling_device (dev );
862+ struct cooling_dev_stats * stats = cdev -> stats ;
863+ ssize_t len = 0 ;
864+ int i , j ;
865+
866+ len += snprintf (buf + len , PAGE_SIZE - len , " From : To\n" );
867+ len += snprintf (buf + len , PAGE_SIZE - len , " : " );
868+ for (i = 0 ; i < stats -> max_states ; i ++ ) {
869+ if (len >= PAGE_SIZE )
870+ break ;
871+ len += snprintf (buf + len , PAGE_SIZE - len , "state%2u " , i );
872+ }
873+ if (len >= PAGE_SIZE )
874+ return PAGE_SIZE ;
875+
876+ len += snprintf (buf + len , PAGE_SIZE - len , "\n" );
877+
878+ for (i = 0 ; i < stats -> max_states ; i ++ ) {
879+ if (len >= PAGE_SIZE )
880+ break ;
881+
882+ len += snprintf (buf + len , PAGE_SIZE - len , "state%2u:" , i );
883+
884+ for (j = 0 ; j < stats -> max_states ; j ++ ) {
885+ if (len >= PAGE_SIZE )
886+ break ;
887+ len += snprintf (buf + len , PAGE_SIZE - len , "%8u " ,
888+ stats -> trans_table [i * stats -> max_states + j ]);
889+ }
890+ if (len >= PAGE_SIZE )
891+ break ;
892+ len += snprintf (buf + len , PAGE_SIZE - len , "\n" );
893+ }
894+
895+ if (len >= PAGE_SIZE ) {
896+ pr_warn_once ("Thermal transition table exceeds PAGE_SIZE. Disabling\n" );
897+ return - EFBIG ;
898+ }
899+ return len ;
900+ }
901+
902+ static DEVICE_ATTR (total_trans , 0444 , thermal_cooling_device_total_trans_show ,
903+ NULL );
904+ static DEVICE_ATTR (time_in_state_ms , 0444 ,
905+ thermal_cooling_device_time_in_state_show , NULL );
906+ static DEVICE_ATTR (reset , 0200 , NULL , thermal_cooling_device_reset_store );
907+ static DEVICE_ATTR (trans_table , 0444 ,
908+ thermal_cooling_device_trans_table_show , NULL );
909+
910+ static struct attribute * cooling_device_stats_attrs [] = {
911+ & dev_attr_total_trans .attr ,
912+ & dev_attr_time_in_state_ms .attr ,
913+ & dev_attr_reset .attr ,
914+ & dev_attr_trans_table .attr ,
915+ NULL
916+ };
917+
918+ static const struct attribute_group cooling_device_stats_attr_group = {
919+ .attrs = cooling_device_stats_attrs ,
920+ .name = "stats"
921+ };
922+
923+ static void cooling_device_stats_setup (struct thermal_cooling_device * cdev )
924+ {
925+ struct cooling_dev_stats * stats ;
926+ unsigned long states ;
927+ int var ;
928+
929+ if (cdev -> ops -> get_max_state (cdev , & states ))
930+ return ;
931+
932+ states ++ ; /* Total number of states is highest state + 1 */
933+
934+ var = sizeof (* stats );
935+ var += sizeof (* stats -> time_in_state ) * states ;
936+ var += sizeof (* stats -> trans_table ) * states * states ;
937+
938+ stats = kzalloc (var , GFP_KERNEL );
939+ if (!stats )
940+ return ;
941+
942+ stats -> time_in_state = (ktime_t * )(stats + 1 );
943+ stats -> trans_table = (unsigned int * )(stats -> time_in_state + states );
944+ cdev -> stats = stats ;
945+ stats -> last_time = ktime_get ();
946+ stats -> max_states = states ;
947+
948+ spin_lock_init (& stats -> lock );
949+
950+ /* Fill the empty slot left in cooling_device_attr_groups */
951+ var = ARRAY_SIZE (cooling_device_attr_groups ) - 2 ;
952+ cooling_device_attr_groups [var ] = & cooling_device_stats_attr_group ;
953+ }
954+
955+ static void cooling_device_stats_destroy (struct thermal_cooling_device * cdev )
956+ {
957+ kfree (cdev -> stats );
958+ cdev -> stats = NULL ;
959+ }
960+
961+ #else
962+
963+ static inline void
964+ cooling_device_stats_setup (struct thermal_cooling_device * cdev ) {}
965+ static inline void
966+ cooling_device_stats_destroy (struct thermal_cooling_device * cdev ) {}
967+
968+ #endif /* CONFIG_THERMAL_STATISTICS */
969+
751970void thermal_cooling_device_setup_sysfs (struct thermal_cooling_device * cdev )
752971{
972+ cooling_device_stats_setup (cdev );
753973 cdev -> device .groups = cooling_device_attr_groups ;
754974}
755975
976+ void thermal_cooling_device_destroy_sysfs (struct thermal_cooling_device * cdev )
977+ {
978+ cooling_device_stats_destroy (cdev );
979+ }
980+
756981/* these helper will be used only at the time of bindig */
757982ssize_t
758983thermal_cooling_device_trip_point_show (struct device * dev ,
0 commit comments