aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-07-17 20:08:06 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-07-17 20:08:06 -0400
commit8c5bd7adb2ce47e6aa39d17b2375f69b0c0aa255 (patch)
tree84ed8b6c9fd4e31eca9adbbbf6be9cd506a2fd46
parentc04c697cf1fe8f0962ccd3c2392a9b637a5307aa (diff)
ACPI / video / i915: No ACPI backlight if firmware expects Windows 8
According to Matthew Garrett, "Windows 8 leaves backlight control up to individual graphics drivers rather than making ACPI calls itself. There's plenty of evidence to suggest that the Intel driver for Windows [8] doesn't use the ACPI interface, including the fact that it's broken on a bunch of machines when the OS claims to support Windows 8. The simplest thing to do appears to be to disable the ACPI backlight interface on these systems". There's a problem with that approach, however, because simply avoiding to register the ACPI backlight interface if the firmware calls _OSI for Windows 8 may not work in the following situations: (1) The ACPI backlight interface actually works on the given system and the i915 driver is not loaded (e.g. another graphics driver is used). (2) The ACPI backlight interface doesn't work on the given system, but there is a vendor platform driver that will register its own, equally broken, backlight interface if not prevented from doing so by the ACPI subsystem. Therefore we need to allow the ACPI backlight interface to be registered until the i915 driver is loaded which then will unregister it if the firmware has called _OSI for Windows 8 (or will register the ACPI video driver without backlight support if not already present). For this reason, introduce an alternative function for registering ACPI video, acpi_video_register_with_quirks(), that will check whether or not the ACPI video driver has already been registered and whether or not the backlight Windows 8 quirk has to be applied. If the quirk has to be applied, it will block the ACPI backlight support and either unregister the backlight interface if the ACPI video driver has already been registered, or register the ACPI video driver without the backlight interface otherwise. Make the i915 driver use acpi_video_register_with_quirks() instead of acpi_video_register() in i915_driver_load(). This change is based on earlier patches from Matthew Garrett, Chun-Yi Lee and Seth Forshee and includes a fix from Aaron Lu's. References: https://bugzilla.kernel.org/show_bug.cgi?id=51231 Tested-by: Aaron Lu <aaron.lu@intel.com> Tested-by: Igor Gnatenko <i.gnatenko.brain@gmail.com> Tested-by: Yves-Alexis Perez <corsac@debian.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Aaron Lu <aaron.lu@intel.com> Acked-by: Matthew Garrett <matthew.garrett@nebula.com>
-rw-r--r--drivers/acpi/internal.h11
-rw-r--r--drivers/acpi/video.c69
-rw-r--r--drivers/acpi/video_detect.c21
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c2
-rw-r--r--include/acpi/video.h11
-rw-r--r--include/linux/acpi.h1
6 files changed, 105 insertions, 10 deletions
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 3a50a34fe176..227aca77ee1e 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -164,4 +164,15 @@ struct platform_device;
164int acpi_create_platform_device(struct acpi_device *adev, 164int acpi_create_platform_device(struct acpi_device *adev,
165 const struct acpi_device_id *id); 165 const struct acpi_device_id *id);
166 166
167/*--------------------------------------------------------------------------
168 Video
169 -------------------------------------------------------------------------- */
170#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
171bool acpi_video_backlight_quirks(void);
172bool acpi_video_verify_backlight_support(void);
173#else
174static inline bool acpi_video_backlight_quirks(void) { return false; }
175static inline bool acpi_video_verify_backlight_support(void) { return false; }
176#endif
177
167#endif /* _ACPI_INTERNAL_H_ */ 178#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index f236e172d948..e9d4bb60c35c 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -44,6 +44,8 @@
44#include <linux/suspend.h> 44#include <linux/suspend.h>
45#include <acpi/video.h> 45#include <acpi/video.h>
46 46
47#include "internal.h"
48
47#define PREFIX "ACPI: " 49#define PREFIX "ACPI: "
48 50
49#define ACPI_VIDEO_BUS_NAME "Video Bus" 51#define ACPI_VIDEO_BUS_NAME "Video Bus"
@@ -901,7 +903,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
901 if (acpi_video_init_brightness(device)) 903 if (acpi_video_init_brightness(device))
902 return; 904 return;
903 905
904 if (acpi_video_backlight_support()) { 906 if (acpi_video_verify_backlight_support()) {
905 struct backlight_properties props; 907 struct backlight_properties props;
906 struct pci_dev *pdev; 908 struct pci_dev *pdev;
907 acpi_handle acpi_parent; 909 acpi_handle acpi_parent;
@@ -1356,8 +1358,8 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
1356 unsigned long long level_current, level_next; 1358 unsigned long long level_current, level_next;
1357 int result = -EINVAL; 1359 int result = -EINVAL;
1358 1360
1359 /* no warning message if acpi_backlight=vendor is used */ 1361 /* no warning message if acpi_backlight=vendor or a quirk is used */
1360 if (!acpi_video_backlight_support()) 1362 if (!acpi_video_verify_backlight_support())
1361 return 0; 1363 return 0;
1362 1364
1363 if (!device->brightness) 1365 if (!device->brightness)
@@ -1859,6 +1861,46 @@ static int acpi_video_bus_remove(struct acpi_device *device)
1859 return 0; 1861 return 0;
1860} 1862}
1861 1863
1864static acpi_status video_unregister_backlight(acpi_handle handle, u32 lvl,
1865 void *context, void **rv)
1866{
1867 struct acpi_device *acpi_dev;
1868 struct acpi_video_bus *video;
1869 struct acpi_video_device *dev, *next;
1870
1871 if (acpi_bus_get_device(handle, &acpi_dev))
1872 return AE_OK;
1873
1874 if (acpi_match_device_ids(acpi_dev, video_device_ids))
1875 return AE_OK;
1876
1877 video = acpi_driver_data(acpi_dev);
1878 if (!video)
1879 return AE_OK;
1880
1881 acpi_video_bus_stop_devices(video);
1882 mutex_lock(&video->device_list_lock);
1883 list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {
1884 if (dev->backlight) {
1885 backlight_device_unregister(dev->backlight);
1886 dev->backlight = NULL;
1887 kfree(dev->brightness->levels);
1888 kfree(dev->brightness);
1889 }
1890 if (dev->cooling_dev) {
1891 sysfs_remove_link(&dev->dev->dev.kobj,
1892 "thermal_cooling");
1893 sysfs_remove_link(&dev->cooling_dev->device.kobj,
1894 "device");
1895 thermal_cooling_device_unregister(dev->cooling_dev);
1896 dev->cooling_dev = NULL;
1897 }
1898 }
1899 mutex_unlock(&video->device_list_lock);
1900 acpi_video_bus_start_devices(video);
1901 return AE_OK;
1902}
1903
1862static int __init is_i740(struct pci_dev *dev) 1904static int __init is_i740(struct pci_dev *dev)
1863{ 1905{
1864 if (dev->device == 0x00D1) 1906 if (dev->device == 0x00D1)
@@ -1890,14 +1932,25 @@ static int __init intel_opregion_present(void)
1890 return opregion; 1932 return opregion;
1891} 1933}
1892 1934
1893int acpi_video_register(void) 1935int __acpi_video_register(bool backlight_quirks)
1894{ 1936{
1895 int result = 0; 1937 bool no_backlight;
1938 int result;
1939
1940 no_backlight = backlight_quirks ? acpi_video_backlight_quirks() : false;
1941
1896 if (register_count) { 1942 if (register_count) {
1897 /* 1943 /*
1898 * if the function of acpi_video_register is already called, 1944 * If acpi_video_register() has been called already, don't try
1899 * don't register the acpi_vide_bus again and return no error. 1945 * to register acpi_video_bus, but unregister backlight devices
1946 * if no backlight support is requested.
1900 */ 1947 */
1948 if (no_backlight)
1949 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
1950 ACPI_UINT32_MAX,
1951 video_unregister_backlight,
1952 NULL, NULL, NULL);
1953
1901 return 0; 1954 return 0;
1902 } 1955 }
1903 1956
@@ -1913,7 +1966,7 @@ int acpi_video_register(void)
1913 1966
1914 return 0; 1967 return 0;
1915} 1968}
1916EXPORT_SYMBOL(acpi_video_register); 1969EXPORT_SYMBOL(__acpi_video_register);
1917 1970
1918void acpi_video_unregister(void) 1971void acpi_video_unregister(void)
1919{ 1972{
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index e6bd910bc6ed..826e52def080 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -38,6 +38,8 @@
38#include <linux/dmi.h> 38#include <linux/dmi.h>
39#include <linux/pci.h> 39#include <linux/pci.h>
40 40
41#include "internal.h"
42
41#define PREFIX "ACPI: " 43#define PREFIX "ACPI: "
42 44
43ACPI_MODULE_NAME("video"); 45ACPI_MODULE_NAME("video");
@@ -234,6 +236,17 @@ static void acpi_video_caps_check(void)
234 acpi_video_get_capabilities(NULL); 236 acpi_video_get_capabilities(NULL);
235} 237}
236 238
239bool acpi_video_backlight_quirks(void)
240{
241 if (acpi_gbl_osi_data >= ACPI_OSI_WIN_8) {
242 acpi_video_caps_check();
243 acpi_video_support |= ACPI_VIDEO_SKIP_BACKLIGHT;
244 return true;
245 }
246 return false;
247}
248EXPORT_SYMBOL(acpi_video_backlight_quirks);
249
237/* Promote the vendor interface instead of the generic video module. 250/* Promote the vendor interface instead of the generic video module.
238 * This function allow DMI blacklists to be implemented by externals 251 * This function allow DMI blacklists to be implemented by externals
239 * platform drivers instead of putting a big blacklist in video_detect.c 252 * platform drivers instead of putting a big blacklist in video_detect.c
@@ -278,6 +291,14 @@ int acpi_video_backlight_support(void)
278} 291}
279EXPORT_SYMBOL(acpi_video_backlight_support); 292EXPORT_SYMBOL(acpi_video_backlight_support);
280 293
294/* For the ACPI video driver use only. */
295bool acpi_video_verify_backlight_support(void)
296{
297 return (acpi_video_support & ACPI_VIDEO_SKIP_BACKLIGHT) ?
298 false : acpi_video_backlight_support();
299}
300EXPORT_SYMBOL(acpi_video_verify_backlight_support);
301
281/* 302/*
282 * Use acpi_backlight=vendor/video to force that backlight switching 303 * Use acpi_backlight=vendor/video to force that backlight switching
283 * is processed by vendor specific acpi drivers or video.ko driver. 304 * is processed by vendor specific acpi drivers or video.ko driver.
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index adb319b53ecd..cf188ab7051a 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1648,7 +1648,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
1648 if (INTEL_INFO(dev)->num_pipes) { 1648 if (INTEL_INFO(dev)->num_pipes) {
1649 /* Must be done after probing outputs */ 1649 /* Must be done after probing outputs */
1650 intel_opregion_init(dev); 1650 intel_opregion_init(dev);
1651 acpi_video_register(); 1651 acpi_video_register_with_quirks();
1652 } 1652 }
1653 1653
1654 if (IS_GEN5(dev)) 1654 if (IS_GEN5(dev))
diff --git a/include/acpi/video.h b/include/acpi/video.h
index 61109f2609fc..b26dc4fb7ba8 100644
--- a/include/acpi/video.h
+++ b/include/acpi/video.h
@@ -17,12 +17,21 @@ struct acpi_device;
17#define ACPI_VIDEO_DISPLAY_LEGACY_TV 0x0200 17#define ACPI_VIDEO_DISPLAY_LEGACY_TV 0x0200
18 18
19#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE) 19#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
20extern int acpi_video_register(void); 20extern int __acpi_video_register(bool backlight_quirks);
21static inline int acpi_video_register(void)
22{
23 return __acpi_video_register(false);
24}
25static inline int acpi_video_register_with_quirks(void)
26{
27 return __acpi_video_register(true);
28}
21extern void acpi_video_unregister(void); 29extern void acpi_video_unregister(void);
22extern int acpi_video_get_edid(struct acpi_device *device, int type, 30extern int acpi_video_get_edid(struct acpi_device *device, int type,
23 int device_id, void **edid); 31 int device_id, void **edid);
24#else 32#else
25static inline int acpi_video_register(void) { return 0; } 33static inline int acpi_video_register(void) { return 0; }
34static inline int acpi_video_register_with_quirks(void) { return 0; }
26static inline void acpi_video_unregister(void) { return; } 35static inline void acpi_video_unregister(void) { return; }
27static inline int acpi_video_get_edid(struct acpi_device *device, int type, 36static inline int acpi_video_get_edid(struct acpi_device *device, int type,
28 int device_id, void **edid) 37 int device_id, void **edid)
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 353ba256f368..6ad72f92469c 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -191,6 +191,7 @@ extern bool wmi_has_guid(const char *guid);
191#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200 191#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200
192#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400 192#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400
193#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800 193#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800
194#define ACPI_VIDEO_SKIP_BACKLIGHT 0x1000
194 195
195#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) 196#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
196 197