diff options
author | Noralf Trønnes <noralf@tronnes.org> | 2017-12-15 12:51:17 -0500 |
---|---|---|
committer | Noralf Trønnes <noralf@tronnes.org> | 2017-12-20 08:52:22 -0500 |
commit | 48c9571c34b153abc1c4f2b431fa74490b671943 (patch) | |
tree | 26ae43819c573a3be597c208e3cb9853edd1de87 /drivers | |
parent | 95b0137f28a420ac02826e674286bc363dd7c196 (diff) |
drm/fb-helper: Add drm_fb_helper_defio_init()
Add helper for initializing fbdev deferred I/O.
The cleanup could have happened in drm_fb_helper_fini(), but that would
have required me to set fb_info->fbdefio to NULL in a couple of drivers
before they call _fini() to avoid double defio cleanup. The problem is
that one of those is vboxvideo which lives in Greg's staging tree.
So I put the cleanup in drm_fb_helper_fbdev_teardown(), not perfect
but not that bad either.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20171215175119.36181-6-noralf@tronnes.org
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 54 |
1 files changed, 53 insertions, 1 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index e3eb3c9a98e3..4a61e1aef41b 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -107,7 +107,8 @@ static DEFINE_MUTEX(kernel_fb_helper_lock); | |||
107 | * always run in process context since the fb_*() function could be running in | 107 | * always run in process context since the fb_*() function could be running in |
108 | * atomic context. If drm_fb_helper_deferred_io() is used as the deferred_io | 108 | * atomic context. If drm_fb_helper_deferred_io() is used as the deferred_io |
109 | * callback it will also schedule dirty_work with the damage collected from the | 109 | * callback it will also schedule dirty_work with the damage collected from the |
110 | * mmap page writes. | 110 | * mmap page writes. Drivers can use drm_fb_helper_defio_init() to setup |
111 | * deferred I/O (coupled with drm_fb_helper_fbdev_teardown()). | ||
111 | */ | 112 | */ |
112 | 113 | ||
113 | #define drm_fb_helper_for_each_connector(fbh, i__) \ | 114 | #define drm_fb_helper_for_each_connector(fbh, i__) \ |
@@ -1029,6 +1030,49 @@ void drm_fb_helper_deferred_io(struct fb_info *info, | |||
1029 | EXPORT_SYMBOL(drm_fb_helper_deferred_io); | 1030 | EXPORT_SYMBOL(drm_fb_helper_deferred_io); |
1030 | 1031 | ||
1031 | /** | 1032 | /** |
1033 | * drm_fb_helper_defio_init - fbdev deferred I/O initialization | ||
1034 | * @fb_helper: driver-allocated fbdev helper | ||
1035 | * | ||
1036 | * This function allocates &fb_deferred_io, sets callback to | ||
1037 | * drm_fb_helper_deferred_io(), delay to 50ms and calls fb_deferred_io_init(). | ||
1038 | * It should be called from the &drm_fb_helper_funcs->fb_probe callback. | ||
1039 | * drm_fb_helper_fbdev_teardown() cleans up deferred I/O. | ||
1040 | * | ||
1041 | * NOTE: A copy of &fb_ops is made and assigned to &info->fbops. This is done | ||
1042 | * because fb_deferred_io_cleanup() clears &fbops->fb_mmap and would thereby | ||
1043 | * affect other instances of that &fb_ops. | ||
1044 | * | ||
1045 | * Returns: | ||
1046 | * 0 on success or a negative error code on failure. | ||
1047 | */ | ||
1048 | int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper) | ||
1049 | { | ||
1050 | struct fb_info *info = fb_helper->fbdev; | ||
1051 | struct fb_deferred_io *fbdefio; | ||
1052 | struct fb_ops *fbops; | ||
1053 | |||
1054 | fbdefio = kzalloc(sizeof(*fbdefio), GFP_KERNEL); | ||
1055 | fbops = kzalloc(sizeof(*fbops), GFP_KERNEL); | ||
1056 | if (!fbdefio || !fbops) { | ||
1057 | kfree(fbdefio); | ||
1058 | kfree(fbops); | ||
1059 | return -ENOMEM; | ||
1060 | } | ||
1061 | |||
1062 | info->fbdefio = fbdefio; | ||
1063 | fbdefio->delay = msecs_to_jiffies(50); | ||
1064 | fbdefio->deferred_io = drm_fb_helper_deferred_io; | ||
1065 | |||
1066 | *fbops = *info->fbops; | ||
1067 | info->fbops = fbops; | ||
1068 | |||
1069 | fb_deferred_io_init(info); | ||
1070 | |||
1071 | return 0; | ||
1072 | } | ||
1073 | EXPORT_SYMBOL(drm_fb_helper_defio_init); | ||
1074 | |||
1075 | /** | ||
1032 | * drm_fb_helper_sys_read - wrapper around fb_sys_read | 1076 | * drm_fb_helper_sys_read - wrapper around fb_sys_read |
1033 | * @info: fb_info struct pointer | 1077 | * @info: fb_info struct pointer |
1034 | * @buf: userspace buffer to read from framebuffer memory | 1078 | * @buf: userspace buffer to read from framebuffer memory |
@@ -2824,6 +2868,7 @@ EXPORT_SYMBOL(drm_fb_helper_fbdev_setup); | |||
2824 | void drm_fb_helper_fbdev_teardown(struct drm_device *dev) | 2868 | void drm_fb_helper_fbdev_teardown(struct drm_device *dev) |
2825 | { | 2869 | { |
2826 | struct drm_fb_helper *fb_helper = dev->fb_helper; | 2870 | struct drm_fb_helper *fb_helper = dev->fb_helper; |
2871 | struct fb_ops *fbops = NULL; | ||
2827 | 2872 | ||
2828 | if (!fb_helper) | 2873 | if (!fb_helper) |
2829 | return; | 2874 | return; |
@@ -2832,7 +2877,14 @@ void drm_fb_helper_fbdev_teardown(struct drm_device *dev) | |||
2832 | if (fb_helper->fbdev && fb_helper->fbdev->dev) | 2877 | if (fb_helper->fbdev && fb_helper->fbdev->dev) |
2833 | drm_fb_helper_unregister_fbi(fb_helper); | 2878 | drm_fb_helper_unregister_fbi(fb_helper); |
2834 | 2879 | ||
2880 | if (fb_helper->fbdev && fb_helper->fbdev->fbdefio) { | ||
2881 | fb_deferred_io_cleanup(fb_helper->fbdev); | ||
2882 | kfree(fb_helper->fbdev->fbdefio); | ||
2883 | fbops = fb_helper->fbdev->fbops; | ||
2884 | } | ||
2885 | |||
2835 | drm_fb_helper_fini(fb_helper); | 2886 | drm_fb_helper_fini(fb_helper); |
2887 | kfree(fbops); | ||
2836 | 2888 | ||
2837 | if (fb_helper->fb) | 2889 | if (fb_helper->fb) |
2838 | drm_framebuffer_remove(fb_helper->fb); | 2890 | drm_framebuffer_remove(fb_helper->fb); |