24
24
* David Airlie
25
25
*/
26
26
27
- #include <linux/async.h>
28
27
#include <linux/console.h>
29
28
#include <linux/delay.h>
30
29
#include <linux/errno.h>
39
38
#include <linux/vga_switcheroo.h>
40
39
41
40
#include <drm/drm_crtc.h>
41
+ #include <drm/drm_crtc_helper.h>
42
42
#include <drm/drm_fb_helper.h>
43
43
#include <drm/drm_fourcc.h>
44
44
#include <drm/drm_gem_framebuffer_helper.h>
@@ -58,7 +58,6 @@ struct intel_fbdev {
58
58
struct intel_framebuffer * fb ;
59
59
struct i915_vma * vma ;
60
60
unsigned long vma_flags ;
61
- async_cookie_t cookie ;
62
61
int preferred_bpp ;
63
62
64
63
/* 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)
135
134
return i915_gem_fb_mmap (obj , vma );
136
135
}
137
136
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
+
138
157
__diag_push ();
139
158
__diag_ignore_all ("-Woverride-init" , "Allow field initialization overrides for fb ops" );
140
159
@@ -147,6 +166,7 @@ static const struct fb_ops intelfb_ops = {
147
166
.fb_pan_display = intel_fbdev_pan_display ,
148
167
__FB_DEFAULT_DEFERRED_OPS_DRAW (intel_fbdev ),
149
168
.fb_mmap = intel_fbdev_mmap ,
169
+ .fb_destroy = intel_fbdev_fb_destroy ,
150
170
};
151
171
152
172
__diag_pop ();
@@ -158,7 +178,6 @@ static int intelfb_create(struct drm_fb_helper *helper,
158
178
struct intel_framebuffer * intel_fb = ifbdev -> fb ;
159
179
struct drm_device * dev = helper -> dev ;
160
180
struct drm_i915_private * dev_priv = to_i915 (dev );
161
- struct pci_dev * pdev = to_pci_dev (dev_priv -> drm .dev );
162
181
const struct i915_gtt_view view = {
163
182
.type = I915_GTT_VIEW_NORMAL ,
164
183
};
@@ -250,7 +269,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
250
269
ifbdev -> vma_flags = flags ;
251
270
252
271
intel_runtime_pm_put (& dev_priv -> runtime_pm , wakeref );
253
- vga_switcheroo_client_fb_set ( pdev , info );
272
+
254
273
return 0 ;
255
274
256
275
out_unpin :
@@ -276,26 +295,6 @@ static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
276
295
.fb_dirty = intelfb_dirty ,
277
296
};
278
297
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
-
299
298
/*
300
299
* Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible.
301
300
* 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)
459
458
true);
460
459
}
461
460
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
-
472
461
/* Suspends/resumes fbdev processing of incoming HPD events. When resuming HPD
473
462
* processing, fbdev will perform a full connector reprobe if a hotplug event
474
463
* was received while HPD was suspended.
@@ -559,8 +548,6 @@ static int intel_fbdev_output_poll_changed(struct drm_device *dev)
559
548
if (!ifbdev )
560
549
return - EINVAL ;
561
550
562
- intel_fbdev_sync (ifbdev );
563
-
564
551
mutex_lock (& ifbdev -> hpd_lock );
565
552
send_hpd = !ifbdev -> hpd_suspended ;
566
553
ifbdev -> hpd_waiting = true;
@@ -580,7 +567,6 @@ static int intel_fbdev_restore_mode(struct drm_i915_private *dev_priv)
580
567
if (!ifbdev )
581
568
return - EINVAL ;
582
569
583
- intel_fbdev_sync (ifbdev );
584
570
if (!ifbdev -> vma )
585
571
return - ENOMEM ;
586
572
@@ -598,7 +584,20 @@ static int intel_fbdev_restore_mode(struct drm_i915_private *dev_priv)
598
584
*/
599
585
600
586
static 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
+ }
602
601
603
602
static int intel_fbdev_client_restore (struct drm_client_dev * client )
604
603
{
@@ -616,7 +615,31 @@ static int intel_fbdev_client_restore(struct drm_client_dev *client)
616
615
617
616
static int intel_fbdev_client_hotplug (struct drm_client_dev * client )
618
617
{
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 ;
620
643
}
621
644
622
645
static const struct drm_client_funcs intel_fbdev_client_funcs = {
@@ -626,91 +649,43 @@ static const struct drm_client_funcs intel_fbdev_client_funcs = {
626
649
.hotplug = intel_fbdev_client_hotplug ,
627
650
};
628
651
629
- int intel_fbdev_init (struct drm_device * dev )
652
+ void intel_fbdev_setup (struct drm_i915_private * i915 )
630
653
{
631
- struct drm_i915_private * dev_priv = to_i915 ( dev ) ;
654
+ struct drm_device * dev = & i915 -> drm ;
632
655
struct intel_fbdev * ifbdev ;
633
656
int ret ;
634
657
635
- if (drm_WARN_ON ( dev , !HAS_DISPLAY (dev_priv ) ))
636
- return - ENODEV ;
658
+ if (!HAS_DISPLAY (i915 ))
659
+ return ;
637
660
638
661
ifbdev = kzalloc (sizeof (* ifbdev ), GFP_KERNEL );
639
662
if (!ifbdev )
640
- return - ENOMEM ;
641
-
642
- mutex_init (& ifbdev -> hpd_lock );
663
+ return ;
643
664
drm_fb_helper_prepare (dev , & ifbdev -> helper , 32 , & intel_fb_helper_funcs );
644
665
666
+ i915 -> display .fbdev .fbdev = ifbdev ;
667
+ INIT_WORK (& i915 -> display .fbdev .suspend_work , intel_fbdev_suspend_worker );
668
+ mutex_init (& ifbdev -> hpd_lock );
645
669
if (intel_fbdev_init_bios (dev , ifbdev ))
646
670
ifbdev -> helper .preferred_bpp = ifbdev -> preferred_bpp ;
647
671
else
648
672
ifbdev -> preferred_bpp = ifbdev -> helper .preferred_bpp ;
649
673
650
674
ret = drm_client_init (dev , & ifbdev -> helper .client , "intel-fbdev" ,
651
675
& intel_fbdev_client_funcs );
652
- if (ret )
676
+ if (ret ) {
677
+ drm_err (dev , "Failed to register client: %d\n" , ret );
653
678
goto err_drm_fb_helper_unprepare ;
679
+ }
654
680
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 );
661
682
662
- return 0 ;
683
+ return ;
663
684
664
- err_drm_client_release :
665
- drm_client_release (& ifbdev -> helper .client );
666
685
err_drm_fb_helper_unprepare :
667
686
drm_fb_helper_unprepare (& ifbdev -> helper );
687
+ mutex_destroy (& ifbdev -> hpd_lock );
668
688
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 );
714
689
}
715
690
716
691
struct intel_framebuffer * intel_fbdev_framebuffer (struct intel_fbdev * fbdev )
0 commit comments