Loading drivers/thermal/step_wise.c +53 −16 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ * * Copyright (C) 2012 Intel Corp * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com> * Copyright (c) 2019, The Linux Foundation. All rights reserved. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Loading Loading @@ -41,6 +42,12 @@ static unsigned long get_target_state(struct thermal_instance *instance, unsigned long cur_state; unsigned long next_target; /* * If the throttle condition is not reached and there is no * previous mitigaiton request, then there is nothing to compute. */ if (!throttle && instance->target == THERMAL_NO_TARGET) return THERMAL_NO_TARGET; /* * We keep this instance the way it is by default. * Otherwise, we use the current state of the Loading Loading @@ -77,7 +84,9 @@ static unsigned long get_target_state(struct thermal_instance *instance, next_target = instance->upper; break; case THERMAL_TREND_DROPPING: if (cur_state <= instance->lower) { case THERMAL_TREND_STABLE: if (cur_state <= instance->lower || instance->target <= instance->lower) { if (!throttle) next_target = THERMAL_NO_TARGET; } else { Loading Loading @@ -115,7 +124,7 @@ static void update_passive_instance(struct thermal_zone_device *tz, static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) { int trip_temp; int trip_temp, hyst_temp; enum thermal_trip_type trip_type; enum thermal_trend trend; struct thermal_instance *instance; Loading @@ -123,20 +132,21 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) int old_target; if (trip == THERMAL_TRIPS_NONE) { trip_temp = tz->forced_passive; hyst_temp = trip_temp = tz->forced_passive; trip_type = THERMAL_TRIPS_NONE; } else { tz->ops->get_trip_temp(tz, trip, &trip_temp); if (tz->ops->get_trip_hyst) { tz->ops->get_trip_hyst(tz, trip, &hyst_temp); hyst_temp = trip_temp - hyst_temp; } else { hyst_temp = trip_temp; } tz->ops->get_trip_type(tz, trip, &trip_type); } trend = get_tz_trend(tz, trip); if (tz->temperature >= trip_temp) { throttle = true; trace_thermal_zone_trip(tz, trip, trip_type); } dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n", trip, trip_type, trip_temp, trend, throttle); Loading @@ -147,6 +157,20 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) continue; old_target = instance->target; /* * Step wise has to lower the mitigation only if the * temperature goes below the hysteresis temperature. * Atleast, it has to hold on to mitigation device lower * limit if the temperature is above the hysteresis * temperature. */ if (tz->temperature >= trip_temp || (tz->temperature > hyst_temp && old_target != THERMAL_NO_TARGET)) throttle = true; else throttle = false; instance->target = get_target_state(instance, trend, throttle); dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n", old_target, (int)instance->target); Loading @@ -154,14 +178,27 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) if (instance->initialized && old_target == instance->target) continue; if (!instance->initialized) { if (instance->target != THERMAL_NO_TARGET) { trace_thermal_zone_trip(tz, trip, trip_type, true); update_passive_instance(tz, trip_type, 1); } } else { /* Activate a passive thermal instance */ if (old_target == THERMAL_NO_TARGET && instance->target != THERMAL_NO_TARGET) instance->target != THERMAL_NO_TARGET) { trace_thermal_zone_trip(tz, trip, trip_type, true); update_passive_instance(tz, trip_type, 1); /* Deactivate a passive thermal instance */ else if (old_target != THERMAL_NO_TARGET && instance->target == THERMAL_NO_TARGET) } else if (old_target != THERMAL_NO_TARGET && instance->target == THERMAL_NO_TARGET) { trace_thermal_zone_trip(tz, trip, trip_type, false); update_passive_instance(tz, trip_type, -1); } } instance->initialized = true; mutex_lock(&instance->cdev->lock); Loading drivers/thermal/thermal_core.c +139 −39 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Loading Loading @@ -33,6 +34,8 @@ MODULE_AUTHOR("Zhang Rui"); MODULE_DESCRIPTION("Generic thermal management sysfs support"); MODULE_LICENSE("GPL v2"); #define THERMAL_MAX_ACTIVE 16 static DEFINE_IDA(thermal_tz_ida); static DEFINE_IDA(thermal_cdev_ida); Loading @@ -49,6 +52,8 @@ static bool power_off_triggered; static struct thermal_governor *def_governor; static struct workqueue_struct *thermal_passive_wq; /* * Governor section: set of functions to handle thermal governors * Loading Loading @@ -292,19 +297,18 @@ static int __init thermal_register_governors(void) * - Hot trips will produce a notification to userspace; * - Critical trip point will cause a system shutdown. */ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, static void thermal_zone_device_set_polling(struct workqueue_struct *queue, struct thermal_zone_device *tz, int delay) { if (delay > 1000) mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, mod_delayed_work(queue, &tz->poll_queue, round_jiffies(msecs_to_jiffies(delay))); else if (delay) mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, mod_delayed_work(queue, &tz->poll_queue, msecs_to_jiffies(delay)); else cancel_delayed_work_sync(&tz->poll_queue); cancel_delayed_work(&tz->poll_queue); } static void monitor_thermal_zone(struct thermal_zone_device *tz) Loading @@ -312,11 +316,14 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz) mutex_lock(&tz->lock); if (tz->passive) thermal_zone_device_set_polling(tz, tz->passive_delay); thermal_zone_device_set_polling(thermal_passive_wq, tz, tz->passive_delay); else if (tz->polling_delay) thermal_zone_device_set_polling(tz, tz->polling_delay); thermal_zone_device_set_polling( system_freezable_power_efficient_wq, tz, tz->polling_delay); else thermal_zone_device_set_polling(tz, 0); thermal_zone_device_set_polling(NULL, tz, 0); mutex_unlock(&tz->lock); } Loading Loading @@ -386,7 +393,7 @@ static void handle_critical_trips(struct thermal_zone_device *tz, if (trip_temp <= 0 || tz->temperature < trip_temp) return; trace_thermal_zone_trip(tz, trip, trip_type); trace_thermal_zone_trip(tz, trip, trip_type, true); if (tz->ops->notify) tz->ops->notify(tz, trip, trip_type); Loading Loading @@ -428,21 +435,11 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) * So, start monitoring again. */ monitor_thermal_zone(tz); trace_thermal_handle_trip(tz, trip); } static void update_temperature(struct thermal_zone_device *tz) static void store_temperature(struct thermal_zone_device *tz, int temp) { int temp, ret; ret = thermal_zone_get_temp(tz, &temp); if (ret) { if (ret != -EAGAIN) dev_warn(&tz->device, "failed to read out thermal zone (%d)\n", ret); return; } mutex_lock(&tz->lock); tz->last_temperature = tz->temperature; tz->temperature = temp; Loading @@ -457,6 +454,21 @@ static void update_temperature(struct thermal_zone_device *tz) tz->last_temperature, tz->temperature); } static void update_temperature(struct thermal_zone_device *tz) { int temp, ret; ret = thermal_zone_get_temp(tz, &temp); if (ret) { if (ret != -EAGAIN) dev_warn(&tz->device, "failed to read out thermal zone (%d)\n", ret); return; } store_temperature(tz, temp); } static void thermal_zone_device_init(struct thermal_zone_device *tz) { struct thermal_instance *pos; Loading @@ -471,17 +483,36 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz) thermal_zone_device_init(tz); } void thermal_zone_device_update_temp(struct thermal_zone_device *tz, enum thermal_notify_event event, int temp) { int count; if (atomic_read(&in_suspend) && tz->polling_delay) return; trace_thermal_device_update(tz, event); store_temperature(tz, temp); thermal_zone_set_trips(tz); tz->notify_event = event; for (count = 0; count < tz->trips; count++) handle_thermal_trip(tz, count); } EXPORT_SYMBOL(thermal_zone_device_update_temp); void thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event) { int count; if (atomic_read(&in_suspend)) if (atomic_read(&in_suspend) && tz->polling_delay) return; if (!tz->ops->get_temp) return; trace_thermal_device_update(tz, event); update_temperature(tz); thermal_zone_set_trips(tz); Loading Loading @@ -710,9 +741,26 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, if (ret) return ret; /* lower default 0, upper default max_state */ lower = lower == THERMAL_NO_LIMIT ? 0 : lower; upper = upper == THERMAL_NO_LIMIT ? max_state : upper; /* * If upper or lower has a MACRO to define the mitigation state, * based on the MACRO determine the default state to use or the * offset from the max_state. */ if (upper >= (THERMAL_MAX_LIMIT - max_state)) { /* upper default max_state */ if (upper == THERMAL_NO_LIMIT) upper = max_state; else upper = max_state - (THERMAL_MAX_LIMIT - upper); } if (lower >= (THERMAL_MAX_LIMIT - max_state)) { /* lower default 0 */ if (lower == THERMAL_NO_LIMIT) lower = 0; else lower = max_state - (THERMAL_MAX_LIMIT - lower); } if (lower > upper || upper > max_state) return -EINVAL; Loading Loading @@ -839,6 +887,7 @@ static void thermal_release(struct device *dev) { struct thermal_zone_device *tz; struct thermal_cooling_device *cdev; struct thermal_instance *instance; if (!strncmp(dev_name(dev), "thermal_zone", sizeof("thermal_zone") - 1)) { Loading @@ -848,6 +897,12 @@ static void thermal_release(struct device *dev) } else if (!strncmp(dev_name(dev), "cooling_device", sizeof("cooling_device") - 1)) { cdev = to_cooling_device(dev); if (list_is_singular(&cdev->thermal_instances)) { instance = list_first_entry(&cdev->thermal_instances, typeof(*instance), cdev_node); list_del(&instance->cdev_node); kfree(instance); } kfree(cdev); } } Loading Loading @@ -953,6 +1008,7 @@ __thermal_cooling_device_register(struct device_node *np, struct thermal_cooling_device *cdev; struct thermal_zone_device *pos = NULL; int result; struct thermal_instance *instance; if (type && strlen(type) >= THERMAL_NAME_LENGTH) return ERR_PTR(-EINVAL); Loading @@ -965,9 +1021,16 @@ __thermal_cooling_device_register(struct device_node *np, if (!cdev) return ERR_PTR(-ENOMEM); instance = kzalloc(sizeof(*instance), GFP_KERNEL); if (!instance) { kfree(cdev); return ERR_PTR(-ENOMEM); } result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL); if (result < 0) { kfree(cdev); kfree(instance); return ERR_PTR(result); } Loading @@ -975,6 +1038,8 @@ __thermal_cooling_device_register(struct device_node *np, strlcpy(cdev->type, type ? : "", sizeof(cdev->type)); mutex_init(&cdev->lock); INIT_LIST_HEAD(&cdev->thermal_instances); instance->target = THERMAL_NO_TARGET; list_add_tail(&instance->cdev_node, &cdev->thermal_instances); cdev->np = np; cdev->ops = ops; cdev->updated = false; Loading Loading @@ -1345,7 +1410,7 @@ thermal_zone_device_register(const char *type, int trips, int mask, /* Bind cooling devices for this zone */ bind_tz(tz); INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check); INIT_DEFERRABLE_WORK(&(tz->poll_queue), thermal_zone_device_check); thermal_zone_device_reset(tz); /* Update the new thermal zone and mark it as already updated. */ Loading Loading @@ -1414,7 +1479,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) mutex_unlock(&thermal_list_lock); thermal_zone_device_set_polling(tz, 0); cancel_delayed_work_sync(&tz->poll_queue); thermal_set_governor(tz, NULL); Loading Loading @@ -1576,7 +1641,8 @@ static int thermal_pm_notify(struct notifier_block *nb, if (tz->ops->get_mode) tz->ops->get_mode(tz, &tz_mode); if (tz_mode == THERMAL_DEVICE_DISABLED) if (tz_mode == THERMAL_DEVICE_DISABLED || tz->polling_delay == 0) continue; thermal_zone_device_init(tz); Loading @@ -1599,21 +1665,26 @@ static int __init thermal_init(void) int result; mutex_init(&poweroff_lock); thermal_passive_wq = alloc_workqueue("thermal_passive_wq", WQ_HIGHPRI | WQ_UNBOUND | WQ_FREEZABLE, THERMAL_MAX_ACTIVE); if (!thermal_passive_wq) { result = -ENOMEM; goto error; } result = thermal_register_governors(); if (result) goto error; goto destroy_wq; result = class_register(&thermal_class); if (result) goto unregister_governors; result = genetlink_init(); if (result) goto unregister_class; result = of_parse_thermal_zones(); if (result) goto exit_netlink; goto unregister_class; result = register_pm_notifier(&thermal_pm_nb); if (result) Loading @@ -1622,12 +1693,12 @@ static int __init thermal_init(void) return 0; exit_netlink: genetlink_exit(); unregister_class: class_unregister(&thermal_class); unregister_governors: thermal_unregister_governors(); destroy_wq: destroy_workqueue(thermal_passive_wq); error: ida_destroy(&thermal_tz_ida); ida_destroy(&thermal_cdev_ida); Loading @@ -1636,4 +1707,33 @@ static int __init thermal_init(void) mutex_destroy(&poweroff_lock); return result; } fs_initcall(thermal_init); static void thermal_exit(void) { unregister_pm_notifier(&thermal_pm_nb); of_thermal_destroy_zones(); destroy_workqueue(thermal_passive_wq); genetlink_exit(); class_unregister(&thermal_class); thermal_unregister_governors(); ida_destroy(&thermal_tz_ida); ida_destroy(&thermal_cdev_ida); mutex_destroy(&thermal_list_lock); mutex_destroy(&thermal_governor_lock); } static int __init thermal_netlink_init(void) { int ret = 0; ret = genetlink_init(); if (!ret) goto exit_netlink; thermal_exit(); exit_netlink: return ret; } subsys_initcall(thermal_init); fs_initcall(thermal_netlink_init); drivers/thermal/thermal_core.h +20 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ * * Copyright (C) 2012 Intel Corp * Author: Durgadoss R <durgadoss.r@intel.com> * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #ifndef __THERMAL_CORE_H__ Loading Loading @@ -97,6 +98,12 @@ int of_thermal_get_ntrips(struct thermal_zone_device *); bool of_thermal_is_trip_valid(struct thermal_zone_device *, int); const struct thermal_trip * of_thermal_get_trip_points(struct thermal_zone_device *); int of_thermal_aggregate_trip(struct thermal_zone_device *tz, enum thermal_trip_type type, int *low, int *high); void of_thermal_handle_trip(struct thermal_zone_device *tz); void of_thermal_handle_trip_temp(struct thermal_zone_device *tz, int trip_temp); #else static inline int of_parse_thermal_zones(void) { return 0; } static inline void of_thermal_destroy_zones(void) { } Loading @@ -114,6 +121,19 @@ of_thermal_get_trip_points(struct thermal_zone_device *tz) { return NULL; } static inline int of_thermal_aggregate_trip(struct thermal_zone_device *tz, enum thermal_trip_type type, int *low, int *high) { return -ENODEV; } static inline void of_thermal_handle_trip(struct thermal_zone_device *tz) { } static inline void of_thermal_handle_trip_temp(struct thermal_zone_device *tz, int trip_temp) { } #endif #endif /* __THERMAL_CORE_H__ */ drivers/thermal/thermal_helpers.c +10 −7 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Loading Loading @@ -106,7 +107,7 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) if (!ret && *temp < crit_temp) *temp = tz->emul_temperature; } trace_thermal_query_temp(tz, *temp); mutex_unlock(&tz->lock); exit: return ret; Loading Loading @@ -140,10 +141,6 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz) high = trip_temp; } /* No need to change trip points */ if (tz->prev_low_trip == low && tz->prev_high_trip == high) goto exit; tz->prev_low_trip = low; tz->prev_high_trip = high; Loading @@ -157,6 +154,7 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz) ret = tz->ops->set_trips(tz, low, high); if (ret) dev_err(&tz->device, "Failed to set trips: %d\n", ret); trace_thermal_set_trip(tz); exit: mutex_unlock(&tz->lock); Loading @@ -177,6 +175,11 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev) /* Make sure cdev enters the deepest cooling state */ list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) { if (list_is_first(&instance->cdev_node, &cdev->thermal_instances)) dev_dbg(&cdev->device, "userspace->target=%lu\n", instance->target); else dev_dbg(&cdev->device, "zone%d->target=%lu\n", instance->tz->id, instance->target); if (instance->target == THERMAL_NO_TARGET) Loading drivers/thermal/thermal_sysfs.c +71 −8 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Loading Loading @@ -63,6 +64,28 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf) : "disabled"); } static int thermal_zone_device_clear(struct thermal_zone_device *tz) { struct thermal_instance *pos; int ret = 0; ret = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED); mutex_lock(&tz->lock); tz->temperature = THERMAL_TEMP_INVALID; tz->passive = 0; list_for_each_entry(pos, &tz->thermal_instances, tz_node) { pos->initialized = false; pos->target = THERMAL_NO_TARGET; mutex_lock(&pos->cdev->lock); pos->cdev->updated = false; /* cdev needs update */ mutex_unlock(&pos->cdev->lock); thermal_cdev_update(pos->cdev); } mutex_unlock(&tz->lock); return ret; } static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) Loading @@ -76,7 +99,7 @@ mode_store(struct device *dev, struct device_attribute *attr, if (!strncmp(buf, "enabled", sizeof("enabled") - 1)) result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED); else if (!strncmp(buf, "disabled", sizeof("disabled") - 1)) result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED); result = thermal_zone_device_clear(tz); else result = -EINVAL; Loading Loading @@ -348,6 +371,24 @@ sustainable_power_store(struct device *dev, struct device_attribute *devattr, return count; } static ssize_t polling_delay_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_zone_device *tz = to_thermal_zone(dev); return scnprintf(buf, PAGE_SIZE, "%d\n", tz->polling_delay); } static ssize_t passive_delay_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_zone_device *tz = to_thermal_zone(dev); return scnprintf(buf, PAGE_SIZE, "%d\n", tz->passive_delay); } #define create_s32_tzp_attr(name) \ static ssize_t \ name##_show(struct device *dev, struct device_attribute *devattr, \ Loading Loading @@ -399,6 +440,8 @@ static DEVICE_ATTR_RO(temp); static DEVICE_ATTR_RW(policy); static DEVICE_ATTR_RO(available_policies); static DEVICE_ATTR_RW(sustainable_power); static DEVICE_ATTR_RO(passive_delay); static DEVICE_ATTR_RO(polling_delay); /* These thermal zone device attributes are created based on conditions */ static DEVICE_ATTR_RW(mode); Loading @@ -414,6 +457,8 @@ static struct attribute *thermal_zone_dev_attrs[] = { &dev_attr_policy.attr, &dev_attr_available_policies.attr, &dev_attr_sustainable_power.attr, &dev_attr_passive_delay.attr, &dev_attr_polling_delay.attr, &dev_attr_k_po.attr, &dev_attr_k_pu.attr, &dev_attr_k_i.attr, Loading Loading @@ -704,7 +749,7 @@ cur_state_store(struct device *dev, struct device_attribute *attr, { struct thermal_cooling_device *cdev = to_cooling_device(dev); unsigned long state; int result; struct thermal_instance *instance = NULL; if (sscanf(buf, "%ld\n", &state) != 1) return -EINVAL; Loading @@ -713,13 +758,15 @@ cur_state_store(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&cdev->lock); instance = list_first_entry(&cdev->thermal_instances, typeof(*instance), cdev_node); instance->target = state; result = cdev->ops->set_cur_state(cdev, state); if (!result) thermal_cooling_device_stats_update(cdev, state); cdev->updated = false; mutex_unlock(&cdev->lock); return result ? result : count; thermal_cdev_update(cdev); return count; } static struct device_attribute Loading Loading @@ -770,6 +817,9 @@ void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev, { struct cooling_dev_stats *stats = cdev->stats; if (!stats) return; spin_lock(&stats->lock); if (stats->state == new_state) Loading @@ -791,6 +841,9 @@ static ssize_t total_trans_show(struct device *dev, struct cooling_dev_stats *stats = cdev->stats; int ret; if (!stats) return -ENODEV; spin_lock(&stats->lock); ret = sprintf(buf, "%u\n", stats->total_trans); spin_unlock(&stats->lock); Loading @@ -807,6 +860,9 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, ssize_t len = 0; int i; if (!stats) return -ENODEV; spin_lock(&stats->lock); update_time_in_state(stats); Loading @@ -825,8 +881,12 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, { struct thermal_cooling_device *cdev = to_cooling_device(dev); struct cooling_dev_stats *stats = cdev->stats; int i, states = stats->max_states; int i, states; if (!stats) return -ENODEV; states = stats->max_states; spin_lock(&stats->lock); stats->total_trans = 0; Loading @@ -850,6 +910,9 @@ static ssize_t trans_table_show(struct device *dev, ssize_t len = 0; int i, j; if (!stats) return -ENODEV; len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += snprintf(buf + len, PAGE_SIZE - len, " : "); for (i = 0; i < stats->max_states; i++) { Loading Loading
drivers/thermal/step_wise.c +53 −16 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ * * Copyright (C) 2012 Intel Corp * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com> * Copyright (c) 2019, The Linux Foundation. All rights reserved. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Loading Loading @@ -41,6 +42,12 @@ static unsigned long get_target_state(struct thermal_instance *instance, unsigned long cur_state; unsigned long next_target; /* * If the throttle condition is not reached and there is no * previous mitigaiton request, then there is nothing to compute. */ if (!throttle && instance->target == THERMAL_NO_TARGET) return THERMAL_NO_TARGET; /* * We keep this instance the way it is by default. * Otherwise, we use the current state of the Loading Loading @@ -77,7 +84,9 @@ static unsigned long get_target_state(struct thermal_instance *instance, next_target = instance->upper; break; case THERMAL_TREND_DROPPING: if (cur_state <= instance->lower) { case THERMAL_TREND_STABLE: if (cur_state <= instance->lower || instance->target <= instance->lower) { if (!throttle) next_target = THERMAL_NO_TARGET; } else { Loading Loading @@ -115,7 +124,7 @@ static void update_passive_instance(struct thermal_zone_device *tz, static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) { int trip_temp; int trip_temp, hyst_temp; enum thermal_trip_type trip_type; enum thermal_trend trend; struct thermal_instance *instance; Loading @@ -123,20 +132,21 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) int old_target; if (trip == THERMAL_TRIPS_NONE) { trip_temp = tz->forced_passive; hyst_temp = trip_temp = tz->forced_passive; trip_type = THERMAL_TRIPS_NONE; } else { tz->ops->get_trip_temp(tz, trip, &trip_temp); if (tz->ops->get_trip_hyst) { tz->ops->get_trip_hyst(tz, trip, &hyst_temp); hyst_temp = trip_temp - hyst_temp; } else { hyst_temp = trip_temp; } tz->ops->get_trip_type(tz, trip, &trip_type); } trend = get_tz_trend(tz, trip); if (tz->temperature >= trip_temp) { throttle = true; trace_thermal_zone_trip(tz, trip, trip_type); } dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n", trip, trip_type, trip_temp, trend, throttle); Loading @@ -147,6 +157,20 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) continue; old_target = instance->target; /* * Step wise has to lower the mitigation only if the * temperature goes below the hysteresis temperature. * Atleast, it has to hold on to mitigation device lower * limit if the temperature is above the hysteresis * temperature. */ if (tz->temperature >= trip_temp || (tz->temperature > hyst_temp && old_target != THERMAL_NO_TARGET)) throttle = true; else throttle = false; instance->target = get_target_state(instance, trend, throttle); dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n", old_target, (int)instance->target); Loading @@ -154,14 +178,27 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) if (instance->initialized && old_target == instance->target) continue; if (!instance->initialized) { if (instance->target != THERMAL_NO_TARGET) { trace_thermal_zone_trip(tz, trip, trip_type, true); update_passive_instance(tz, trip_type, 1); } } else { /* Activate a passive thermal instance */ if (old_target == THERMAL_NO_TARGET && instance->target != THERMAL_NO_TARGET) instance->target != THERMAL_NO_TARGET) { trace_thermal_zone_trip(tz, trip, trip_type, true); update_passive_instance(tz, trip_type, 1); /* Deactivate a passive thermal instance */ else if (old_target != THERMAL_NO_TARGET && instance->target == THERMAL_NO_TARGET) } else if (old_target != THERMAL_NO_TARGET && instance->target == THERMAL_NO_TARGET) { trace_thermal_zone_trip(tz, trip, trip_type, false); update_passive_instance(tz, trip_type, -1); } } instance->initialized = true; mutex_lock(&instance->cdev->lock); Loading
drivers/thermal/thermal_core.c +139 −39 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Loading Loading @@ -33,6 +34,8 @@ MODULE_AUTHOR("Zhang Rui"); MODULE_DESCRIPTION("Generic thermal management sysfs support"); MODULE_LICENSE("GPL v2"); #define THERMAL_MAX_ACTIVE 16 static DEFINE_IDA(thermal_tz_ida); static DEFINE_IDA(thermal_cdev_ida); Loading @@ -49,6 +52,8 @@ static bool power_off_triggered; static struct thermal_governor *def_governor; static struct workqueue_struct *thermal_passive_wq; /* * Governor section: set of functions to handle thermal governors * Loading Loading @@ -292,19 +297,18 @@ static int __init thermal_register_governors(void) * - Hot trips will produce a notification to userspace; * - Critical trip point will cause a system shutdown. */ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, static void thermal_zone_device_set_polling(struct workqueue_struct *queue, struct thermal_zone_device *tz, int delay) { if (delay > 1000) mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, mod_delayed_work(queue, &tz->poll_queue, round_jiffies(msecs_to_jiffies(delay))); else if (delay) mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, mod_delayed_work(queue, &tz->poll_queue, msecs_to_jiffies(delay)); else cancel_delayed_work_sync(&tz->poll_queue); cancel_delayed_work(&tz->poll_queue); } static void monitor_thermal_zone(struct thermal_zone_device *tz) Loading @@ -312,11 +316,14 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz) mutex_lock(&tz->lock); if (tz->passive) thermal_zone_device_set_polling(tz, tz->passive_delay); thermal_zone_device_set_polling(thermal_passive_wq, tz, tz->passive_delay); else if (tz->polling_delay) thermal_zone_device_set_polling(tz, tz->polling_delay); thermal_zone_device_set_polling( system_freezable_power_efficient_wq, tz, tz->polling_delay); else thermal_zone_device_set_polling(tz, 0); thermal_zone_device_set_polling(NULL, tz, 0); mutex_unlock(&tz->lock); } Loading Loading @@ -386,7 +393,7 @@ static void handle_critical_trips(struct thermal_zone_device *tz, if (trip_temp <= 0 || tz->temperature < trip_temp) return; trace_thermal_zone_trip(tz, trip, trip_type); trace_thermal_zone_trip(tz, trip, trip_type, true); if (tz->ops->notify) tz->ops->notify(tz, trip, trip_type); Loading Loading @@ -428,21 +435,11 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) * So, start monitoring again. */ monitor_thermal_zone(tz); trace_thermal_handle_trip(tz, trip); } static void update_temperature(struct thermal_zone_device *tz) static void store_temperature(struct thermal_zone_device *tz, int temp) { int temp, ret; ret = thermal_zone_get_temp(tz, &temp); if (ret) { if (ret != -EAGAIN) dev_warn(&tz->device, "failed to read out thermal zone (%d)\n", ret); return; } mutex_lock(&tz->lock); tz->last_temperature = tz->temperature; tz->temperature = temp; Loading @@ -457,6 +454,21 @@ static void update_temperature(struct thermal_zone_device *tz) tz->last_temperature, tz->temperature); } static void update_temperature(struct thermal_zone_device *tz) { int temp, ret; ret = thermal_zone_get_temp(tz, &temp); if (ret) { if (ret != -EAGAIN) dev_warn(&tz->device, "failed to read out thermal zone (%d)\n", ret); return; } store_temperature(tz, temp); } static void thermal_zone_device_init(struct thermal_zone_device *tz) { struct thermal_instance *pos; Loading @@ -471,17 +483,36 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz) thermal_zone_device_init(tz); } void thermal_zone_device_update_temp(struct thermal_zone_device *tz, enum thermal_notify_event event, int temp) { int count; if (atomic_read(&in_suspend) && tz->polling_delay) return; trace_thermal_device_update(tz, event); store_temperature(tz, temp); thermal_zone_set_trips(tz); tz->notify_event = event; for (count = 0; count < tz->trips; count++) handle_thermal_trip(tz, count); } EXPORT_SYMBOL(thermal_zone_device_update_temp); void thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event) { int count; if (atomic_read(&in_suspend)) if (atomic_read(&in_suspend) && tz->polling_delay) return; if (!tz->ops->get_temp) return; trace_thermal_device_update(tz, event); update_temperature(tz); thermal_zone_set_trips(tz); Loading Loading @@ -710,9 +741,26 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, if (ret) return ret; /* lower default 0, upper default max_state */ lower = lower == THERMAL_NO_LIMIT ? 0 : lower; upper = upper == THERMAL_NO_LIMIT ? max_state : upper; /* * If upper or lower has a MACRO to define the mitigation state, * based on the MACRO determine the default state to use or the * offset from the max_state. */ if (upper >= (THERMAL_MAX_LIMIT - max_state)) { /* upper default max_state */ if (upper == THERMAL_NO_LIMIT) upper = max_state; else upper = max_state - (THERMAL_MAX_LIMIT - upper); } if (lower >= (THERMAL_MAX_LIMIT - max_state)) { /* lower default 0 */ if (lower == THERMAL_NO_LIMIT) lower = 0; else lower = max_state - (THERMAL_MAX_LIMIT - lower); } if (lower > upper || upper > max_state) return -EINVAL; Loading Loading @@ -839,6 +887,7 @@ static void thermal_release(struct device *dev) { struct thermal_zone_device *tz; struct thermal_cooling_device *cdev; struct thermal_instance *instance; if (!strncmp(dev_name(dev), "thermal_zone", sizeof("thermal_zone") - 1)) { Loading @@ -848,6 +897,12 @@ static void thermal_release(struct device *dev) } else if (!strncmp(dev_name(dev), "cooling_device", sizeof("cooling_device") - 1)) { cdev = to_cooling_device(dev); if (list_is_singular(&cdev->thermal_instances)) { instance = list_first_entry(&cdev->thermal_instances, typeof(*instance), cdev_node); list_del(&instance->cdev_node); kfree(instance); } kfree(cdev); } } Loading Loading @@ -953,6 +1008,7 @@ __thermal_cooling_device_register(struct device_node *np, struct thermal_cooling_device *cdev; struct thermal_zone_device *pos = NULL; int result; struct thermal_instance *instance; if (type && strlen(type) >= THERMAL_NAME_LENGTH) return ERR_PTR(-EINVAL); Loading @@ -965,9 +1021,16 @@ __thermal_cooling_device_register(struct device_node *np, if (!cdev) return ERR_PTR(-ENOMEM); instance = kzalloc(sizeof(*instance), GFP_KERNEL); if (!instance) { kfree(cdev); return ERR_PTR(-ENOMEM); } result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL); if (result < 0) { kfree(cdev); kfree(instance); return ERR_PTR(result); } Loading @@ -975,6 +1038,8 @@ __thermal_cooling_device_register(struct device_node *np, strlcpy(cdev->type, type ? : "", sizeof(cdev->type)); mutex_init(&cdev->lock); INIT_LIST_HEAD(&cdev->thermal_instances); instance->target = THERMAL_NO_TARGET; list_add_tail(&instance->cdev_node, &cdev->thermal_instances); cdev->np = np; cdev->ops = ops; cdev->updated = false; Loading Loading @@ -1345,7 +1410,7 @@ thermal_zone_device_register(const char *type, int trips, int mask, /* Bind cooling devices for this zone */ bind_tz(tz); INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check); INIT_DEFERRABLE_WORK(&(tz->poll_queue), thermal_zone_device_check); thermal_zone_device_reset(tz); /* Update the new thermal zone and mark it as already updated. */ Loading Loading @@ -1414,7 +1479,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) mutex_unlock(&thermal_list_lock); thermal_zone_device_set_polling(tz, 0); cancel_delayed_work_sync(&tz->poll_queue); thermal_set_governor(tz, NULL); Loading Loading @@ -1576,7 +1641,8 @@ static int thermal_pm_notify(struct notifier_block *nb, if (tz->ops->get_mode) tz->ops->get_mode(tz, &tz_mode); if (tz_mode == THERMAL_DEVICE_DISABLED) if (tz_mode == THERMAL_DEVICE_DISABLED || tz->polling_delay == 0) continue; thermal_zone_device_init(tz); Loading @@ -1599,21 +1665,26 @@ static int __init thermal_init(void) int result; mutex_init(&poweroff_lock); thermal_passive_wq = alloc_workqueue("thermal_passive_wq", WQ_HIGHPRI | WQ_UNBOUND | WQ_FREEZABLE, THERMAL_MAX_ACTIVE); if (!thermal_passive_wq) { result = -ENOMEM; goto error; } result = thermal_register_governors(); if (result) goto error; goto destroy_wq; result = class_register(&thermal_class); if (result) goto unregister_governors; result = genetlink_init(); if (result) goto unregister_class; result = of_parse_thermal_zones(); if (result) goto exit_netlink; goto unregister_class; result = register_pm_notifier(&thermal_pm_nb); if (result) Loading @@ -1622,12 +1693,12 @@ static int __init thermal_init(void) return 0; exit_netlink: genetlink_exit(); unregister_class: class_unregister(&thermal_class); unregister_governors: thermal_unregister_governors(); destroy_wq: destroy_workqueue(thermal_passive_wq); error: ida_destroy(&thermal_tz_ida); ida_destroy(&thermal_cdev_ida); Loading @@ -1636,4 +1707,33 @@ static int __init thermal_init(void) mutex_destroy(&poweroff_lock); return result; } fs_initcall(thermal_init); static void thermal_exit(void) { unregister_pm_notifier(&thermal_pm_nb); of_thermal_destroy_zones(); destroy_workqueue(thermal_passive_wq); genetlink_exit(); class_unregister(&thermal_class); thermal_unregister_governors(); ida_destroy(&thermal_tz_ida); ida_destroy(&thermal_cdev_ida); mutex_destroy(&thermal_list_lock); mutex_destroy(&thermal_governor_lock); } static int __init thermal_netlink_init(void) { int ret = 0; ret = genetlink_init(); if (!ret) goto exit_netlink; thermal_exit(); exit_netlink: return ret; } subsys_initcall(thermal_init); fs_initcall(thermal_netlink_init);
drivers/thermal/thermal_core.h +20 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ * * Copyright (C) 2012 Intel Corp * Author: Durgadoss R <durgadoss.r@intel.com> * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #ifndef __THERMAL_CORE_H__ Loading Loading @@ -97,6 +98,12 @@ int of_thermal_get_ntrips(struct thermal_zone_device *); bool of_thermal_is_trip_valid(struct thermal_zone_device *, int); const struct thermal_trip * of_thermal_get_trip_points(struct thermal_zone_device *); int of_thermal_aggregate_trip(struct thermal_zone_device *tz, enum thermal_trip_type type, int *low, int *high); void of_thermal_handle_trip(struct thermal_zone_device *tz); void of_thermal_handle_trip_temp(struct thermal_zone_device *tz, int trip_temp); #else static inline int of_parse_thermal_zones(void) { return 0; } static inline void of_thermal_destroy_zones(void) { } Loading @@ -114,6 +121,19 @@ of_thermal_get_trip_points(struct thermal_zone_device *tz) { return NULL; } static inline int of_thermal_aggregate_trip(struct thermal_zone_device *tz, enum thermal_trip_type type, int *low, int *high) { return -ENODEV; } static inline void of_thermal_handle_trip(struct thermal_zone_device *tz) { } static inline void of_thermal_handle_trip_temp(struct thermal_zone_device *tz, int trip_temp) { } #endif #endif /* __THERMAL_CORE_H__ */
drivers/thermal/thermal_helpers.c +10 −7 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Loading Loading @@ -106,7 +107,7 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) if (!ret && *temp < crit_temp) *temp = tz->emul_temperature; } trace_thermal_query_temp(tz, *temp); mutex_unlock(&tz->lock); exit: return ret; Loading Loading @@ -140,10 +141,6 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz) high = trip_temp; } /* No need to change trip points */ if (tz->prev_low_trip == low && tz->prev_high_trip == high) goto exit; tz->prev_low_trip = low; tz->prev_high_trip = high; Loading @@ -157,6 +154,7 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz) ret = tz->ops->set_trips(tz, low, high); if (ret) dev_err(&tz->device, "Failed to set trips: %d\n", ret); trace_thermal_set_trip(tz); exit: mutex_unlock(&tz->lock); Loading @@ -177,6 +175,11 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev) /* Make sure cdev enters the deepest cooling state */ list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) { if (list_is_first(&instance->cdev_node, &cdev->thermal_instances)) dev_dbg(&cdev->device, "userspace->target=%lu\n", instance->target); else dev_dbg(&cdev->device, "zone%d->target=%lu\n", instance->tz->id, instance->target); if (instance->target == THERMAL_NO_TARGET) Loading
drivers/thermal/thermal_sysfs.c +71 −8 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Loading Loading @@ -63,6 +64,28 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf) : "disabled"); } static int thermal_zone_device_clear(struct thermal_zone_device *tz) { struct thermal_instance *pos; int ret = 0; ret = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED); mutex_lock(&tz->lock); tz->temperature = THERMAL_TEMP_INVALID; tz->passive = 0; list_for_each_entry(pos, &tz->thermal_instances, tz_node) { pos->initialized = false; pos->target = THERMAL_NO_TARGET; mutex_lock(&pos->cdev->lock); pos->cdev->updated = false; /* cdev needs update */ mutex_unlock(&pos->cdev->lock); thermal_cdev_update(pos->cdev); } mutex_unlock(&tz->lock); return ret; } static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) Loading @@ -76,7 +99,7 @@ mode_store(struct device *dev, struct device_attribute *attr, if (!strncmp(buf, "enabled", sizeof("enabled") - 1)) result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED); else if (!strncmp(buf, "disabled", sizeof("disabled") - 1)) result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED); result = thermal_zone_device_clear(tz); else result = -EINVAL; Loading Loading @@ -348,6 +371,24 @@ sustainable_power_store(struct device *dev, struct device_attribute *devattr, return count; } static ssize_t polling_delay_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_zone_device *tz = to_thermal_zone(dev); return scnprintf(buf, PAGE_SIZE, "%d\n", tz->polling_delay); } static ssize_t passive_delay_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_zone_device *tz = to_thermal_zone(dev); return scnprintf(buf, PAGE_SIZE, "%d\n", tz->passive_delay); } #define create_s32_tzp_attr(name) \ static ssize_t \ name##_show(struct device *dev, struct device_attribute *devattr, \ Loading Loading @@ -399,6 +440,8 @@ static DEVICE_ATTR_RO(temp); static DEVICE_ATTR_RW(policy); static DEVICE_ATTR_RO(available_policies); static DEVICE_ATTR_RW(sustainable_power); static DEVICE_ATTR_RO(passive_delay); static DEVICE_ATTR_RO(polling_delay); /* These thermal zone device attributes are created based on conditions */ static DEVICE_ATTR_RW(mode); Loading @@ -414,6 +457,8 @@ static struct attribute *thermal_zone_dev_attrs[] = { &dev_attr_policy.attr, &dev_attr_available_policies.attr, &dev_attr_sustainable_power.attr, &dev_attr_passive_delay.attr, &dev_attr_polling_delay.attr, &dev_attr_k_po.attr, &dev_attr_k_pu.attr, &dev_attr_k_i.attr, Loading Loading @@ -704,7 +749,7 @@ cur_state_store(struct device *dev, struct device_attribute *attr, { struct thermal_cooling_device *cdev = to_cooling_device(dev); unsigned long state; int result; struct thermal_instance *instance = NULL; if (sscanf(buf, "%ld\n", &state) != 1) return -EINVAL; Loading @@ -713,13 +758,15 @@ cur_state_store(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&cdev->lock); instance = list_first_entry(&cdev->thermal_instances, typeof(*instance), cdev_node); instance->target = state; result = cdev->ops->set_cur_state(cdev, state); if (!result) thermal_cooling_device_stats_update(cdev, state); cdev->updated = false; mutex_unlock(&cdev->lock); return result ? result : count; thermal_cdev_update(cdev); return count; } static struct device_attribute Loading Loading @@ -770,6 +817,9 @@ void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev, { struct cooling_dev_stats *stats = cdev->stats; if (!stats) return; spin_lock(&stats->lock); if (stats->state == new_state) Loading @@ -791,6 +841,9 @@ static ssize_t total_trans_show(struct device *dev, struct cooling_dev_stats *stats = cdev->stats; int ret; if (!stats) return -ENODEV; spin_lock(&stats->lock); ret = sprintf(buf, "%u\n", stats->total_trans); spin_unlock(&stats->lock); Loading @@ -807,6 +860,9 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, ssize_t len = 0; int i; if (!stats) return -ENODEV; spin_lock(&stats->lock); update_time_in_state(stats); Loading @@ -825,8 +881,12 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, { struct thermal_cooling_device *cdev = to_cooling_device(dev); struct cooling_dev_stats *stats = cdev->stats; int i, states = stats->max_states; int i, states; if (!stats) return -ENODEV; states = stats->max_states; spin_lock(&stats->lock); stats->total_trans = 0; Loading @@ -850,6 +910,9 @@ static ssize_t trans_table_show(struct device *dev, ssize_t len = 0; int i, j; if (!stats) return -ENODEV; len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += snprintf(buf + len, PAGE_SIZE - len, " : "); for (i = 0; i < stats->max_states; i++) { Loading