@@ -153,6 +153,8 @@ struct acpi_thermal {
struct acpi_thermal_trip trips[ACPI_THERMAL_TRIP_MAX];
struct acpi_handle_list devices;
struct thermal_zone_device *thermal_zone;
+ struct thermal_trip *_trips;
+ int num_trips;
int kelvin_offset; /* in millidegrees */
struct work_struct thermal_check_work;
struct mutex thermal_check_lock;
@@ -244,6 +246,198 @@ do { \
"Please report to linux-acpi@vger.kernel.org\n", str); \
} while (0)
+static void acpi_thermal_trips_override(struct thermal_trip *trip, int temperature)
+{
+ if (temperature > trip->temperature)
+ pr_info("Overriding temperature %d->%d m°C\n",
+ trip->temperature, temperature);
+
+ trip->temperature = temperature;
+}
+
+static struct thermal_trip *acpi_thermal_trips_alloc_critical(struct acpi_thermal *tz,
+ struct thermal_trip *trips,
+ int *num_trips)
+{
+ acpi_status status = AE_OK;
+ unsigned long long temp;
+
+ /*
+ * Module parameters disable the critical trip point
+ */
+ if (crt < 0)
+ goto out;
+
+ status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, &temp);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_debug(tz->device->handle, "No critical threshold\n");
+ goto out;
+ }
+
+ if (temp <= 2732) {
+ pr_info(FW_BUG "Invalid critical threshold (%llu)\n", temp);
+ goto out;
+ }
+
+ trips = krealloc(trips, sizeof(*trips) * (*num_trips + 1), GFP_KERNEL);
+ if (!trips)
+ goto out;
+
+ memset(&trips[*num_trips], 0, sizeof(*trips));
+
+ trips[*num_trips].temperature = deci_kelvin_to_millicelsius(temp);
+ trips[*num_trips].type = THERMAL_TRIP_CRITICAL;
+
+ if (crt > 0)
+ acpi_thermal_trips_override(&trips[*num_trips], crt * MILLI);
+
+ (*num_trips)++;
+out:
+ return trips;
+}
+
+static struct thermal_trip *acpi_thermal_trips_alloc_hot(struct acpi_thermal *tz,
+ struct thermal_trip *trips,
+ int *num_trips)
+{
+ acpi_status status;
+ unsigned long long temp;
+
+ status = acpi_evaluate_integer(tz->device->handle, "_HOT", NULL, &temp);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_debug(tz->device->handle, "No hot threshold\n");
+ goto out;
+ }
+
+ trips = krealloc(trips, sizeof(*trips) * (*num_trips + 1), GFP_KERNEL);
+ if (!trips)
+ goto out;
+
+ memset(&trips[*num_trips], 0, sizeof(*trips));
+
+ trips[*num_trips].temperature = deci_kelvin_to_millicelsius(temp);
+ trips[*num_trips].type = THERMAL_TRIP_HOT;
+
+ (*num_trips)++;
+out:
+ return trips;
+}
+
+static struct thermal_trip *acpi_thermal_trips_alloc_passive(struct acpi_thermal *tz,
+ struct thermal_trip *trips,
+ int *num_trips)
+{
+ struct acpi_handle_list devices;
+ acpi_status status;
+ unsigned long long temp;
+
+ /*
+ * Module parameters disable all passive trip points
+ */
+ if (psv < 0)
+ goto out;
+
+ status = acpi_evaluate_integer(tz->device->handle, "_PSV", NULL, &temp);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_debug(tz->device->handle, "No passive threshold\n");
+ goto out;
+ }
+
+ status = acpi_evaluate_reference(tz->device->handle, "_PSL", NULL, &devices);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_debug(tz->device->handle, "No passive device associated\n");
+ goto out;
+ }
+
+ trips = krealloc(trips, sizeof(*trips) * (*num_trips + 1), GFP_KERNEL);
+ if (!trips)
+ goto out;
+
+ memset(&trips[*num_trips], 0, sizeof(*trips));
+
+ trips[*num_trips].temperature = deci_kelvin_to_millicelsius(temp);
+ trips[*num_trips].type = THERMAL_TRIP_PASSIVE;
+
+ (*num_trips)++;
+out:
+ return trips;
+}
+
+static struct thermal_trip *acpi_thermal_trips_alloc_active(struct acpi_thermal *tz,
+ struct thermal_trip *trips,
+ int *num_trips)
+{
+ struct acpi_handle_list devices;
+ acpi_status status;
+ unsigned long long temp;
+ int i;
+
+ /*
+ * Module parameters disable all active trip points
+ */
+ if (act < 0)
+ return trips;
+
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+ char name[5];
+
+ sprintf(name, "_AC%d", i);
+
+ status = acpi_evaluate_integer(tz->device->handle, name, NULL, &temp);
+ if (ACPI_FAILURE(status))
+ break;
+
+ sprintf(name, "_AL%d", i);
+
+ status = acpi_evaluate_reference(tz->device->handle, name, NULL, &devices);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_info(tz->device->handle, "No _AL%d defined for _AC%d\n", i, i);
+ break;
+ }
+
+ trips = krealloc(trips, sizeof(*trips) * (*num_trips + 1), GFP_KERNEL);
+ if (!trips)
+ break;
+
+ memset(&trips[*num_trips], 0, sizeof(*trips));
+
+ trips[*num_trips].temperature = deci_kelvin_to_millicelsius(temp);
+ trips[*num_trips].type = THERMAL_TRIP_ACTIVE;
+
+ (*num_trips)++;
+ }
+
+ /*
+ * We found at least one trip point and we have an override option
+ */
+ if (i && act) {
+ /*
+ * Regarding the ACPI specification AC0 is the highest active
+ * temperature trip point. We will override this one.
+ */
+ acpi_thermal_trips_override(&trips[*num_trips], act * MILLI);
+ }
+
+ return trips;
+}
+
+static struct thermal_trip *acpi_thermal_trips_alloc(struct acpi_thermal *tz, int *num_trips)
+{
+ struct thermal_trip *trips = NULL;
+
+ *num_trips = 0;
+
+ trips = acpi_thermal_trips_alloc_critical(tz, trips, num_trips);
+
+ trips = acpi_thermal_trips_alloc_hot(tz, trips, num_trips);
+
+ trips = acpi_thermal_trips_alloc_passive(tz, trips, num_trips);
+
+ trips = acpi_thermal_trips_alloc_active(tz, trips, num_trips);
+
+ return trips;
+}
+
static int acpi_thermal_trips_update_critical(struct acpi_thermal *tz, int flag)
{
acpi_status status = AE_OK;
@@ -398,7 +592,7 @@ static int acpi_thermal_trips_update_active(struct acpi_thermal *tz, int flag)
int valid = 0;
int i;
- for (i = ACPI_THERMAL_TRIP_ACTIVE; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
valid = tz->trips[i].flags.valid;
@@ -820,35 +1014,20 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
{
- int trips = 0;
int result;
acpi_status status;
- int i;
-
- if (tz->trips[ACPI_THERMAL_TRIP_CRITICAL].flags.valid)
- trips++;
-
- if (tz->trips[ACPI_THERMAL_TRIP_HOT].flags.valid)
- trips++;
-
- if (tz->trips[ACPI_THERMAL_TRIP_PASSIVE].flags.valid)
- trips++;
-
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips[i].flags.valid;
- i++, trips++);
if (tz->trips[ACPI_THERMAL_TRIP_PASSIVE].flags.valid)
tz->thermal_zone =
- thermal_zone_device_register("acpitz", trips, 0, tz,
- &acpi_thermal_zone_ops, NULL,
- tz->trips[ACPI_THERMAL_TRIP_PASSIVE].tsp*100,
- tz->polling_frequency*100);
+ thermal_zone_device_register_with_trips("acpitz", tz->_trips, tz->num_trips, 0, tz,
+ &acpi_thermal_zone_ops, NULL,
+ tz->trips[ACPI_THERMAL_TRIP_PASSIVE].tsp*100,
+ tz->polling_frequency*100);
else
tz->thermal_zone =
- thermal_zone_device_register("acpitz", trips, 0, tz,
- &acpi_thermal_zone_ops, NULL,
- 0, tz->polling_frequency * 100);
-
+ thermal_zone_device_register_with_trips("acpitz", tz->_trips, tz->num_trips, 0, tz,
+ &acpi_thermal_zone_ops, NULL,
+ 0, tz->polling_frequency*100);
if (IS_ERR(tz->thermal_zone))
return -ENODEV;
@@ -1051,8 +1230,8 @@ static void acpi_thermal_check_fn(struct work_struct *work)
static int acpi_thermal_add(struct acpi_device *device)
{
- struct acpi_thermal *tz;
- int result;
+ struct acpi_thermal *tz = NULL;
+ int result = 0;
if (!device)
return -EINVAL;
@@ -1073,9 +1252,13 @@ static int acpi_thermal_add(struct acpi_device *device)
acpi_thermal_guess_offset(tz);
+ tz->_trips = acpi_thermal_trips_alloc(tz, &tz->num_trips);
+ if (!tz->_trips)
+ goto free_trips;
+
result = acpi_thermal_register_thermal_zone(tz);
if (result)
- goto free_memory;
+ goto free_trips;
refcount_set(&tz->thermal_check_count, 3);
mutex_init(&tz->thermal_check_lock);
@@ -1085,6 +1268,8 @@ static int acpi_thermal_add(struct acpi_device *device)
acpi_device_bid(device), tz->temperature);
goto end;
+free_trips:
+ kfree(tz->_trips);
free_memory:
kfree(tz);
end:
@@ -1101,6 +1286,7 @@ static void acpi_thermal_remove(struct acpi_device *device)
flush_workqueue(acpi_thermal_pm_queue);
tz = acpi_driver_data(device);
+ kfree(tz->trips);
acpi_thermal_unregister_thermal_zone(tz);
kfree(tz);
}