aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_fbdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/intel_fbdev.c')
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c83
1 files changed, 59 insertions, 24 deletions
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index f475414671d8..9b584f3fbb99 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -24,8 +24,10 @@
24 * David Airlie 24 * David Airlie
25 */ 25 */
26 26
27#include <linux/async.h>
27#include <linux/module.h> 28#include <linux/module.h>
28#include <linux/kernel.h> 29#include <linux/kernel.h>
30#include <linux/console.h>
29#include <linux/errno.h> 31#include <linux/errno.h>
30#include <linux/string.h> 32#include <linux/string.h>
31#include <linux/mm.h> 33#include <linux/mm.h>
@@ -331,24 +333,6 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
331 int num_connectors_enabled = 0; 333 int num_connectors_enabled = 0;
332 int num_connectors_detected = 0; 334 int num_connectors_detected = 0;
333 335
334 /*
335 * If the user specified any force options, just bail here
336 * and use that config.
337 */
338 for (i = 0; i < fb_helper->connector_count; i++) {
339 struct drm_fb_helper_connector *fb_conn;
340 struct drm_connector *connector;
341
342 fb_conn = fb_helper->connector_info[i];
343 connector = fb_conn->connector;
344
345 if (!enabled[i])
346 continue;
347
348 if (connector->force != DRM_FORCE_UNSPECIFIED)
349 return false;
350 }
351
352 save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), 336 save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool),
353 GFP_KERNEL); 337 GFP_KERNEL);
354 if (!save_enabled) 338 if (!save_enabled)
@@ -374,8 +358,18 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
374 continue; 358 continue;
375 } 359 }
376 360
361 if (connector->force == DRM_FORCE_OFF) {
362 DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
363 connector->name);
364 enabled[i] = false;
365 continue;
366 }
367
377 encoder = connector->encoder; 368 encoder = connector->encoder;
378 if (!encoder || WARN_ON(!encoder->crtc)) { 369 if (!encoder || WARN_ON(!encoder->crtc)) {
370 if (connector->force > DRM_FORCE_OFF)
371 goto bail;
372
379 DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n", 373 DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
380 connector->name); 374 connector->name);
381 enabled[i] = false; 375 enabled[i] = false;
@@ -394,8 +388,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
394 for (j = 0; j < fb_helper->connector_count; j++) { 388 for (j = 0; j < fb_helper->connector_count; j++) {
395 if (crtcs[j] == new_crtc) { 389 if (crtcs[j] == new_crtc) {
396 DRM_DEBUG_KMS("fallback: cloned configuration\n"); 390 DRM_DEBUG_KMS("fallback: cloned configuration\n");
397 fallback = true; 391 goto bail;
398 goto out;
399 } 392 }
400 } 393 }
401 394
@@ -466,8 +459,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
466 fallback = true; 459 fallback = true;
467 } 460 }
468 461
469out:
470 if (fallback) { 462 if (fallback) {
463bail:
471 DRM_DEBUG_KMS("Not using firmware configuration\n"); 464 DRM_DEBUG_KMS("Not using firmware configuration\n");
472 memcpy(enabled, save_enabled, dev->mode_config.num_connector); 465 memcpy(enabled, save_enabled, dev->mode_config.num_connector);
473 kfree(save_enabled); 466 kfree(save_enabled);
@@ -636,6 +629,15 @@ out:
636 return false; 629 return false;
637} 630}
638 631
632static void intel_fbdev_suspend_worker(struct work_struct *work)
633{
634 intel_fbdev_set_suspend(container_of(work,
635 struct drm_i915_private,
636 fbdev_suspend_work)->dev,
637 FBINFO_STATE_RUNNING,
638 true);
639}
640
639int intel_fbdev_init(struct drm_device *dev) 641int intel_fbdev_init(struct drm_device *dev)
640{ 642{
641 struct intel_fbdev *ifbdev; 643 struct intel_fbdev *ifbdev;
@@ -662,14 +664,16 @@ int intel_fbdev_init(struct drm_device *dev)
662 } 664 }
663 665
664 dev_priv->fbdev = ifbdev; 666 dev_priv->fbdev = ifbdev;
667 INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker);
668
665 drm_fb_helper_single_add_all_connectors(&ifbdev->helper); 669 drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
666 670
667 return 0; 671 return 0;
668} 672}
669 673
670void intel_fbdev_initial_config(struct drm_device *dev) 674void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
671{ 675{
672 struct drm_i915_private *dev_priv = dev->dev_private; 676 struct drm_i915_private *dev_priv = data;
673 struct intel_fbdev *ifbdev = dev_priv->fbdev; 677 struct intel_fbdev *ifbdev = dev_priv->fbdev;
674 678
675 /* Due to peculiar init order wrt to hpd handling this is separate. */ 679 /* Due to peculiar init order wrt to hpd handling this is separate. */
@@ -682,12 +686,15 @@ void intel_fbdev_fini(struct drm_device *dev)
682 if (!dev_priv->fbdev) 686 if (!dev_priv->fbdev)
683 return; 687 return;
684 688
689 flush_work(&dev_priv->fbdev_suspend_work);
690
691 async_synchronize_full();
685 intel_fbdev_destroy(dev, dev_priv->fbdev); 692 intel_fbdev_destroy(dev, dev_priv->fbdev);
686 kfree(dev_priv->fbdev); 693 kfree(dev_priv->fbdev);
687 dev_priv->fbdev = NULL; 694 dev_priv->fbdev = NULL;
688} 695}
689 696
690void intel_fbdev_set_suspend(struct drm_device *dev, int state) 697void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous)
691{ 698{
692 struct drm_i915_private *dev_priv = dev->dev_private; 699 struct drm_i915_private *dev_priv = dev->dev_private;
693 struct intel_fbdev *ifbdev = dev_priv->fbdev; 700 struct intel_fbdev *ifbdev = dev_priv->fbdev;
@@ -698,6 +705,33 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
698 705
699 info = ifbdev->helper.fbdev; 706 info = ifbdev->helper.fbdev;
700 707
708 if (synchronous) {
709 /* Flush any pending work to turn the console on, and then
710 * wait to turn it off. It must be synchronous as we are
711 * about to suspend or unload the driver.
712 *
713 * Note that from within the work-handler, we cannot flush
714 * ourselves, so only flush outstanding work upon suspend!
715 */
716 if (state != FBINFO_STATE_RUNNING)
717 flush_work(&dev_priv->fbdev_suspend_work);
718 console_lock();
719 } else {
720 /*
721 * The console lock can be pretty contented on resume due
722 * to all the printk activity. Try to keep it out of the hot
723 * path of resume if possible.
724 */
725 WARN_ON(state != FBINFO_STATE_RUNNING);
726 if (!console_trylock()) {
727 /* Don't block our own workqueue as this can
728 * be run in parallel with other i915.ko tasks.
729 */
730 schedule_work(&dev_priv->fbdev_suspend_work);
731 return;
732 }
733 }
734
701 /* On resume from hibernation: If the object is shmemfs backed, it has 735 /* On resume from hibernation: If the object is shmemfs backed, it has
702 * been restored from swap. If the object is stolen however, it will be 736 * been restored from swap. If the object is stolen however, it will be
703 * full of whatever garbage was left in there. 737 * full of whatever garbage was left in there.
@@ -706,6 +740,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
706 memset_io(info->screen_base, 0, info->screen_size); 740 memset_io(info->screen_base, 0, info->screen_size);
707 741
708 fb_set_suspend(info, state); 742 fb_set_suspend(info, state);
743 console_unlock();
709} 744}
710 745
711void intel_fbdev_output_poll_changed(struct drm_device *dev) 746void intel_fbdev_output_poll_changed(struct drm_device *dev)