diff options
author | Aaron Lu <aaron.lu@intel.com> | 2014-03-04 01:24:46 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-03-04 19:43:44 -0500 |
commit | a59ffb2062df3a5c346dbed931fa1e587fd0f0f3 (patch) | |
tree | fe3f973f9a0f85fcdd5e7ce723bd895495453132 /drivers/acpi/thermal.c | |
parent | 0414855fdc4a40da05221fc6062cccbc0c30f169 (diff) |
ACPI / thermal: make acpi_thermal_check asynchronous on resume
On resume we do not need to wait for acpi_thermal_check to finish.
Instead, we can run it asynchronously and not block the whole system
resume. Also, we make sure when we are suspending again, previously
queued work for acpi_thermal_check is done.
Signed-off-by: Aaron Lu <aaron.lu@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/thermal.c')
-rw-r--r-- | drivers/acpi/thermal.c | 37 |
1 files changed, 33 insertions, 4 deletions
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 08626c851be7..964068553334 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/device.h> | 43 | #include <linux/device.h> |
44 | #include <linux/thermal.h> | 44 | #include <linux/thermal.h> |
45 | #include <linux/acpi.h> | 45 | #include <linux/acpi.h> |
46 | #include <linux/workqueue.h> | ||
46 | #include <asm/uaccess.h> | 47 | #include <asm/uaccess.h> |
47 | 48 | ||
48 | #define PREFIX "ACPI: " | 49 | #define PREFIX "ACPI: " |
@@ -90,6 +91,8 @@ static int psv; | |||
90 | module_param(psv, int, 0644); | 91 | module_param(psv, int, 0644); |
91 | MODULE_PARM_DESC(psv, "Disable or override all passive trip points."); | 92 | MODULE_PARM_DESC(psv, "Disable or override all passive trip points."); |
92 | 93 | ||
94 | static struct workqueue_struct *acpi_thermal_pm_queue; | ||
95 | |||
93 | static int acpi_thermal_add(struct acpi_device *device); | 96 | static int acpi_thermal_add(struct acpi_device *device); |
94 | static int acpi_thermal_remove(struct acpi_device *device); | 97 | static int acpi_thermal_remove(struct acpi_device *device); |
95 | static void acpi_thermal_notify(struct acpi_device *device, u32 event); | 98 | static void acpi_thermal_notify(struct acpi_device *device, u32 event); |
@@ -101,11 +104,13 @@ static const struct acpi_device_id thermal_device_ids[] = { | |||
101 | MODULE_DEVICE_TABLE(acpi, thermal_device_ids); | 104 | MODULE_DEVICE_TABLE(acpi, thermal_device_ids); |
102 | 105 | ||
103 | #ifdef CONFIG_PM_SLEEP | 106 | #ifdef CONFIG_PM_SLEEP |
107 | static int acpi_thermal_suspend(struct device *dev); | ||
104 | static int acpi_thermal_resume(struct device *dev); | 108 | static int acpi_thermal_resume(struct device *dev); |
105 | #else | 109 | #else |
110 | #define acpi_thermal_suspend NULL | ||
106 | #define acpi_thermal_resume NULL | 111 | #define acpi_thermal_resume NULL |
107 | #endif | 112 | #endif |
108 | static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume); | 113 | static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume); |
109 | 114 | ||
110 | static struct acpi_driver acpi_thermal_driver = { | 115 | static struct acpi_driver acpi_thermal_driver = { |
111 | .name = "thermal", | 116 | .name = "thermal", |
@@ -186,6 +191,7 @@ struct acpi_thermal { | |||
186 | struct thermal_zone_device *thermal_zone; | 191 | struct thermal_zone_device *thermal_zone; |
187 | int tz_enabled; | 192 | int tz_enabled; |
188 | int kelvin_offset; | 193 | int kelvin_offset; |
194 | struct work_struct thermal_check_work; | ||
189 | }; | 195 | }; |
190 | 196 | ||
191 | /* -------------------------------------------------------------------------- | 197 | /* -------------------------------------------------------------------------- |
@@ -1064,6 +1070,13 @@ static void acpi_thermal_guess_offset(struct acpi_thermal *tz) | |||
1064 | tz->kelvin_offset = 2732; | 1070 | tz->kelvin_offset = 2732; |
1065 | } | 1071 | } |
1066 | 1072 | ||
1073 | static void acpi_thermal_check_fn(struct work_struct *work) | ||
1074 | { | ||
1075 | struct acpi_thermal *tz = container_of(work, struct acpi_thermal, | ||
1076 | thermal_check_work); | ||
1077 | acpi_thermal_check(tz); | ||
1078 | } | ||
1079 | |||
1067 | static int acpi_thermal_add(struct acpi_device *device) | 1080 | static int acpi_thermal_add(struct acpi_device *device) |
1068 | { | 1081 | { |
1069 | int result = 0; | 1082 | int result = 0; |
@@ -1093,6 +1106,8 @@ static int acpi_thermal_add(struct acpi_device *device) | |||
1093 | if (result) | 1106 | if (result) |
1094 | goto free_memory; | 1107 | goto free_memory; |
1095 | 1108 | ||
1109 | INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn); | ||
1110 | |||
1096 | pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device), | 1111 | pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device), |
1097 | acpi_device_bid(device), KELVIN_TO_CELSIUS(tz->temperature)); | 1112 | acpi_device_bid(device), KELVIN_TO_CELSIUS(tz->temperature)); |
1098 | goto end; | 1113 | goto end; |
@@ -1110,6 +1125,7 @@ static int acpi_thermal_remove(struct acpi_device *device) | |||
1110 | if (!device || !acpi_driver_data(device)) | 1125 | if (!device || !acpi_driver_data(device)) |
1111 | return -EINVAL; | 1126 | return -EINVAL; |
1112 | 1127 | ||
1128 | flush_workqueue(acpi_thermal_pm_queue); | ||
1113 | tz = acpi_driver_data(device); | 1129 | tz = acpi_driver_data(device); |
1114 | 1130 | ||
1115 | acpi_thermal_unregister_thermal_zone(tz); | 1131 | acpi_thermal_unregister_thermal_zone(tz); |
@@ -1118,6 +1134,13 @@ static int acpi_thermal_remove(struct acpi_device *device) | |||
1118 | } | 1134 | } |
1119 | 1135 | ||
1120 | #ifdef CONFIG_PM_SLEEP | 1136 | #ifdef CONFIG_PM_SLEEP |
1137 | static int acpi_thermal_suspend(struct device *dev) | ||
1138 | { | ||
1139 | /* Make sure the previously queued thermal check work has been done */ | ||
1140 | flush_workqueue(acpi_thermal_pm_queue); | ||
1141 | return 0; | ||
1142 | } | ||
1143 | |||
1121 | static int acpi_thermal_resume(struct device *dev) | 1144 | static int acpi_thermal_resume(struct device *dev) |
1122 | { | 1145 | { |
1123 | struct acpi_thermal *tz; | 1146 | struct acpi_thermal *tz; |
@@ -1148,7 +1171,7 @@ static int acpi_thermal_resume(struct device *dev) | |||
1148 | tz->state.active |= tz->trips.active[i].flags.enabled; | 1171 | tz->state.active |= tz->trips.active[i].flags.enabled; |
1149 | } | 1172 | } |
1150 | 1173 | ||
1151 | acpi_thermal_check(tz); | 1174 | queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work); |
1152 | 1175 | ||
1153 | return AE_OK; | 1176 | return AE_OK; |
1154 | } | 1177 | } |
@@ -1240,16 +1263,22 @@ static int __init acpi_thermal_init(void) | |||
1240 | return -ENODEV; | 1263 | return -ENODEV; |
1241 | } | 1264 | } |
1242 | 1265 | ||
1266 | acpi_thermal_pm_queue = create_workqueue("acpi_thermal_pm"); | ||
1267 | if (!acpi_thermal_pm_queue) | ||
1268 | return -ENODEV; | ||
1269 | |||
1243 | result = acpi_bus_register_driver(&acpi_thermal_driver); | 1270 | result = acpi_bus_register_driver(&acpi_thermal_driver); |
1244 | if (result < 0) | 1271 | if (result < 0) { |
1272 | destroy_workqueue(acpi_thermal_pm_queue); | ||
1245 | return -ENODEV; | 1273 | return -ENODEV; |
1274 | } | ||
1246 | 1275 | ||
1247 | return 0; | 1276 | return 0; |
1248 | } | 1277 | } |
1249 | 1278 | ||
1250 | static void __exit acpi_thermal_exit(void) | 1279 | static void __exit acpi_thermal_exit(void) |
1251 | { | 1280 | { |
1252 | 1281 | destroy_workqueue(acpi_thermal_pm_queue); | |
1253 | acpi_bus_unregister_driver(&acpi_thermal_driver); | 1282 | acpi_bus_unregister_driver(&acpi_thermal_driver); |
1254 | 1283 | ||
1255 | return; | 1284 | return; |