aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal/thermal_sys.c
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@srcf.ucam.org>2008-12-03 12:55:32 -0500
committerLen Brown <len.brown@intel.com>2009-02-20 18:41:56 -0500
commitb1569e99c795bf83b4ddf41c4f1c42761ab7f75e (patch)
treead45358dd111e0c4ce71d58565068c47c0171c3d /drivers/thermal/thermal_sys.c
parent6503e5df08008b9a47022b5e9ebba658c8fa69af (diff)
ACPI: move thermal trip handling to generic thermal layer
The ACPI code currently carries its own thermal trip handling, meaning that any other thermal implementation will need to reimplement it. Move the code to the generic thermal layer. Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/thermal/thermal_sys.c')
-rw-r--r--drivers/thermal/thermal_sys.c188
1 files changed, 186 insertions, 2 deletions
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index bd139adc6d32..6378741882f3 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -30,6 +30,7 @@
30#include <linux/idr.h> 30#include <linux/idr.h>
31#include <linux/thermal.h> 31#include <linux/thermal.h>
32#include <linux/spinlock.h> 32#include <linux/spinlock.h>
33#include <linux/reboot.h>
33 34
34MODULE_AUTHOR("Zhang Rui"); 35MODULE_AUTHOR("Zhang Rui");
35MODULE_DESCRIPTION("Generic thermal management sysfs support"); 36MODULE_DESCRIPTION("Generic thermal management sysfs support");
@@ -517,6 +518,97 @@ thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
517} 518}
518#endif 519#endif
519 520
521static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
522 int delay)
523{
524 cancel_delayed_work(&(tz->poll_queue));
525
526 if (!delay)
527 return;
528
529 if (delay > 1000)
530 schedule_delayed_work(&(tz->poll_queue),
531 round_jiffies(msecs_to_jiffies(delay)));
532 else
533 schedule_delayed_work(&(tz->poll_queue),
534 msecs_to_jiffies(delay));
535}
536
537static void thermal_zone_device_passive(struct thermal_zone_device *tz,
538 int temp, int trip_temp, int trip)
539{
540 int trend = 0;
541 struct thermal_cooling_device_instance *instance;
542 struct thermal_cooling_device *cdev;
543 long state, max_state;
544
545 /*
546 * Above Trip?
547 * -----------
548 * Calculate the thermal trend (using the passive cooling equation)
549 * and modify the performance limit for all passive cooling devices
550 * accordingly. Note that we assume symmetry.
551 */
552 if (temp >= trip_temp) {
553 tz->passive = true;
554
555 trend = (tz->tc1 * (temp - tz->last_temperature)) +
556 (tz->tc2 * (temp - trip_temp));
557
558 /* Heating up? */
559 if (trend > 0) {
560 list_for_each_entry(instance, &tz->cooling_devices,
561 node) {
562 if (instance->trip != trip)
563 continue;
564 cdev = instance->cdev;
565 cdev->ops->get_cur_state(cdev, &state);
566 cdev->ops->get_max_state(cdev, &max_state);
567 if (state++ < max_state)
568 cdev->ops->set_cur_state(cdev, state);
569 }
570 } else if (trend < 0) { /* Cooling off? */
571 list_for_each_entry(instance, &tz->cooling_devices,
572 node) {
573 if (instance->trip != trip)
574 continue;
575 cdev = instance->cdev;
576 cdev->ops->get_cur_state(cdev, &state);
577 cdev->ops->get_max_state(cdev, &max_state);
578 if (state > 0)
579 cdev->ops->set_cur_state(cdev, --state);
580 }
581 }
582 return;
583 }
584
585 /*
586 * Below Trip?
587 * -----------
588 * Implement passive cooling hysteresis to slowly increase performance
589 * and avoid thrashing around the passive trip point. Note that we
590 * assume symmetry.
591 */
592 list_for_each_entry(instance, &tz->cooling_devices, node) {
593 if (instance->trip != trip)
594 continue;
595 cdev = instance->cdev;
596 cdev->ops->get_cur_state(cdev, &state);
597 cdev->ops->get_max_state(cdev, &max_state);
598 if (state > 0)
599 cdev->ops->set_cur_state(cdev, --state);
600 if (state == 0)
601 tz->passive = false;
602 }
603}
604
605static void thermal_zone_device_check(struct work_struct *work)
606{
607 struct thermal_zone_device *tz = container_of(work, struct
608 thermal_zone_device,
609 poll_queue.work);
610 thermal_zone_device_update(tz);
611}
520 612
521/** 613/**
522 * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone 614 * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
@@ -787,20 +879,101 @@ void thermal_cooling_device_unregister(struct
787EXPORT_SYMBOL(thermal_cooling_device_unregister); 879EXPORT_SYMBOL(thermal_cooling_device_unregister);
788 880
789/** 881/**
882 * thermal_zone_device_update - force an update of a thermal zone's state
883 * @ttz: the thermal zone to update
884 */
885
886void thermal_zone_device_update(struct thermal_zone_device *tz)
887{
888 int count, ret = 0;
889 long temp, trip_temp;
890 enum thermal_trip_type trip_type;
891 struct thermal_cooling_device_instance *instance;
892 struct thermal_cooling_device *cdev;
893
894 mutex_lock(&tz->lock);
895
896 tz->ops->get_temp(tz, &temp);
897
898 for (count = 0; count < tz->trips; count++) {
899 tz->ops->get_trip_type(tz, count, &trip_type);
900 tz->ops->get_trip_temp(tz, count, &trip_temp);
901
902 switch (trip_type) {
903 case THERMAL_TRIP_CRITICAL:
904 if (temp > trip_temp) {
905 if (tz->ops->notify)
906 ret = tz->ops->notify(tz, count,
907 trip_type);
908 if (!ret) {
909 printk(KERN_EMERG
910 "Critical temperature reached (%ld C), shutting down.\n",
911 temp/1000);
912 orderly_poweroff(true);
913 }
914 }
915 break;
916 case THERMAL_TRIP_HOT:
917 if (temp > trip_temp)
918 if (tz->ops->notify)
919 tz->ops->notify(tz, count, trip_type);
920 break;
921 case THERMAL_TRIP_ACTIVE:
922 list_for_each_entry(instance, &tz->cooling_devices,
923 node) {
924 if (instance->trip != count)
925 continue;
926
927 cdev = instance->cdev;
928
929 if (temp > trip_temp)
930 cdev->ops->set_cur_state(cdev, 1);
931 else
932 cdev->ops->set_cur_state(cdev, 0);
933 }
934 break;
935 case THERMAL_TRIP_PASSIVE:
936 if (temp > trip_temp || tz->passive)
937 thermal_zone_device_passive(tz, temp,
938 trip_temp, count);
939 break;
940 }
941 }
942 tz->last_temperature = temp;
943 if (tz->passive)
944 thermal_zone_device_set_polling(tz, tz->passive_delay);
945 else if (tz->polling_delay)
946 thermal_zone_device_set_polling(tz, tz->polling_delay);
947 mutex_unlock(&tz->lock);
948}
949EXPORT_SYMBOL(thermal_zone_device_update);
950
951/**
790 * thermal_zone_device_register - register a new thermal zone device 952 * thermal_zone_device_register - register a new thermal zone device
791 * @type: the thermal zone device type 953 * @type: the thermal zone device type
792 * @trips: the number of trip points the thermal zone support 954 * @trips: the number of trip points the thermal zone support
793 * @devdata: private device data 955 * @devdata: private device data
794 * @ops: standard thermal zone device callbacks 956 * @ops: standard thermal zone device callbacks
957 * @tc1: thermal coefficient 1 for passive calculations
958 * @tc2: thermal coefficient 2 for passive calculations
959 * @passive_delay: number of milliseconds to wait between polls when
960 * performing passive cooling
961 * @polling_delay: number of milliseconds to wait between polls when checking
962 * whether trip points have been crossed (0 for interrupt
963 * driven systems)
795 * 964 *
796 * thermal_zone_device_unregister() must be called when the device is no 965 * thermal_zone_device_unregister() must be called when the device is no
797 * longer needed. 966 * longer needed. The passive cooling formula uses tc1 and tc2 as described in
967 * section 11.1.5.1 of the ACPI specification 3.0.
798 */ 968 */
799struct thermal_zone_device *thermal_zone_device_register(char *type, 969struct thermal_zone_device *thermal_zone_device_register(char *type,
800 int trips, 970 int trips,
801 void *devdata, struct 971 void *devdata, struct
802 thermal_zone_device_ops 972 thermal_zone_device_ops
803 *ops) 973 *ops, int tc1, int
974 tc2,
975 int passive_delay,
976 int polling_delay)
804{ 977{
805 struct thermal_zone_device *tz; 978 struct thermal_zone_device *tz;
806 struct thermal_cooling_device *pos; 979 struct thermal_cooling_device *pos;
@@ -834,6 +1007,11 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
834 tz->device.class = &thermal_class; 1007 tz->device.class = &thermal_class;
835 tz->devdata = devdata; 1008 tz->devdata = devdata;
836 tz->trips = trips; 1009 tz->trips = trips;
1010 tz->tc1 = tc1;
1011 tz->tc2 = tc2;
1012 tz->passive_delay = passive_delay;
1013 tz->polling_delay = polling_delay;
1014
837 dev_set_name(&tz->device, "thermal_zone%d", tz->id); 1015 dev_set_name(&tz->device, "thermal_zone%d", tz->id);
838 result = device_register(&tz->device); 1016 result = device_register(&tz->device);
839 if (result) { 1017 if (result) {
@@ -879,6 +1057,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
879 } 1057 }
880 mutex_unlock(&thermal_list_lock); 1058 mutex_unlock(&thermal_list_lock);
881 1059
1060 INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
1061
1062 thermal_zone_device_update(tz);
1063
882 if (!result) 1064 if (!result)
883 return tz; 1065 return tz;
884 1066
@@ -918,6 +1100,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
918 tz->ops->unbind(tz, cdev); 1100 tz->ops->unbind(tz, cdev);
919 mutex_unlock(&thermal_list_lock); 1101 mutex_unlock(&thermal_list_lock);
920 1102
1103 thermal_zone_device_set_polling(tz, 0);
1104
921 if (tz->type[0]) 1105 if (tz->type[0])
922 device_remove_file(&tz->device, &dev_attr_type); 1106 device_remove_file(&tz->device, &dev_attr_type);
923 device_remove_file(&tz->device, &dev_attr_temp); 1107 device_remove_file(&tz->device, &dev_attr_temp);