|
13 | 13 |
|
14 | 14 | #include "thermal_core.h"
|
15 | 15 |
|
| 16 | +static void bang_bang_set_instance_target(struct thermal_instance *instance, |
| 17 | + unsigned int target) |
| 18 | +{ |
| 19 | + if (instance->target != 0 && instance->target != 1 && |
| 20 | + instance->target != THERMAL_NO_TARGET) |
| 21 | + pr_debug("Unexpected state %ld of thermal instance %s in bang-bang\n", |
| 22 | + instance->target, instance->name); |
| 23 | + |
| 24 | + /* |
| 25 | + * Enable the fan when the trip is crossed on the way up and disable it |
| 26 | + * when the trip is crossed on the way down. |
| 27 | + */ |
| 28 | + instance->target = target; |
| 29 | + instance->initialized = true; |
| 30 | + |
| 31 | + dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target); |
| 32 | + |
| 33 | + mutex_lock(&instance->cdev->lock); |
| 34 | + __thermal_cdev_update(instance->cdev); |
| 35 | + mutex_unlock(&instance->cdev->lock); |
| 36 | +} |
| 37 | + |
16 | 38 | /**
|
17 | 39 | * bang_bang_control - controls devices associated with the given zone
|
18 | 40 | * @tz: thermal_zone_device
|
@@ -54,33 +76,60 @@ static void bang_bang_control(struct thermal_zone_device *tz,
|
54 | 76 | tz->temperature, trip->hysteresis);
|
55 | 77 |
|
56 | 78 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
|
57 |
| - if (instance->trip != trip) |
58 |
| - continue; |
| 79 | + if (instance->trip == trip) |
| 80 | + bang_bang_set_instance_target(instance, crossed_up); |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +static void bang_bang_manage(struct thermal_zone_device *tz) |
| 85 | +{ |
| 86 | + const struct thermal_trip_desc *td; |
| 87 | + struct thermal_instance *instance; |
59 | 88 |
|
60 |
| - if (instance->target != 0 && instance->target != 1 && |
61 |
| - instance->target != THERMAL_NO_TARGET) |
62 |
| - pr_debug("Unexpected state %ld of thermal instance %s in bang-bang\n", |
63 |
| - instance->target, instance->name); |
| 89 | + /* If the code below has run already, nothing needs to be done. */ |
| 90 | + if (tz->governor_data) |
| 91 | + return; |
64 | 92 |
|
65 |
| - /* |
66 |
| - * Enable the fan when the trip is crossed on the way up and |
67 |
| - * disable it when the trip is crossed on the way down. |
68 |
| - */ |
69 |
| - instance->target = crossed_up; |
| 93 | + for_each_trip_desc(tz, td) { |
| 94 | + const struct thermal_trip *trip = &td->trip; |
70 | 95 |
|
71 |
| - dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target); |
| 96 | + if (tz->temperature >= td->threshold || |
| 97 | + trip->temperature == THERMAL_TEMP_INVALID || |
| 98 | + trip->type == THERMAL_TRIP_CRITICAL || |
| 99 | + trip->type == THERMAL_TRIP_HOT) |
| 100 | + continue; |
72 | 101 |
|
73 |
| - mutex_lock(&instance->cdev->lock); |
74 |
| - instance->cdev->updated = false; /* cdev needs update */ |
75 |
| - mutex_unlock(&instance->cdev->lock); |
| 102 | + /* |
| 103 | + * If the initial cooling device state is "on", but the zone |
| 104 | + * temperature is not above the trip point, the core will not |
| 105 | + * call bang_bang_control() until the zone temperature reaches |
| 106 | + * the trip point temperature which may be never. In those |
| 107 | + * cases, set the initial state of the cooling device to 0. |
| 108 | + */ |
| 109 | + list_for_each_entry(instance, &tz->thermal_instances, tz_node) { |
| 110 | + if (!instance->initialized && instance->trip == trip) |
| 111 | + bang_bang_set_instance_target(instance, 0); |
| 112 | + } |
76 | 113 | }
|
77 | 114 |
|
78 |
| - list_for_each_entry(instance, &tz->thermal_instances, tz_node) |
79 |
| - thermal_cdev_update(instance->cdev); |
| 115 | + tz->governor_data = (void *)true; |
| 116 | +} |
| 117 | + |
| 118 | +static void bang_bang_update_tz(struct thermal_zone_device *tz, |
| 119 | + enum thermal_notify_event reason) |
| 120 | +{ |
| 121 | + /* |
| 122 | + * Let bang_bang_manage() know that it needs to walk trips after binding |
| 123 | + * a new cdev and after system resume. |
| 124 | + */ |
| 125 | + if (reason == THERMAL_TZ_BIND_CDEV || reason == THERMAL_TZ_RESUME) |
| 126 | + tz->governor_data = NULL; |
80 | 127 | }
|
81 | 128 |
|
82 | 129 | static struct thermal_governor thermal_gov_bang_bang = {
|
83 | 130 | .name = "bang_bang",
|
84 | 131 | .trip_crossed = bang_bang_control,
|
| 132 | + .manage = bang_bang_manage, |
| 133 | + .update_tz = bang_bang_update_tz, |
85 | 134 | };
|
86 | 135 | THERMAL_GOVERNOR_DECLARE(thermal_gov_bang_bang);
|
0 commit comments