提交 ac7729da 编写于 作者: R Rafael J. Wysocki 提交者: Len Brown

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: NRafael J. Wysocki <rjw@sisk.pl>
Tested-by: NRafał Miłecki <zajec5@gmail.com>
Acked-by: NMatthew Garrett <mjg@redhat.com>
Signed-off-by: NLen Brown <len.brown@intel.com>
上级 7da23b86
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h> #include <acpi/acpi_drivers.h>
#include <linux/suspend.h>
#define PREFIX "ACPI: " #define PREFIX "ACPI: "
...@@ -89,7 +90,6 @@ module_param(allow_duplicates, bool, 0644); ...@@ -89,7 +90,6 @@ module_param(allow_duplicates, bool, 0644);
static int register_count = 0; static int register_count = 0;
static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device, int type); static int acpi_video_bus_remove(struct acpi_device *device, int type);
static int acpi_video_resume(struct acpi_device *device);
static void acpi_video_bus_notify(struct acpi_device *device, u32 event); static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id video_device_ids[] = { static const struct acpi_device_id video_device_ids[] = {
...@@ -105,7 +105,6 @@ static struct acpi_driver acpi_video_bus = { ...@@ -105,7 +105,6 @@ static struct acpi_driver acpi_video_bus = {
.ops = { .ops = {
.add = acpi_video_bus_add, .add = acpi_video_bus_add,
.remove = acpi_video_bus_remove, .remove = acpi_video_bus_remove,
.resume = acpi_video_resume,
.notify = acpi_video_bus_notify, .notify = acpi_video_bus_notify,
}, },
}; };
...@@ -160,6 +159,7 @@ struct acpi_video_bus { ...@@ -160,6 +159,7 @@ struct acpi_video_bus {
struct proc_dir_entry *dir; struct proc_dir_entry *dir;
struct input_dev *input; struct input_dev *input;
char phys[32]; /* for input device */ char phys[32]; /* for input device */
struct notifier_block pm_nb;
}; };
struct acpi_video_device_flags { struct acpi_video_device_flags {
...@@ -1021,6 +1021,13 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) ...@@ -1021,6 +1021,13 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
if (IS_ERR(device->backlight)) if (IS_ERR(device->backlight))
return; return;
/*
* Save current brightness level in case we have to restore it
* before acpi_video_device_lcd_set_level() is called next time.
*/
device->backlight->props.brightness =
acpi_video_get_brightness(device->backlight);
result = sysfs_create_link(&device->backlight->dev.kobj, result = sysfs_create_link(&device->backlight->dev.kobj,
&device->dev->dev.kobj, "device"); &device->dev->dev.kobj, "device");
if (result) if (result)
...@@ -2236,24 +2243,31 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) ...@@ -2236,24 +2243,31 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
return; return;
} }
static int instance; static int acpi_video_resume(struct notifier_block *nb,
static int acpi_video_resume(struct acpi_device *device) unsigned long val, void *ign)
{ {
struct acpi_video_bus *video; struct acpi_video_bus *video;
struct acpi_video_device *video_device; struct acpi_video_device *video_device;
int i; int i;
if (!device || !acpi_driver_data(device)) switch (val) {
return -EINVAL; case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
case PM_RESTORE_PREPARE:
return NOTIFY_DONE;
}
video = acpi_driver_data(device); video = container_of(nb, struct acpi_video_bus, pm_nb);
dev_info(&video->device->dev, "Restoring backlight state\n");
for (i = 0; i < video->attached_count; i++) { for (i = 0; i < video->attached_count; i++) {
video_device = video->attached_array[i].bind_info; video_device = video->attached_array[i].bind_info;
if (video_device && video_device->backlight) if (video_device && video_device->backlight)
acpi_video_set_brightness(video_device->backlight); acpi_video_set_brightness(video_device->backlight);
} }
return AE_OK;
return NOTIFY_OK;
} }
static acpi_status static acpi_status
...@@ -2277,6 +2291,8 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context, ...@@ -2277,6 +2291,8 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
return AE_OK; return AE_OK;
} }
static int instance;
static int acpi_video_bus_add(struct acpi_device *device) static int acpi_video_bus_add(struct acpi_device *device)
{ {
struct acpi_video_bus *video; struct acpi_video_bus *video;
...@@ -2370,6 +2386,10 @@ static int acpi_video_bus_add(struct acpi_device *device) ...@@ -2370,6 +2386,10 @@ static int acpi_video_bus_add(struct acpi_device *device)
video->flags.rom ? "yes" : "no", video->flags.rom ? "yes" : "no",
video->flags.post ? "yes" : "no"); video->flags.post ? "yes" : "no");
video->pm_nb.notifier_call = acpi_video_resume;
video->pm_nb.priority = 0;
register_pm_notifier(&video->pm_nb);
return 0; return 0;
err_free_input_dev: err_free_input_dev:
...@@ -2396,6 +2416,8 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) ...@@ -2396,6 +2416,8 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
video = acpi_driver_data(device); video = acpi_driver_data(device);
unregister_pm_notifier(&video->pm_nb);
acpi_video_bus_stop_devices(video); acpi_video_bus_stop_devices(video);
acpi_video_bus_put_devices(video); acpi_video_bus_put_devices(video);
acpi_video_bus_remove_fs(device); acpi_video_bus_remove_fs(device);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册