Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac7729da authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Len Brown
Browse files

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: default avatarRafael J. Wysocki <rjw@sisk.pl>
Tested-by: default avatarRafał Miłecki <zajec5@gmail.com>
Acked-by: default avatarMatthew Garrett <mjg@redhat.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 7da23b86
Loading
Loading
Loading
Loading
+30 −8
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@
#include <linux/dmi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/suspend.h>

#define PREFIX "ACPI: "

@@ -89,7 +90,6 @@ module_param(allow_duplicates, bool, 0644);
static int register_count = 0;
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_resume(struct acpi_device *device);
static void acpi_video_bus_notify(struct acpi_device *device, u32 event);

static const struct acpi_device_id video_device_ids[] = {
@@ -105,7 +105,6 @@ static struct acpi_driver acpi_video_bus = {
	.ops = {
		.add = acpi_video_bus_add,
		.remove = acpi_video_bus_remove,
		.resume = acpi_video_resume,
		.notify = acpi_video_bus_notify,
		},
};
@@ -160,6 +159,7 @@ struct acpi_video_bus {
	struct proc_dir_entry *dir;
	struct input_dev *input;
	char phys[32];	/* for input device */
	struct notifier_block pm_nb;
};

struct acpi_video_device_flags {
@@ -1021,6 +1021,13 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
		if (IS_ERR(device->backlight))
			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,
					   &device->dev->dev.kobj, "device");
		if (result)
@@ -2236,24 +2243,31 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
	return;
}

static int instance;
static int acpi_video_resume(struct acpi_device *device)
static int acpi_video_resume(struct notifier_block *nb,
				unsigned long val, void *ign)
{
	struct acpi_video_bus *video;
	struct acpi_video_device *video_device;
	int i;

	if (!device || !acpi_driver_data(device))
		return -EINVAL;
	switch (val) {
	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++) {
		video_device = video->attached_array[i].bind_info;
		if (video_device && video_device->backlight)
			acpi_video_set_brightness(video_device->backlight);
	}
	return AE_OK;

	return NOTIFY_OK;
}

static acpi_status
@@ -2277,6 +2291,8 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
	return AE_OK;
}

static int instance;

static int acpi_video_bus_add(struct acpi_device *device)
{
	struct acpi_video_bus *video;
@@ -2370,6 +2386,10 @@ static int acpi_video_bus_add(struct acpi_device *device)
	       video->flags.rom ? "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;

 err_free_input_dev:
@@ -2396,6 +2416,8 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)

	video = acpi_driver_data(device);

	unregister_pm_notifier(&video->pm_nb);

	acpi_video_bus_stop_devices(video);
	acpi_video_bus_put_devices(video);
	acpi_video_bus_remove_fs(device);