@@ -84,6 +84,15 @@ static LIST_HEAD(kernel_fb_helper_list);
84
84
* and set up an initial configuration using the detected hardware, drivers
85
85
* should call drm_fb_helper_single_add_all_connectors() followed by
86
86
* drm_fb_helper_initial_config().
87
+ *
88
+ * If CONFIG_FB_DEFERRED_IO is enabled and &drm_framebuffer_funcs ->dirty is
89
+ * set, the drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit}
90
+ * functions will accumulate changes and schedule &fb_helper .dirty_work to run
91
+ * right away. This worker then calls the dirty() function ensuring that it
92
+ * will always run in process context since the fb_*() function could be
93
+ * running in atomic context. If drm_fb_helper_deferred_io() is used as the
94
+ * deferred_io callback it will also schedule dirty_work with the damage
95
+ * collected from the mmap page writes.
87
96
*/
88
97
89
98
/**
@@ -637,6 +646,23 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
637
646
kfree (helper -> crtc_info );
638
647
}
639
648
649
+ static void drm_fb_helper_dirty_work (struct work_struct * work )
650
+ {
651
+ struct drm_fb_helper * helper = container_of (work , struct drm_fb_helper ,
652
+ dirty_work );
653
+ struct drm_clip_rect * clip = & helper -> dirty_clip ;
654
+ struct drm_clip_rect clip_copy ;
655
+ unsigned long flags ;
656
+
657
+ spin_lock_irqsave (& helper -> dirty_lock , flags );
658
+ clip_copy = * clip ;
659
+ clip -> x1 = clip -> y1 = ~0 ;
660
+ clip -> x2 = clip -> y2 = 0 ;
661
+ spin_unlock_irqrestore (& helper -> dirty_lock , flags );
662
+
663
+ helper -> fb -> funcs -> dirty (helper -> fb , NULL , 0 , 0 , & clip_copy , 1 );
664
+ }
665
+
640
666
/**
641
667
* drm_fb_helper_prepare - setup a drm_fb_helper structure
642
668
* @dev: DRM device
@@ -650,6 +676,9 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
650
676
const struct drm_fb_helper_funcs * funcs )
651
677
{
652
678
INIT_LIST_HEAD (& helper -> kernel_fb_list );
679
+ spin_lock_init (& helper -> dirty_lock );
680
+ INIT_WORK (& helper -> dirty_work , drm_fb_helper_dirty_work );
681
+ helper -> dirty_clip .x1 = helper -> dirty_clip .y1 = ~0 ;
653
682
helper -> funcs = funcs ;
654
683
helper -> dev = dev ;
655
684
}
@@ -834,6 +863,59 @@ void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
834
863
}
835
864
EXPORT_SYMBOL (drm_fb_helper_unlink_fbi );
836
865
866
+ static void drm_fb_helper_dirty (struct fb_info * info , u32 x , u32 y ,
867
+ u32 width , u32 height )
868
+ {
869
+ struct drm_fb_helper * helper = info -> par ;
870
+ struct drm_clip_rect * clip = & helper -> dirty_clip ;
871
+ unsigned long flags ;
872
+
873
+ if (!helper -> fb -> funcs -> dirty )
874
+ return ;
875
+
876
+ spin_lock_irqsave (& helper -> dirty_lock , flags );
877
+ clip -> x1 = min_t (u32 , clip -> x1 , x );
878
+ clip -> y1 = min_t (u32 , clip -> y1 , y );
879
+ clip -> x2 = max_t (u32 , clip -> x2 , x + width );
880
+ clip -> y2 = max_t (u32 , clip -> y2 , y + height );
881
+ spin_unlock_irqrestore (& helper -> dirty_lock , flags );
882
+
883
+ schedule_work (& helper -> dirty_work );
884
+ }
885
+
886
+ /**
887
+ * drm_fb_helper_deferred_io() - fbdev deferred_io callback function
888
+ * @info: fb_info struct pointer
889
+ * @pagelist: list of dirty mmap framebuffer pages
890
+ *
891
+ * This function is used as the &fb_deferred_io ->deferred_io
892
+ * callback function for flushing the fbdev mmap writes.
893
+ */
894
+ void drm_fb_helper_deferred_io (struct fb_info * info ,
895
+ struct list_head * pagelist )
896
+ {
897
+ unsigned long start , end , min , max ;
898
+ struct page * page ;
899
+ u32 y1 , y2 ;
900
+
901
+ min = ULONG_MAX ;
902
+ max = 0 ;
903
+ list_for_each_entry (page , pagelist , lru ) {
904
+ start = page -> index << PAGE_SHIFT ;
905
+ end = start + PAGE_SIZE - 1 ;
906
+ min = min (min , start );
907
+ max = max (max , end );
908
+ }
909
+
910
+ if (min < max ) {
911
+ y1 = min / info -> fix .line_length ;
912
+ y2 = min_t (u32 , DIV_ROUND_UP (max , info -> fix .line_length ),
913
+ info -> var .yres );
914
+ drm_fb_helper_dirty (info , 0 , y1 , info -> var .xres , y2 - y1 );
915
+ }
916
+ }
917
+ EXPORT_SYMBOL (drm_fb_helper_deferred_io );
918
+
837
919
/**
838
920
* drm_fb_helper_sys_read - wrapper around fb_sys_read
839
921
* @info: fb_info struct pointer
@@ -862,7 +944,14 @@ EXPORT_SYMBOL(drm_fb_helper_sys_read);
862
944
ssize_t drm_fb_helper_sys_write (struct fb_info * info , const char __user * buf ,
863
945
size_t count , loff_t * ppos )
864
946
{
865
- return fb_sys_write (info , buf , count , ppos );
947
+ ssize_t ret ;
948
+
949
+ ret = fb_sys_write (info , buf , count , ppos );
950
+ if (ret > 0 )
951
+ drm_fb_helper_dirty (info , 0 , 0 , info -> var .xres ,
952
+ info -> var .yres );
953
+
954
+ return ret ;
866
955
}
867
956
EXPORT_SYMBOL (drm_fb_helper_sys_write );
868
957
@@ -877,6 +966,8 @@ void drm_fb_helper_sys_fillrect(struct fb_info *info,
877
966
const struct fb_fillrect * rect )
878
967
{
879
968
sys_fillrect (info , rect );
969
+ drm_fb_helper_dirty (info , rect -> dx , rect -> dy ,
970
+ rect -> width , rect -> height );
880
971
}
881
972
EXPORT_SYMBOL (drm_fb_helper_sys_fillrect );
882
973
@@ -891,6 +982,8 @@ void drm_fb_helper_sys_copyarea(struct fb_info *info,
891
982
const struct fb_copyarea * area )
892
983
{
893
984
sys_copyarea (info , area );
985
+ drm_fb_helper_dirty (info , area -> dx , area -> dy ,
986
+ area -> width , area -> height );
894
987
}
895
988
EXPORT_SYMBOL (drm_fb_helper_sys_copyarea );
896
989
@@ -905,6 +998,8 @@ void drm_fb_helper_sys_imageblit(struct fb_info *info,
905
998
const struct fb_image * image )
906
999
{
907
1000
sys_imageblit (info , image );
1001
+ drm_fb_helper_dirty (info , image -> dx , image -> dy ,
1002
+ image -> width , image -> height );
908
1003
}
909
1004
EXPORT_SYMBOL (drm_fb_helper_sys_imageblit );
910
1005
@@ -919,6 +1014,8 @@ void drm_fb_helper_cfb_fillrect(struct fb_info *info,
919
1014
const struct fb_fillrect * rect )
920
1015
{
921
1016
cfb_fillrect (info , rect );
1017
+ drm_fb_helper_dirty (info , rect -> dx , rect -> dy ,
1018
+ rect -> width , rect -> height );
922
1019
}
923
1020
EXPORT_SYMBOL (drm_fb_helper_cfb_fillrect );
924
1021
@@ -933,6 +1030,8 @@ void drm_fb_helper_cfb_copyarea(struct fb_info *info,
933
1030
const struct fb_copyarea * area )
934
1031
{
935
1032
cfb_copyarea (info , area );
1033
+ drm_fb_helper_dirty (info , area -> dx , area -> dy ,
1034
+ area -> width , area -> height );
936
1035
}
937
1036
EXPORT_SYMBOL (drm_fb_helper_cfb_copyarea );
938
1037
@@ -947,6 +1046,8 @@ void drm_fb_helper_cfb_imageblit(struct fb_info *info,
947
1046
const struct fb_image * image )
948
1047
{
949
1048
cfb_imageblit (info , image );
1049
+ drm_fb_helper_dirty (info , image -> dx , image -> dy ,
1050
+ image -> width , image -> height );
950
1051
}
951
1052
EXPORT_SYMBOL (drm_fb_helper_cfb_imageblit );
952
1053
0 commit comments