diff options
author | Matthew Garrett <mjg59@srcf.ucam.org> | 2009-03-19 17:35:39 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-03-27 22:11:03 -0400 |
commit | 74a365b3f354fafc537efa5867deb7a9fadbfe27 (patch) | |
tree | 66ebff203807d2ed77e77e1ccc2f71f63e571098 /drivers/acpi/video.c | |
parent | c60d638e29c780b75b648283a197d0226e3576c3 (diff) |
ACPI: Populate DIDL before registering ACPI video device on Intel
Intel graphics hardware that implements the ACPI IGD OpRegion spec
requires that the list of display devices be populated before any ACPI
video methods are called. Detect when this is the case and defer
registration until the opregion code calls it. Fixes crashes on HP
laptops.
http://bugzilla.kernel.org/show_bug.cgi?id=11259
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Acked-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/video.c')
-rw-r--r-- | drivers/acpi/video.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 9730ec167590..ae427100a1ef 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include <linux/thermal.h> | 37 | #include <linux/thermal.h> |
38 | #include <linux/video_output.h> | 38 | #include <linux/video_output.h> |
39 | #include <linux/sort.h> | 39 | #include <linux/sort.h> |
40 | #include <linux/pci.h> | ||
41 | #include <linux/pci_ids.h> | ||
40 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
41 | 43 | ||
42 | #include <acpi/acpi_bus.h> | 44 | #include <acpi/acpi_bus.h> |
@@ -2251,7 +2253,27 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) | |||
2251 | return 0; | 2253 | return 0; |
2252 | } | 2254 | } |
2253 | 2255 | ||
2254 | static int __init acpi_video_init(void) | 2256 | static int __init intel_opregion_present(void) |
2257 | { | ||
2258 | #if defined(CONFIG_DRM_I915) || defined(CONFIG_DRM_I915_MODULE) | ||
2259 | struct pci_dev *dev = NULL; | ||
2260 | u32 address; | ||
2261 | |||
2262 | for_each_pci_dev(dev) { | ||
2263 | if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) | ||
2264 | continue; | ||
2265 | if (dev->vendor != PCI_VENDOR_ID_INTEL) | ||
2266 | continue; | ||
2267 | pci_read_config_dword(dev, 0xfc, &address); | ||
2268 | if (!address) | ||
2269 | continue; | ||
2270 | return 1; | ||
2271 | } | ||
2272 | #endif | ||
2273 | return 0; | ||
2274 | } | ||
2275 | |||
2276 | int acpi_video_register(void) | ||
2255 | { | 2277 | { |
2256 | int result = 0; | 2278 | int result = 0; |
2257 | 2279 | ||
@@ -2268,6 +2290,22 @@ static int __init acpi_video_init(void) | |||
2268 | 2290 | ||
2269 | return 0; | 2291 | return 0; |
2270 | } | 2292 | } |
2293 | EXPORT_SYMBOL(acpi_video_register); | ||
2294 | |||
2295 | /* | ||
2296 | * This is kind of nasty. Hardware using Intel chipsets may require | ||
2297 | * the video opregion code to be run first in order to initialise | ||
2298 | * state before any ACPI video calls are made. To handle this we defer | ||
2299 | * registration of the video class until the opregion code has run. | ||
2300 | */ | ||
2301 | |||
2302 | static int __init acpi_video_init(void) | ||
2303 | { | ||
2304 | if (intel_opregion_present()) | ||
2305 | return 0; | ||
2306 | |||
2307 | return acpi_video_register(); | ||
2308 | } | ||
2271 | 2309 | ||
2272 | static void __exit acpi_video_exit(void) | 2310 | static void __exit acpi_video_exit(void) |
2273 | { | 2311 | { |