diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2010-04-04 19:43:51 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2010-04-06 17:02:00 -0400 |
commit | ac7729da880e742613129ee6dea0045328670d2d (patch) | |
tree | 6af1dcc2a3aa141164cfb7e3c177186fe3ec22d8 /drivers/acpi | |
parent | 7da23b86e14b77c094b11a9fa5ef5b3758fc9193 (diff) |
ACPI / PM: Move ACPI video resume to a PM notifier
There is a problem with the ACPI video resume routine that it's
executed before the GPU that may be accessed by it. To fix this
issue, move the ACPI video resume to a power management notifier,
so that's executed after resuming all devices, including the GPU.
Fixes https://bugzilla.kernel.org/show_bug.cgi?id=15096, which is
a listed regression from 2.6.31.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Tested-by: Rafał Miłecki <zajec5@gmail.com>
Acked-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/video.c | 38 |
1 files changed, 30 insertions, 8 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 6a0143796772..416eb0303a83 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/dmi.h> | 44 | #include <linux/dmi.h> |
45 | #include <acpi/acpi_bus.h> | 45 | #include <acpi/acpi_bus.h> |
46 | #include <acpi/acpi_drivers.h> | 46 | #include <acpi/acpi_drivers.h> |
47 | #include <linux/suspend.h> | ||
47 | 48 | ||
48 | #define PREFIX "ACPI: " | 49 | #define PREFIX "ACPI: " |
49 | 50 | ||
@@ -89,7 +90,6 @@ module_param(allow_duplicates, bool, 0644); | |||
89 | static int register_count = 0; | 90 | static int register_count = 0; |
90 | static int acpi_video_bus_add(struct acpi_device *device); | 91 | static int acpi_video_bus_add(struct acpi_device *device); |
91 | static int acpi_video_bus_remove(struct acpi_device *device, int type); | 92 | static int acpi_video_bus_remove(struct acpi_device *device, int type); |
92 | static int acpi_video_resume(struct acpi_device *device); | ||
93 | static void acpi_video_bus_notify(struct acpi_device *device, u32 event); | 93 | static void acpi_video_bus_notify(struct acpi_device *device, u32 event); |
94 | 94 | ||
95 | static const struct acpi_device_id video_device_ids[] = { | 95 | static const struct acpi_device_id video_device_ids[] = { |
@@ -105,7 +105,6 @@ static struct acpi_driver acpi_video_bus = { | |||
105 | .ops = { | 105 | .ops = { |
106 | .add = acpi_video_bus_add, | 106 | .add = acpi_video_bus_add, |
107 | .remove = acpi_video_bus_remove, | 107 | .remove = acpi_video_bus_remove, |
108 | .resume = acpi_video_resume, | ||
109 | .notify = acpi_video_bus_notify, | 108 | .notify = acpi_video_bus_notify, |
110 | }, | 109 | }, |
111 | }; | 110 | }; |
@@ -160,6 +159,7 @@ struct acpi_video_bus { | |||
160 | struct proc_dir_entry *dir; | 159 | struct proc_dir_entry *dir; |
161 | struct input_dev *input; | 160 | struct input_dev *input; |
162 | char phys[32]; /* for input device */ | 161 | char phys[32]; /* for input device */ |
162 | struct notifier_block pm_nb; | ||
163 | }; | 163 | }; |
164 | 164 | ||
165 | struct acpi_video_device_flags { | 165 | struct acpi_video_device_flags { |
@@ -1021,6 +1021,13 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
1021 | if (IS_ERR(device->backlight)) | 1021 | if (IS_ERR(device->backlight)) |
1022 | return; | 1022 | return; |
1023 | 1023 | ||
1024 | /* | ||
1025 | * Save current brightness level in case we have to restore it | ||
1026 | * before acpi_video_device_lcd_set_level() is called next time. | ||
1027 | */ | ||
1028 | device->backlight->props.brightness = | ||
1029 | acpi_video_get_brightness(device->backlight); | ||
1030 | |||
1024 | result = sysfs_create_link(&device->backlight->dev.kobj, | 1031 | result = sysfs_create_link(&device->backlight->dev.kobj, |
1025 | &device->dev->dev.kobj, "device"); | 1032 | &device->dev->dev.kobj, "device"); |
1026 | if (result) | 1033 | if (result) |
@@ -2236,24 +2243,31 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) | |||
2236 | return; | 2243 | return; |
2237 | } | 2244 | } |
2238 | 2245 | ||
2239 | static int instance; | 2246 | static int acpi_video_resume(struct notifier_block *nb, |
2240 | static int acpi_video_resume(struct acpi_device *device) | 2247 | unsigned long val, void *ign) |
2241 | { | 2248 | { |
2242 | struct acpi_video_bus *video; | 2249 | struct acpi_video_bus *video; |
2243 | struct acpi_video_device *video_device; | 2250 | struct acpi_video_device *video_device; |
2244 | int i; | 2251 | int i; |
2245 | 2252 | ||
2246 | if (!device || !acpi_driver_data(device)) | 2253 | switch (val) { |
2247 | return -EINVAL; | 2254 | case PM_HIBERNATION_PREPARE: |
2255 | case PM_SUSPEND_PREPARE: | ||
2256 | case PM_RESTORE_PREPARE: | ||
2257 | return NOTIFY_DONE; | ||
2258 | } | ||
2248 | 2259 | ||
2249 | video = acpi_driver_data(device); | 2260 | video = container_of(nb, struct acpi_video_bus, pm_nb); |
2261 | |||
2262 | dev_info(&video->device->dev, "Restoring backlight state\n"); | ||
2250 | 2263 | ||
2251 | for (i = 0; i < video->attached_count; i++) { | 2264 | for (i = 0; i < video->attached_count; i++) { |
2252 | video_device = video->attached_array[i].bind_info; | 2265 | video_device = video->attached_array[i].bind_info; |
2253 | if (video_device && video_device->backlight) | 2266 | if (video_device && video_device->backlight) |
2254 | acpi_video_set_brightness(video_device->backlight); | 2267 | acpi_video_set_brightness(video_device->backlight); |
2255 | } | 2268 | } |
2256 | return AE_OK; | 2269 | |
2270 | return NOTIFY_OK; | ||
2257 | } | 2271 | } |
2258 | 2272 | ||
2259 | static acpi_status | 2273 | static acpi_status |
@@ -2277,6 +2291,8 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context, | |||
2277 | return AE_OK; | 2291 | return AE_OK; |
2278 | } | 2292 | } |
2279 | 2293 | ||
2294 | static int instance; | ||
2295 | |||
2280 | static int acpi_video_bus_add(struct acpi_device *device) | 2296 | static int acpi_video_bus_add(struct acpi_device *device) |
2281 | { | 2297 | { |
2282 | struct acpi_video_bus *video; | 2298 | struct acpi_video_bus *video; |
@@ -2370,6 +2386,10 @@ static int acpi_video_bus_add(struct acpi_device *device) | |||
2370 | video->flags.rom ? "yes" : "no", | 2386 | video->flags.rom ? "yes" : "no", |
2371 | video->flags.post ? "yes" : "no"); | 2387 | video->flags.post ? "yes" : "no"); |
2372 | 2388 | ||
2389 | video->pm_nb.notifier_call = acpi_video_resume; | ||
2390 | video->pm_nb.priority = 0; | ||
2391 | register_pm_notifier(&video->pm_nb); | ||
2392 | |||
2373 | return 0; | 2393 | return 0; |
2374 | 2394 | ||
2375 | err_free_input_dev: | 2395 | err_free_input_dev: |
@@ -2396,6 +2416,8 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) | |||
2396 | 2416 | ||
2397 | video = acpi_driver_data(device); | 2417 | video = acpi_driver_data(device); |
2398 | 2418 | ||
2419 | unregister_pm_notifier(&video->pm_nb); | ||
2420 | |||
2399 | acpi_video_bus_stop_devices(video); | 2421 | acpi_video_bus_stop_devices(video); |
2400 | acpi_video_bus_put_devices(video); | 2422 | acpi_video_bus_put_devices(video); |
2401 | acpi_video_bus_remove_fs(device); | 2423 | acpi_video_bus_remove_fs(device); |