Skip to content

Commit 8c5bd7a

Browse files
committed
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>
1 parent c04c697 commit 8c5bd7a

File tree

6 files changed

+105
-10
lines changed

6 files changed

+105
-10
lines changed

drivers/acpi/internal.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,15 @@ struct platform_device;
164164
int acpi_create_platform_device(struct acpi_device *adev,
165165
const struct acpi_device_id *id);
166166

167+
/*--------------------------------------------------------------------------
168+
Video
169+
-------------------------------------------------------------------------- */
170+
#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
171+
bool acpi_video_backlight_quirks(void);
172+
bool acpi_video_verify_backlight_support(void);
173+
#else
174+
static inline bool acpi_video_backlight_quirks(void) { return false; }
175+
static inline bool acpi_video_verify_backlight_support(void) { return false; }
176+
#endif
177+
167178
#endif /* _ACPI_INTERNAL_H_ */

drivers/acpi/video.c

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
#include <linux/suspend.h>
4545
#include <acpi/video.h>
4646

47+
#include "internal.h"
48+
4749
#define PREFIX "ACPI: "
4850

4951
#define ACPI_VIDEO_BUS_NAME "Video Bus"
@@ -901,7 +903,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
901903
if (acpi_video_init_brightness(device))
902904
return;
903905

904-
if (acpi_video_backlight_support()) {
906+
if (acpi_video_verify_backlight_support()) {
905907
struct backlight_properties props;
906908
struct pci_dev *pdev;
907909
acpi_handle acpi_parent;
@@ -1356,8 +1358,8 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
13561358
unsigned long long level_current, level_next;
13571359
int result = -EINVAL;
13581360

1359-
/* no warning message if acpi_backlight=vendor is used */
1360-
if (!acpi_video_backlight_support())
1361+
/* no warning message if acpi_backlight=vendor or a quirk is used */
1362+
if (!acpi_video_verify_backlight_support())
13611363
return 0;
13621364

13631365
if (!device->brightness)
@@ -1859,6 +1861,46 @@ static int acpi_video_bus_remove(struct acpi_device *device)
18591861
return 0;
18601862
}
18611863

1864+
static 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+
18621904
static int __init is_i740(struct pci_dev *dev)
18631905
{
18641906
if (dev->device == 0x00D1)
@@ -1890,14 +1932,25 @@ static int __init intel_opregion_present(void)
18901932
return opregion;
18911933
}
18921934

1893-
int acpi_video_register(void)
1935+
int __acpi_video_register(bool backlight_quirks)
18941936
{
1895-
int result = 0;
1937+
bool no_backlight;
1938+
int result;
1939+
1940+
no_backlight = backlight_quirks ? acpi_video_backlight_quirks() : false;
1941+
18961942
if (register_count) {
18971943
/*
1898-
* if the function of acpi_video_register is already called,
1899-
* don't register the acpi_vide_bus again and return no error.
1944+
* If acpi_video_register() has been called already, don't try
1945+
* to register acpi_video_bus, but unregister backlight devices
1946+
* if no backlight support is requested.
19001947
*/
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+
19011954
return 0;
19021955
}
19031956

@@ -1913,7 +1966,7 @@ int acpi_video_register(void)
19131966

19141967
return 0;
19151968
}
1916-
EXPORT_SYMBOL(acpi_video_register);
1969+
EXPORT_SYMBOL(__acpi_video_register);
19171970

19181971
void acpi_video_unregister(void)
19191972
{

drivers/acpi/video_detect.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
#include <linux/dmi.h>
3939
#include <linux/pci.h>
4040

41+
#include "internal.h"
42+
4143
#define PREFIX "ACPI: "
4244

4345
ACPI_MODULE_NAME("video");
@@ -234,6 +236,17 @@ static void acpi_video_caps_check(void)
234236
acpi_video_get_capabilities(NULL);
235237
}
236238

239+
bool 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+
}
248+
EXPORT_SYMBOL(acpi_video_backlight_quirks);
249+
237250
/* Promote the vendor interface instead of the generic video module.
238251
* This function allow DMI blacklists to be implemented by externals
239252
* platform drivers instead of putting a big blacklist in video_detect.c
@@ -278,6 +291,14 @@ int acpi_video_backlight_support(void)
278291
}
279292
EXPORT_SYMBOL(acpi_video_backlight_support);
280293

294+
/* For the ACPI video driver use only. */
295+
bool acpi_video_verify_backlight_support(void)
296+
{
297+
return (acpi_video_support & ACPI_VIDEO_SKIP_BACKLIGHT) ?
298+
false : acpi_video_backlight_support();
299+
}
300+
EXPORT_SYMBOL(acpi_video_verify_backlight_support);
301+
281302
/*
282303
* Use acpi_backlight=vendor/video to force that backlight switching
283304
* is processed by vendor specific acpi drivers or video.ko driver.

drivers/gpu/drm/i915/i915_dma.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1648,7 +1648,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
16481648
if (INTEL_INFO(dev)->num_pipes) {
16491649
/* Must be done after probing outputs */
16501650
intel_opregion_init(dev);
1651-
acpi_video_register();
1651+
acpi_video_register_with_quirks();
16521652
}
16531653

16541654
if (IS_GEN5(dev))

include/acpi/video.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,21 @@ struct acpi_device;
1717
#define ACPI_VIDEO_DISPLAY_LEGACY_TV 0x0200
1818

1919
#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
20-
extern int acpi_video_register(void);
20+
extern int __acpi_video_register(bool backlight_quirks);
21+
static inline int acpi_video_register(void)
22+
{
23+
return __acpi_video_register(false);
24+
}
25+
static inline int acpi_video_register_with_quirks(void)
26+
{
27+
return __acpi_video_register(true);
28+
}
2129
extern void acpi_video_unregister(void);
2230
extern int acpi_video_get_edid(struct acpi_device *device, int type,
2331
int device_id, void **edid);
2432
#else
2533
static inline int acpi_video_register(void) { return 0; }
34+
static inline int acpi_video_register_with_quirks(void) { return 0; }
2635
static inline void acpi_video_unregister(void) { return; }
2736
static inline int acpi_video_get_edid(struct acpi_device *device, int type,
2837
int device_id, void **edid)

include/linux/acpi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ extern bool wmi_has_guid(const char *guid);
191191
#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200
192192
#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400
193193
#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800
194+
#define ACPI_VIDEO_SKIP_BACKLIGHT 0x1000
194195

195196
#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
196197

0 commit comments

Comments
 (0)