2424 * David Airlie
2525 */
2626
27- #include <linux/async.h>
2827#include <linux/console.h>
2928#include <linux/delay.h>
3029#include <linux/errno.h>
3938#include <linux/vga_switcheroo.h>
4039
4140#include <drm/drm_crtc.h>
41+ #include <drm/drm_crtc_helper.h>
4242#include <drm/drm_fb_helper.h>
4343#include <drm/drm_fourcc.h>
4444#include <drm/drm_gem_framebuffer_helper.h>
@@ -58,7 +58,6 @@ struct intel_fbdev {
5858 struct intel_framebuffer * fb ;
5959 struct i915_vma * vma ;
6060 unsigned long vma_flags ;
61- async_cookie_t cookie ;
6261 int preferred_bpp ;
6362
6463 /* Whether or not fbdev hpd processing is temporarily suspended */
@@ -135,6 +134,26 @@ static int intel_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma)
135134 return i915_gem_fb_mmap (obj , vma );
136135}
137136
137+ static void intel_fbdev_fb_destroy (struct fb_info * info )
138+ {
139+ struct drm_fb_helper * fb_helper = info -> par ;
140+ struct intel_fbdev * ifbdev = container_of (fb_helper , struct intel_fbdev , helper );
141+
142+ drm_fb_helper_fini (& ifbdev -> helper );
143+
144+ /*
145+ * We rely on the object-free to release the VMA pinning for
146+ * the info->screen_base mmaping. Leaking the VMA is simpler than
147+ * trying to rectify all the possible error paths leading here.
148+ */
149+ intel_unpin_fb_vma (ifbdev -> vma , ifbdev -> vma_flags );
150+ drm_framebuffer_remove (& ifbdev -> fb -> base );
151+
152+ drm_client_release (& fb_helper -> client );
153+ drm_fb_helper_unprepare (& ifbdev -> helper );
154+ kfree (ifbdev );
155+ }
156+
138157__diag_push ();
139158__diag_ignore_all ("-Woverride-init" , "Allow field initialization overrides for fb ops" );
140159
@@ -147,6 +166,7 @@ static const struct fb_ops intelfb_ops = {
147166 .fb_pan_display = intel_fbdev_pan_display ,
148167 __FB_DEFAULT_DEFERRED_OPS_DRAW (intel_fbdev ),
149168 .fb_mmap = intel_fbdev_mmap ,
169+ .fb_destroy = intel_fbdev_fb_destroy ,
150170};
151171
152172__diag_pop ();
@@ -158,7 +178,6 @@ static int intelfb_create(struct drm_fb_helper *helper,
158178 struct intel_framebuffer * intel_fb = ifbdev -> fb ;
159179 struct drm_device * dev = helper -> dev ;
160180 struct drm_i915_private * dev_priv = to_i915 (dev );
161- struct pci_dev * pdev = to_pci_dev (dev_priv -> drm .dev );
162181 const struct i915_gtt_view view = {
163182 .type = I915_GTT_VIEW_NORMAL ,
164183 };
@@ -250,7 +269,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
250269 ifbdev -> vma_flags = flags ;
251270
252271 intel_runtime_pm_put (& dev_priv -> runtime_pm , wakeref );
253- vga_switcheroo_client_fb_set ( pdev , info );
272+
254273 return 0 ;
255274
256275out_unpin :
@@ -276,26 +295,6 @@ static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
276295 .fb_dirty = intelfb_dirty ,
277296};
278297
279- static void intel_fbdev_destroy (struct intel_fbdev * ifbdev )
280- {
281- /* We rely on the object-free to release the VMA pinning for
282- * the info->screen_base mmaping. Leaking the VMA is simpler than
283- * trying to rectify all the possible error paths leading here.
284- */
285-
286- drm_fb_helper_fini (& ifbdev -> helper );
287-
288- if (ifbdev -> vma )
289- intel_unpin_fb_vma (ifbdev -> vma , ifbdev -> vma_flags );
290-
291- if (ifbdev -> fb )
292- drm_framebuffer_remove (& ifbdev -> fb -> base );
293-
294- drm_client_release (& ifbdev -> helper .client );
295- drm_fb_helper_unprepare (& ifbdev -> helper );
296- kfree (ifbdev );
297- }
298-
299298/*
300299 * Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible.
301300 * The core display code will have read out the current plane configuration,
@@ -459,16 +458,6 @@ static void intel_fbdev_suspend_worker(struct work_struct *work)
459458 true);
460459}
461460
462- static void intel_fbdev_sync (struct intel_fbdev * ifbdev )
463- {
464- if (!ifbdev -> cookie )
465- return ;
466-
467- /* Only serialises with all preceding async calls, hence +1 */
468- async_synchronize_cookie (ifbdev -> cookie + 1 );
469- ifbdev -> cookie = 0 ;
470- }
471-
472461/* Suspends/resumes fbdev processing of incoming HPD events. When resuming HPD
473462 * processing, fbdev will perform a full connector reprobe if a hotplug event
474463 * was received while HPD was suspended.
@@ -559,8 +548,6 @@ static int intel_fbdev_output_poll_changed(struct drm_device *dev)
559548 if (!ifbdev )
560549 return - EINVAL ;
561550
562- intel_fbdev_sync (ifbdev );
563-
564551 mutex_lock (& ifbdev -> hpd_lock );
565552 send_hpd = !ifbdev -> hpd_suspended ;
566553 ifbdev -> hpd_waiting = true;
@@ -580,7 +567,6 @@ static int intel_fbdev_restore_mode(struct drm_i915_private *dev_priv)
580567 if (!ifbdev )
581568 return - EINVAL ;
582569
583- intel_fbdev_sync (ifbdev );
584570 if (!ifbdev -> vma )
585571 return - ENOMEM ;
586572
@@ -598,7 +584,20 @@ static int intel_fbdev_restore_mode(struct drm_i915_private *dev_priv)
598584 */
599585
600586static void intel_fbdev_client_unregister (struct drm_client_dev * client )
601- { }
587+ {
588+ struct drm_fb_helper * fb_helper = drm_fb_helper_from_client (client );
589+ struct drm_device * dev = fb_helper -> dev ;
590+ struct pci_dev * pdev = to_pci_dev (dev -> dev );
591+
592+ if (fb_helper -> info ) {
593+ vga_switcheroo_client_fb_set (pdev , NULL );
594+ drm_fb_helper_unregister_info (fb_helper );
595+ } else {
596+ drm_fb_helper_unprepare (fb_helper );
597+ drm_client_release (& fb_helper -> client );
598+ kfree (fb_helper );
599+ }
600+ }
602601
603602static int intel_fbdev_client_restore (struct drm_client_dev * client )
604603{
@@ -616,7 +615,31 @@ static int intel_fbdev_client_restore(struct drm_client_dev *client)
616615
617616static int intel_fbdev_client_hotplug (struct drm_client_dev * client )
618617{
619- return intel_fbdev_output_poll_changed (client -> dev );
618+ struct drm_fb_helper * fb_helper = drm_fb_helper_from_client (client );
619+ struct drm_device * dev = client -> dev ;
620+ struct pci_dev * pdev = to_pci_dev (dev -> dev );
621+ int ret ;
622+
623+ if (dev -> fb_helper )
624+ return intel_fbdev_output_poll_changed (dev );
625+
626+ ret = drm_fb_helper_init (dev , fb_helper );
627+ if (ret )
628+ goto err_drm_err ;
629+
630+ ret = drm_fb_helper_initial_config (fb_helper );
631+ if (ret )
632+ goto err_drm_fb_helper_fini ;
633+
634+ vga_switcheroo_client_fb_set (pdev , fb_helper -> info );
635+
636+ return 0 ;
637+
638+ err_drm_fb_helper_fini :
639+ drm_fb_helper_fini (fb_helper );
640+ err_drm_err :
641+ drm_err (dev , "Failed to setup i915 fbdev emulation (ret=%d)\n" , ret );
642+ return ret ;
620643}
621644
622645static const struct drm_client_funcs intel_fbdev_client_funcs = {
@@ -626,91 +649,43 @@ static const struct drm_client_funcs intel_fbdev_client_funcs = {
626649 .hotplug = intel_fbdev_client_hotplug ,
627650};
628651
629- int intel_fbdev_init (struct drm_device * dev )
652+ void intel_fbdev_setup (struct drm_i915_private * i915 )
630653{
631- struct drm_i915_private * dev_priv = to_i915 ( dev ) ;
654+ struct drm_device * dev = & i915 -> drm ;
632655 struct intel_fbdev * ifbdev ;
633656 int ret ;
634657
635- if (drm_WARN_ON ( dev , !HAS_DISPLAY (dev_priv ) ))
636- return - ENODEV ;
658+ if (!HAS_DISPLAY (i915 ))
659+ return ;
637660
638661 ifbdev = kzalloc (sizeof (* ifbdev ), GFP_KERNEL );
639662 if (!ifbdev )
640- return - ENOMEM ;
641-
642- mutex_init (& ifbdev -> hpd_lock );
663+ return ;
643664 drm_fb_helper_prepare (dev , & ifbdev -> helper , 32 , & intel_fb_helper_funcs );
644665
666+ i915 -> display .fbdev .fbdev = ifbdev ;
667+ INIT_WORK (& i915 -> display .fbdev .suspend_work , intel_fbdev_suspend_worker );
668+ mutex_init (& ifbdev -> hpd_lock );
645669 if (intel_fbdev_init_bios (dev , ifbdev ))
646670 ifbdev -> helper .preferred_bpp = ifbdev -> preferred_bpp ;
647671 else
648672 ifbdev -> preferred_bpp = ifbdev -> helper .preferred_bpp ;
649673
650674 ret = drm_client_init (dev , & ifbdev -> helper .client , "intel-fbdev" ,
651675 & intel_fbdev_client_funcs );
652- if (ret )
676+ if (ret ) {
677+ drm_err (dev , "Failed to register client: %d\n" , ret );
653678 goto err_drm_fb_helper_unprepare ;
679+ }
654680
655- ret = drm_fb_helper_init (dev , & ifbdev -> helper );
656- if (ret )
657- goto err_drm_client_release ;
658-
659- dev_priv -> display .fbdev .fbdev = ifbdev ;
660- INIT_WORK (& dev_priv -> display .fbdev .suspend_work , intel_fbdev_suspend_worker );
681+ drm_client_register (& ifbdev -> helper .client );
661682
662- return 0 ;
683+ return ;
663684
664- err_drm_client_release :
665- drm_client_release (& ifbdev -> helper .client );
666685err_drm_fb_helper_unprepare :
667686 drm_fb_helper_unprepare (& ifbdev -> helper );
687+ mutex_destroy (& ifbdev -> hpd_lock );
668688 kfree (ifbdev );
669- return ret ;
670- }
671-
672- static void intel_fbdev_initial_config (void * data , async_cookie_t cookie )
673- {
674- struct intel_fbdev * ifbdev = data ;
675-
676- /* Due to peculiar init order wrt to hpd handling this is separate. */
677- if (drm_fb_helper_initial_config (& ifbdev -> helper ))
678- intel_fbdev_unregister (to_i915 (ifbdev -> helper .dev ));
679- }
680-
681- void intel_fbdev_initial_config_async (struct drm_i915_private * dev_priv )
682- {
683- struct intel_fbdev * ifbdev = dev_priv -> display .fbdev .fbdev ;
684-
685- if (!ifbdev )
686- return ;
687-
688- ifbdev -> cookie = async_schedule (intel_fbdev_initial_config , ifbdev );
689- }
690-
691- void intel_fbdev_unregister (struct drm_i915_private * dev_priv )
692- {
693- struct intel_fbdev * ifbdev = dev_priv -> display .fbdev .fbdev ;
694-
695- if (!ifbdev )
696- return ;
697-
698- intel_fbdev_set_suspend (& dev_priv -> drm , FBINFO_STATE_SUSPENDED , true);
699-
700- if (!current_is_async ())
701- intel_fbdev_sync (ifbdev );
702-
703- drm_fb_helper_unregister_info (& ifbdev -> helper );
704- }
705-
706- void intel_fbdev_fini (struct drm_i915_private * dev_priv )
707- {
708- struct intel_fbdev * ifbdev = fetch_and_zero (& dev_priv -> display .fbdev .fbdev );
709-
710- if (!ifbdev )
711- return ;
712-
713- intel_fbdev_destroy (ifbdev );
714689}
715690
716691struct intel_framebuffer * intel_fbdev_framebuffer (struct intel_fbdev * fbdev )
0 commit comments