Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/fb-helper: Perform all fbdev I/O with the same implementation

Implement the fbdev's read/write helpers with the same functions. Use
the generic fbdev's code as template. Convert all drivers.

DRM's fb helpers must implement regular I/O functionality in struct
fb_ops and possibly perform a damage update. Handle all this in the
same functions and convert drivers. The functionality has been used
as part of the generic fbdev code for some time. The drivers don't
set struct drm_fb_helper.fb_dirty, so they will not be affected by
damage handling.

For I/O memory, fb helpers now provide drm_fb_helper_cfb_read() and
drm_fb_helper_cfb_write(). Several drivers require these. Until now
tegra used I/O read and write, although the memory buffer appears to
be in system memory. So use _sys_ helpers now.

v3:
* fix docs (Javier)
v2:
* rebase onto vmwgfx changes

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20221103151446.2638-18-tzimmermann@suse.de

+254 -158
+2
drivers/gpu/drm/armada/armada_fbdev.c
··· 19 19 static const struct fb_ops armada_fb_ops = { 20 20 .owner = THIS_MODULE, 21 21 DRM_FB_HELPER_DEFAULT_OPS, 22 + .fb_read = drm_fb_helper_cfb_read, 23 + .fb_write = drm_fb_helper_cfb_write, 22 24 .fb_fillrect = drm_fb_helper_cfb_fillrect, 23 25 .fb_copyarea = drm_fb_helper_cfb_copyarea, 24 26 .fb_imageblit = drm_fb_helper_cfb_imageblit,
+225 -158
drivers/gpu/drm/drm_fb_helper.c
··· 747 747 } 748 748 EXPORT_SYMBOL(drm_fb_helper_deferred_io); 749 749 750 + typedef ssize_t (*drm_fb_helper_read_screen)(struct fb_info *info, char __user *buf, 751 + size_t count, loff_t pos); 752 + 753 + static ssize_t __drm_fb_helper_read(struct fb_info *info, char __user *buf, size_t count, 754 + loff_t *ppos, drm_fb_helper_read_screen read_screen) 755 + { 756 + loff_t pos = *ppos; 757 + size_t total_size; 758 + ssize_t ret; 759 + 760 + if (info->screen_size) 761 + total_size = info->screen_size; 762 + else 763 + total_size = info->fix.smem_len; 764 + 765 + if (pos >= total_size) 766 + return 0; 767 + if (count >= total_size) 768 + count = total_size; 769 + if (total_size - count < pos) 770 + count = total_size - pos; 771 + 772 + if (info->fbops->fb_sync) 773 + info->fbops->fb_sync(info); 774 + 775 + ret = read_screen(info, buf, count, pos); 776 + if (ret > 0) 777 + *ppos += ret; 778 + 779 + return ret; 780 + } 781 + 782 + typedef ssize_t (*drm_fb_helper_write_screen)(struct fb_info *info, const char __user *buf, 783 + size_t count, loff_t pos); 784 + 785 + static ssize_t __drm_fb_helper_write(struct fb_info *info, const char __user *buf, size_t count, 786 + loff_t *ppos, drm_fb_helper_write_screen write_screen) 787 + { 788 + loff_t pos = *ppos; 789 + size_t total_size; 790 + ssize_t ret; 791 + int err = 0; 792 + 793 + if (info->screen_size) 794 + total_size = info->screen_size; 795 + else 796 + total_size = info->fix.smem_len; 797 + 798 + if (pos > total_size) 799 + return -EFBIG; 800 + if (count > total_size) { 801 + err = -EFBIG; 802 + count = total_size; 803 + } 804 + if (total_size - count < pos) { 805 + if (!err) 806 + err = -ENOSPC; 807 + count = total_size - pos; 808 + } 809 + 810 + if (info->fbops->fb_sync) 811 + info->fbops->fb_sync(info); 812 + 813 + /* 814 + * Copy to framebuffer even if we already logged an error. Emulates 815 + * the behavior of the original fbdev implementation. 816 + */ 817 + ret = write_screen(info, buf, count, pos); 818 + if (ret < 0) 819 + return ret; /* return last error, if any */ 820 + else if (!ret) 821 + return err; /* return previous error, if any */ 822 + 823 + *ppos += ret; 824 + 825 + return ret; 826 + } 827 + 828 + static ssize_t drm_fb_helper_read_screen_buffer(struct fb_info *info, char __user *buf, 829 + size_t count, loff_t pos) 830 + { 831 + const char *src = info->screen_buffer + pos; 832 + 833 + if (copy_to_user(buf, src, count)) 834 + return -EFAULT; 835 + 836 + return count; 837 + } 838 + 750 839 /** 751 - * drm_fb_helper_sys_read - wrapper around fb_sys_read 840 + * drm_fb_helper_sys_read - Implements struct &fb_ops.fb_read for system memory 752 841 * @info: fb_info struct pointer 753 842 * @buf: userspace buffer to read from framebuffer memory 754 843 * @count: number of bytes to read from framebuffer memory 755 844 * @ppos: read offset within framebuffer memory 756 845 * 757 - * A wrapper around fb_sys_read implemented by fbdev core 846 + * Returns: 847 + * The number of bytes read on success, or an error code otherwise. 758 848 */ 759 849 ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, 760 850 size_t count, loff_t *ppos) 761 851 { 762 - return fb_sys_read(info, buf, count, ppos); 852 + return __drm_fb_helper_read(info, buf, count, ppos, drm_fb_helper_read_screen_buffer); 763 853 } 764 854 EXPORT_SYMBOL(drm_fb_helper_sys_read); 765 855 856 + static ssize_t drm_fb_helper_write_screen_buffer(struct fb_info *info, const char __user *buf, 857 + size_t count, loff_t pos) 858 + { 859 + char *dst = info->screen_buffer + pos; 860 + 861 + if (copy_from_user(dst, buf, count)) 862 + return -EFAULT; 863 + 864 + return count; 865 + } 866 + 766 867 /** 767 - * drm_fb_helper_sys_write - wrapper around fb_sys_write 868 + * drm_fb_helper_sys_write - Implements struct &fb_ops.fb_write for system memory 768 869 * @info: fb_info struct pointer 769 870 * @buf: userspace buffer to write to framebuffer memory 770 871 * @count: number of bytes to write to framebuffer memory 771 872 * @ppos: write offset within framebuffer memory 772 873 * 773 - * A wrapper around fb_sys_write implemented by fbdev core 874 + * Returns: 875 + * The number of bytes written on success, or an error code otherwise. 774 876 */ 775 877 ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf, 776 878 size_t count, loff_t *ppos) ··· 881 779 ssize_t ret; 882 780 struct drm_rect damage_area; 883 781 884 - ret = fb_sys_write(info, buf, count, ppos); 782 + ret = __drm_fb_helper_write(info, buf, count, ppos, drm_fb_helper_write_screen_buffer); 885 783 if (ret <= 0) 886 784 return ret; 887 785 ··· 938 836 drm_fb_helper_damage(info, image->dx, image->dy, image->width, image->height); 939 837 } 940 838 EXPORT_SYMBOL(drm_fb_helper_sys_imageblit); 839 + 840 + static ssize_t fb_read_screen_base(struct fb_info *info, char __user *buf, size_t count, 841 + loff_t pos) 842 + { 843 + const char __iomem *src = info->screen_base + pos; 844 + size_t alloc_size = min_t(size_t, count, PAGE_SIZE); 845 + ssize_t ret = 0; 846 + int err = 0; 847 + char *tmp; 848 + 849 + tmp = kmalloc(alloc_size, GFP_KERNEL); 850 + if (!tmp) 851 + return -ENOMEM; 852 + 853 + while (count) { 854 + size_t c = min_t(size_t, count, alloc_size); 855 + 856 + memcpy_fromio(tmp, src, c); 857 + if (copy_to_user(buf, tmp, c)) { 858 + err = -EFAULT; 859 + break; 860 + } 861 + 862 + src += c; 863 + buf += c; 864 + ret += c; 865 + count -= c; 866 + } 867 + 868 + kfree(tmp); 869 + 870 + return ret ? ret : err; 871 + } 872 + 873 + /** 874 + * drm_fb_helper_cfb_read - Implements struct &fb_ops.fb_read for I/O memory 875 + * @info: fb_info struct pointer 876 + * @buf: userspace buffer to read from framebuffer memory 877 + * @count: number of bytes to read from framebuffer memory 878 + * @ppos: read offset within framebuffer memory 879 + * 880 + * Returns: 881 + * The number of bytes read on success, or an error code otherwise. 882 + */ 883 + ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf, 884 + size_t count, loff_t *ppos) 885 + { 886 + return __drm_fb_helper_read(info, buf, count, ppos, fb_read_screen_base); 887 + } 888 + EXPORT_SYMBOL(drm_fb_helper_cfb_read); 889 + 890 + static ssize_t fb_write_screen_base(struct fb_info *info, const char __user *buf, size_t count, 891 + loff_t pos) 892 + { 893 + char __iomem *dst = info->screen_base + pos; 894 + size_t alloc_size = min_t(size_t, count, PAGE_SIZE); 895 + ssize_t ret = 0; 896 + int err = 0; 897 + u8 *tmp; 898 + 899 + tmp = kmalloc(alloc_size, GFP_KERNEL); 900 + if (!tmp) 901 + return -ENOMEM; 902 + 903 + while (count) { 904 + size_t c = min_t(size_t, count, alloc_size); 905 + 906 + if (copy_from_user(tmp, buf, c)) { 907 + err = -EFAULT; 908 + break; 909 + } 910 + memcpy_toio(dst, tmp, c); 911 + 912 + dst += c; 913 + buf += c; 914 + ret += c; 915 + count -= c; 916 + } 917 + 918 + kfree(tmp); 919 + 920 + return ret ? ret : err; 921 + } 922 + 923 + /** 924 + * drm_fb_helper_cfb_write - Implements struct &fb_ops.fb_write for I/O memory 925 + * @info: fb_info struct pointer 926 + * @buf: userspace buffer to write to framebuffer memory 927 + * @count: number of bytes to write to framebuffer memory 928 + * @ppos: write offset within framebuffer memory 929 + * 930 + * Returns: 931 + * The number of bytes written on success, or an error code otherwise. 932 + */ 933 + ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf, 934 + size_t count, loff_t *ppos) 935 + { 936 + loff_t pos = *ppos; 937 + ssize_t ret; 938 + struct drm_rect damage_area; 939 + 940 + ret = __drm_fb_helper_write(info, buf, count, ppos, fb_write_screen_base); 941 + if (ret <= 0) 942 + return ret; 943 + 944 + drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area); 945 + drm_fb_helper_damage(info, damage_area.x1, damage_area.y1, 946 + drm_rect_width(&damage_area), 947 + drm_rect_height(&damage_area)); 948 + 949 + return ret; 950 + } 951 + EXPORT_SYMBOL(drm_fb_helper_cfb_write); 941 952 942 953 /** 943 954 * drm_fb_helper_cfb_fillrect - wrapper around cfb_fillrect ··· 2398 2183 return !drm_fbdev_use_shadow_fb(fb_helper) && buffer->map.is_iomem; 2399 2184 } 2400 2185 2401 - static ssize_t fb_read_screen_base(struct fb_info *info, char __user *buf, size_t count, 2402 - loff_t pos) 2403 - { 2404 - const char __iomem *src = info->screen_base + pos; 2405 - size_t alloc_size = min_t(size_t, count, PAGE_SIZE); 2406 - ssize_t ret = 0; 2407 - int err = 0; 2408 - char *tmp; 2409 - 2410 - tmp = kmalloc(alloc_size, GFP_KERNEL); 2411 - if (!tmp) 2412 - return -ENOMEM; 2413 - 2414 - while (count) { 2415 - size_t c = min_t(size_t, count, alloc_size); 2416 - 2417 - memcpy_fromio(tmp, src, c); 2418 - if (copy_to_user(buf, tmp, c)) { 2419 - err = -EFAULT; 2420 - break; 2421 - } 2422 - 2423 - src += c; 2424 - buf += c; 2425 - ret += c; 2426 - count -= c; 2427 - } 2428 - 2429 - kfree(tmp); 2430 - 2431 - return ret ? ret : err; 2432 - } 2433 - 2434 - static ssize_t fb_read_screen_buffer(struct fb_info *info, char __user *buf, size_t count, 2435 - loff_t pos) 2436 - { 2437 - const char *src = info->screen_buffer + pos; 2438 - 2439 - if (copy_to_user(buf, src, count)) 2440 - return -EFAULT; 2441 - 2442 - return count; 2443 - } 2444 - 2445 2186 static ssize_t drm_fbdev_fb_read(struct fb_info *info, char __user *buf, 2446 2187 size_t count, loff_t *ppos) 2447 2188 { 2448 - loff_t pos = *ppos; 2449 - size_t total_size; 2450 2189 ssize_t ret; 2451 2190 2452 - if (info->screen_size) 2453 - total_size = info->screen_size; 2454 - else 2455 - total_size = info->fix.smem_len; 2456 - 2457 - if (pos >= total_size) 2458 - return 0; 2459 - if (count >= total_size) 2460 - count = total_size; 2461 - if (total_size - count < pos) 2462 - count = total_size - pos; 2463 - 2464 - if (info->fbops->fb_sync) 2465 - info->fbops->fb_sync(info); 2466 - 2467 2191 if (drm_fbdev_use_iomem(info)) 2468 - ret = fb_read_screen_base(info, buf, count, pos); 2192 + ret = drm_fb_helper_cfb_read(info, buf, count, ppos); 2469 2193 else 2470 - ret = fb_read_screen_buffer(info, buf, count, pos); 2471 - 2472 - if (ret > 0) 2473 - *ppos += ret; 2194 + ret = drm_fb_helper_sys_read(info, buf, count, ppos); 2474 2195 2475 2196 return ret; 2476 - } 2477 - 2478 - static ssize_t fb_write_screen_base(struct fb_info *info, const char __user *buf, size_t count, 2479 - loff_t pos) 2480 - { 2481 - char __iomem *dst = info->screen_base + pos; 2482 - size_t alloc_size = min_t(size_t, count, PAGE_SIZE); 2483 - ssize_t ret = 0; 2484 - int err = 0; 2485 - u8 *tmp; 2486 - 2487 - tmp = kmalloc(alloc_size, GFP_KERNEL); 2488 - if (!tmp) 2489 - return -ENOMEM; 2490 - 2491 - while (count) { 2492 - size_t c = min_t(size_t, count, alloc_size); 2493 - 2494 - if (copy_from_user(tmp, buf, c)) { 2495 - err = -EFAULT; 2496 - break; 2497 - } 2498 - memcpy_toio(dst, tmp, c); 2499 - 2500 - dst += c; 2501 - buf += c; 2502 - ret += c; 2503 - count -= c; 2504 - } 2505 - 2506 - kfree(tmp); 2507 - 2508 - return ret ? ret : err; 2509 - } 2510 - 2511 - static ssize_t fb_write_screen_buffer(struct fb_info *info, const char __user *buf, size_t count, 2512 - loff_t pos) 2513 - { 2514 - char *dst = info->screen_buffer + pos; 2515 - 2516 - if (copy_from_user(dst, buf, count)) 2517 - return -EFAULT; 2518 - 2519 - return count; 2520 2197 } 2521 2198 2522 2199 static ssize_t drm_fbdev_fb_write(struct fb_info *info, const char __user *buf, 2523 2200 size_t count, loff_t *ppos) 2524 2201 { 2525 - loff_t pos = *ppos; 2526 - size_t total_size; 2527 2202 ssize_t ret; 2528 - struct drm_rect damage_area; 2529 - int err = 0; 2530 2203 2531 - if (info->screen_size) 2532 - total_size = info->screen_size; 2533 - else 2534 - total_size = info->fix.smem_len; 2535 - 2536 - if (pos > total_size) 2537 - return -EFBIG; 2538 - if (count > total_size) { 2539 - err = -EFBIG; 2540 - count = total_size; 2541 - } 2542 - if (total_size - count < pos) { 2543 - if (!err) 2544 - err = -ENOSPC; 2545 - count = total_size - pos; 2546 - } 2547 - 2548 - if (info->fbops->fb_sync) 2549 - info->fbops->fb_sync(info); 2550 - 2551 - /* 2552 - * Copy to framebuffer even if we already logged an error. Emulates 2553 - * the behavior of the original fbdev implementation. 2554 - */ 2555 2204 if (drm_fbdev_use_iomem(info)) 2556 - ret = fb_write_screen_base(info, buf, count, pos); 2205 + ret = drm_fb_helper_cfb_write(info, buf, count, ppos); 2557 2206 else 2558 - ret = fb_write_screen_buffer(info, buf, count, pos); 2559 - 2560 - if (ret < 0) 2561 - return ret; /* return last error, if any */ 2562 - else if (!ret) 2563 - return err; /* return previous error, if any */ 2564 - 2565 - *ppos += ret; 2566 - 2567 - drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area); 2568 - drm_fb_helper_damage(info, damage_area.x1, damage_area.y1, 2569 - drm_rect_width(&damage_area), 2570 - drm_rect_height(&damage_area)); 2207 + ret = drm_fb_helper_sys_write(info, buf, count, ppos); 2571 2208 2572 2209 return ret; 2573 2210 }
+2
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
··· 49 49 .owner = THIS_MODULE, 50 50 DRM_FB_HELPER_DEFAULT_OPS, 51 51 .fb_mmap = exynos_drm_fb_mmap, 52 + .fb_read = drm_fb_helper_cfb_read, 53 + .fb_write = drm_fb_helper_cfb_write, 52 54 .fb_fillrect = drm_fb_helper_cfb_fillrect, 53 55 .fb_copyarea = drm_fb_helper_cfb_copyarea, 54 56 .fb_imageblit = drm_fb_helper_cfb_imageblit,
+2
drivers/gpu/drm/gma500/framebuffer.c
··· 147 147 .owner = THIS_MODULE, 148 148 DRM_FB_HELPER_DEFAULT_OPS, 149 149 .fb_setcolreg = psbfb_setcolreg, 150 + .fb_read = drm_fb_helper_cfb_read, 151 + .fb_write = drm_fb_helper_cfb_write, 150 152 .fb_fillrect = drm_fb_helper_cfb_fillrect, 151 153 .fb_copyarea = drm_fb_helper_cfb_copyarea, 152 154 .fb_imageblit = drm_fb_helper_cfb_imageblit,
+2
drivers/gpu/drm/i915/display/intel_fbdev.c
··· 124 124 .owner = THIS_MODULE, 125 125 DRM_FB_HELPER_DEFAULT_OPS, 126 126 .fb_set_par = intel_fbdev_set_par, 127 + .fb_read = drm_fb_helper_cfb_read, 128 + .fb_write = drm_fb_helper_cfb_write, 127 129 .fb_fillrect = drm_fb_helper_cfb_fillrect, 128 130 .fb_copyarea = drm_fb_helper_cfb_copyarea, 129 131 .fb_imageblit = drm_fb_helper_cfb_imageblit,
+2
drivers/gpu/drm/radeon/radeon_fb.c
··· 80 80 DRM_FB_HELPER_DEFAULT_OPS, 81 81 .fb_open = radeonfb_open, 82 82 .fb_release = radeonfb_release, 83 + .fb_read = drm_fb_helper_cfb_read, 84 + .fb_write = drm_fb_helper_cfb_write, 83 85 .fb_fillrect = drm_fb_helper_cfb_fillrect, 84 86 .fb_copyarea = drm_fb_helper_cfb_copyarea, 85 87 .fb_imageblit = drm_fb_helper_cfb_imageblit,
+2
drivers/gpu/drm/tegra/fb.c
··· 206 206 static const struct fb_ops tegra_fb_ops = { 207 207 .owner = THIS_MODULE, 208 208 DRM_FB_HELPER_DEFAULT_OPS, 209 + .fb_read = drm_fb_helper_sys_read, 210 + .fb_write = drm_fb_helper_sys_write, 209 211 .fb_fillrect = drm_fb_helper_sys_fillrect, 210 212 .fb_copyarea = drm_fb_helper_sys_copyarea, 211 213 .fb_imageblit = drm_fb_helper_sys_imageblit,
+17
include/drm/drm_fb_helper.h
··· 257 257 void drm_fb_helper_sys_imageblit(struct fb_info *info, 258 258 const struct fb_image *image); 259 259 260 + ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf, 261 + size_t count, loff_t *ppos); 262 + ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf, 263 + size_t count, loff_t *ppos); 264 + 260 265 void drm_fb_helper_cfb_fillrect(struct fb_info *info, 261 266 const struct fb_fillrect *rect); 262 267 void drm_fb_helper_cfb_copyarea(struct fb_info *info, ··· 405 400 static inline void drm_fb_helper_sys_imageblit(struct fb_info *info, 406 401 const struct fb_image *image) 407 402 { 403 + } 404 + 405 + static inline ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf, 406 + size_t count, loff_t *ppos) 407 + { 408 + return -ENODEV; 409 + } 410 + 411 + static inline ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf, 412 + size_t count, loff_t *ppos) 413 + { 414 + return -ENODEV; 408 415 } 409 416 410 417 static inline void drm_fb_helper_cfb_fillrect(struct fb_info *info,