aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhao Yakui <yakui.zhao@intel.com>2009-06-15 23:23:13 -0400
committerLen Brown <len.brown@intel.com>2009-06-23 23:38:41 -0400
commit86e437f077c68112edcb6854ec036ed7e3f9a7f3 (patch)
treeac6ec8b6ac4f96ce7ef7b5e9fa057099d7ce9af1
parent07a2039b8eb0af4ff464efd3dfd95de5c02648c6 (diff)
ACPI: Add the reference count to avoid unloading ACPI video bus twice
Sometimes both acpi video and i915 driver are compiled as modules. And there exists the strict dependency between the two drivers. The acpi video bus will be unloaded in course of unloading the i915 driver. If we unload the acpi video driver, then the kernel oops will be triggered. Add the reference count to avoid unloading the ACPI video bus twice. The reference count should be checked before unregistering the acpi video bus. If the reference count is already zero, it won't unregister it again. And after the acpi video bus is already unregistered, the reference count will be set to zero. http://bugzilla.kernel.org/show_bug.cgi?id=13396 Signed-off-by: Zhao Yakui <yakui.zhao@intel.com> Acked-by: Zhang Rui <rui.zhang@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/video.c41
-rw-r--r--drivers/gpu/drm/i915/i915_opregion.c2
-rw-r--r--include/acpi/video.h4
3 files changed, 38 insertions, 9 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 1bdfb37377e3..a63566ba230b 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -76,6 +76,7 @@ MODULE_LICENSE("GPL");
76static int brightness_switch_enabled = 1; 76static int brightness_switch_enabled = 1;
77module_param(brightness_switch_enabled, bool, 0644); 77module_param(brightness_switch_enabled, bool, 0644);
78 78
79static int register_count = 0;
79static int acpi_video_bus_add(struct acpi_device *device); 80static int acpi_video_bus_add(struct acpi_device *device);
80static int acpi_video_bus_remove(struct acpi_device *device, int type); 81static int acpi_video_bus_remove(struct acpi_device *device, int type);
81static int acpi_video_resume(struct acpi_device *device); 82static int acpi_video_resume(struct acpi_device *device);
@@ -2318,6 +2319,13 @@ static int __init intel_opregion_present(void)
2318int acpi_video_register(void) 2319int acpi_video_register(void)
2319{ 2320{
2320 int result = 0; 2321 int result = 0;
2322 if (register_count) {
2323 /*
2324 * if the function of acpi_video_register is already called,
2325 * don't register the acpi_vide_bus again and return no error.
2326 */
2327 return 0;
2328 }
2321 2329
2322 acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir); 2330 acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
2323 if (!acpi_video_dir) 2331 if (!acpi_video_dir)
@@ -2329,10 +2337,35 @@ int acpi_video_register(void)
2329 return -ENODEV; 2337 return -ENODEV;
2330 } 2338 }
2331 2339
2340 /*
2341 * When the acpi_video_bus is loaded successfully, increase
2342 * the counter reference.
2343 */
2344 register_count = 1;
2345
2332 return 0; 2346 return 0;
2333} 2347}
2334EXPORT_SYMBOL(acpi_video_register); 2348EXPORT_SYMBOL(acpi_video_register);
2335 2349
2350void acpi_video_unregister(void)
2351{
2352 if (!register_count) {
2353 /*
2354 * If the acpi video bus is already unloaded, don't
2355 * unload it again and return directly.
2356 */
2357 return;
2358 }
2359 acpi_bus_unregister_driver(&acpi_video_bus);
2360
2361 remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
2362
2363 register_count = 0;
2364
2365 return;
2366}
2367EXPORT_SYMBOL(acpi_video_unregister);
2368
2336/* 2369/*
2337 * This is kind of nasty. Hardware using Intel chipsets may require 2370 * This is kind of nasty. Hardware using Intel chipsets may require
2338 * the video opregion code to be run first in order to initialise 2371 * the video opregion code to be run first in order to initialise
@@ -2350,16 +2383,12 @@ static int __init acpi_video_init(void)
2350 return acpi_video_register(); 2383 return acpi_video_register();
2351} 2384}
2352 2385
2353void acpi_video_exit(void) 2386static void __exit acpi_video_exit(void)
2354{ 2387{
2355 2388 acpi_video_unregister();
2356 acpi_bus_unregister_driver(&acpi_video_bus);
2357
2358 remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
2359 2389
2360 return; 2390 return;
2361} 2391}
2362EXPORT_SYMBOL(acpi_video_exit);
2363 2392
2364module_init(acpi_video_init); 2393module_init(acpi_video_init);
2365module_exit(acpi_video_exit); 2394module_exit(acpi_video_exit);
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c
index dc425e74a268..e4b4e8898e39 100644
--- a/drivers/gpu/drm/i915/i915_opregion.c
+++ b/drivers/gpu/drm/i915/i915_opregion.c
@@ -419,7 +419,7 @@ void intel_opregion_free(struct drm_device *dev, int suspend)
419 return; 419 return;
420 420
421 if (!suspend) 421 if (!suspend)
422 acpi_video_exit(); 422 acpi_video_unregister();
423 423
424 opregion->acpi->drdy = 0; 424 opregion->acpi->drdy = 0;
425 425
diff --git a/include/acpi/video.h b/include/acpi/video.h
index af6fe95fd3d0..cf7be3dd157b 100644
--- a/include/acpi/video.h
+++ b/include/acpi/video.h
@@ -3,10 +3,10 @@
3 3
4#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE) 4#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
5extern int acpi_video_register(void); 5extern int acpi_video_register(void);
6extern int acpi_video_exit(void); 6extern void acpi_video_unregister(void);
7#else 7#else
8static inline int acpi_video_register(void) { return 0; } 8static inline int acpi_video_register(void) { return 0; }
9static inline void acpi_video_exit(void) { return; } 9static inline void acpi_video_unregister(void) { return; }
10#endif 10#endif
11 11
12#endif 12#endif