diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0040-fbdev-add-FBIOCOPYAREA-ioctl.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.4/950-0040-fbdev-add-FBIOCOPYAREA-ioctl.patch | 327 |
1 files changed, 0 insertions, 327 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0040-fbdev-add-FBIOCOPYAREA-ioctl.patch b/target/linux/bcm27xx/patches-5.4/950-0040-fbdev-add-FBIOCOPYAREA-ioctl.patch deleted file mode 100644 index 23d6cd3139..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0040-fbdev-add-FBIOCOPYAREA-ioctl.patch +++ /dev/null @@ -1,327 +0,0 @@ -From 764b96cc27c293fb37a8b9031ddb25290974e3a2 Mon Sep 17 00:00:00 2001 -From: Siarhei Siamashka <siarhei.siamashka@gmail.com> -Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH] fbdev: add FBIOCOPYAREA ioctl - -Based on the patch authored by Ali Gholami Rudi at - https://lkml.org/lkml/2009/7/13/153 - -Provide an ioctl for userspace applications, but only if this operation -is hardware accelerated (otherwide it does not make any sense). - -Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com> - -bcm2708_fb: Add ioctl for reading gpu memory through dma - -video: bcm2708_fb: Add compat_ioctl support. - -When using a 64 bit kernel with 32 bit userspace we need -compat ioctl handling for FBIODMACOPY as one of the -parameters is a pointer. - -Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org> ---- - drivers/video/fbdev/bcm2708_fb.c | 167 ++++++++++++++++++++++++++++++- - drivers/video/fbdev/core/fbmem.c | 35 +++++++ - include/uapi/linux/fb.h | 12 +++ - 3 files changed, 213 insertions(+), 1 deletion(-) - ---- a/drivers/video/fbdev/bcm2708_fb.c -+++ b/drivers/video/fbdev/bcm2708_fb.c -@@ -32,8 +32,10 @@ - #include <linux/printk.h> - #include <linux/console.h> - #include <linux/debugfs.h> -+#include <linux/uaccess.h> - #include <linux/io.h> - #include <linux/dma-mapping.h> -+#include <linux/cred.h> - #include <soc/bcm2835/raspberrypi-firmware.h> - #include <linux/mutex.h> - -@@ -613,7 +615,110 @@ static int bcm2708_fb_pan_display(struct - return result; - } - --static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) -+static void dma_memcpy(struct bcm2708_fb *fb, dma_addr_t dst, dma_addr_t src, -+ int size) -+{ -+ struct bcm2708_fb_dev *fbdev = fb->fbdev; -+ struct bcm2708_dma_cb *cb = fbdev->cb_base; -+ int burst_size = (fbdev->dma_chan == 0) ? 8 : 2; -+ -+ cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH | -+ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH | -+ BCM2708_DMA_D_INC; -+ cb->dst = dst; -+ cb->src = src; -+ cb->length = size; -+ cb->stride = 0; -+ cb->pad[0] = 0; -+ cb->pad[1] = 0; -+ cb->next = 0; -+ -+ // Not sure what to do if this gets a signal whilst waiting -+ if (mutex_lock_interruptible(&fbdev->dma_mutex)) -+ return; -+ -+ if (size < dma_busy_wait_threshold) { -+ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle); -+ bcm_dma_wait_idle(fbdev->dma_chan_base); -+ } else { -+ void __iomem *local_dma_chan = fbdev->dma_chan_base; -+ -+ cb->info |= BCM2708_DMA_INT_EN; -+ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle); -+ while (bcm_dma_is_busy(local_dma_chan)) { -+ wait_event_interruptible(fbdev->dma_waitq, -+ !bcm_dma_is_busy(local_dma_chan)); -+ } -+ fbdev->dma_stats.dma_irqs++; -+ } -+ fbdev->dma_stats.dma_copies++; -+ -+ mutex_unlock(&fbdev->dma_mutex); -+} -+ -+/* address with no aliases */ -+#define INTALIAS_NORMAL(x) ((x) & ~0xc0000000) -+/* cache coherent but non-allocating in L1 and L2 */ -+#define INTALIAS_L1L2_NONALLOCATING(x) (((x) & ~0xc0000000) | 0x80000000) -+ -+static long vc_mem_copy(struct bcm2708_fb *fb, struct fb_dmacopy *ioparam) -+{ -+ size_t size = PAGE_SIZE; -+ u32 *buf = NULL; -+ dma_addr_t bus_addr; -+ long rc = 0; -+ size_t offset; -+ -+ /* restrict this to root user */ -+ if (!uid_eq(current_euid(), GLOBAL_ROOT_UID)) { -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ if (!fb->gpu.base || !fb->gpu.length) { -+ pr_err("[%s]: Unable to determine gpu memory (%x,%x)\n", -+ __func__, fb->gpu.base, fb->gpu.length); -+ return -EFAULT; -+ } -+ -+ if (INTALIAS_NORMAL(ioparam->src) < fb->gpu.base || -+ INTALIAS_NORMAL(ioparam->src) >= fb->gpu.base + fb->gpu.length) { -+ pr_err("[%s]: Invalid memory access %x (%x-%x)", __func__, -+ INTALIAS_NORMAL(ioparam->src), fb->gpu.base, -+ fb->gpu.base + fb->gpu.length); -+ return -EFAULT; -+ } -+ -+ buf = dma_alloc_coherent(fb->fb.device, PAGE_ALIGN(size), &bus_addr, -+ GFP_ATOMIC); -+ if (!buf) { -+ pr_err("[%s]: failed to dma_alloc_coherent(%zd)\n", __func__, -+ size); -+ rc = -ENOMEM; -+ goto out; -+ } -+ -+ for (offset = 0; offset < ioparam->length; offset += size) { -+ size_t remaining = ioparam->length - offset; -+ size_t s = min(size, remaining); -+ u8 *p = (u8 *)((uintptr_t)ioparam->src + offset); -+ u8 *q = (u8 *)ioparam->dst + offset; -+ -+ dma_memcpy(fb, bus_addr, -+ INTALIAS_L1L2_NONALLOCATING((dma_addr_t)p), size); -+ if (copy_to_user(q, buf, s) != 0) { -+ pr_err("[%s]: failed to copy-to-user\n", __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ } -+out: -+ if (buf) -+ dma_free_coherent(fb->fb.device, PAGE_ALIGN(size), buf, -+ bus_addr); -+ return rc; -+} -+ - static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg) - { -@@ -629,6 +734,21 @@ static int bcm2708_ioctl(struct fb_info - RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC, - &dummy, sizeof(dummy)); - break; -+ -+ case FBIODMACOPY: -+ { -+ struct fb_dmacopy ioparam; -+ /* Get the parameter data. -+ */ -+ if (copy_from_user -+ (&ioparam, (void *)arg, sizeof(ioparam))) { -+ pr_err("[%s]: failed to copy-from-user\n", __func__); -+ ret = -EFAULT; -+ break; -+ } -+ ret = vc_mem_copy(fb, &ioparam); -+ break; -+ } - default: - dev_dbg(info->device, "Unknown ioctl 0x%x\n", cmd); - return -ENOTTY; -@@ -639,6 +759,48 @@ static int bcm2708_ioctl(struct fb_info - - return ret; - } -+ -+#ifdef CONFIG_COMPAT -+struct fb_dmacopy32 { -+ compat_uptr_t dst; -+ __u32 src; -+ __u32 length; -+}; -+ -+#define FBIODMACOPY32 _IOW('z', 0x22, struct fb_dmacopy32) -+ -+static int bcm2708_compat_ioctl(struct fb_info *info, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct bcm2708_fb *fb = to_bcm2708(info); -+ int ret; -+ -+ switch (cmd) { -+ case FBIODMACOPY32: -+ { -+ struct fb_dmacopy32 param32; -+ struct fb_dmacopy param; -+ /* Get the parameter data. -+ */ -+ if (copy_from_user(¶m32, (void *)arg, sizeof(param32))) { -+ pr_err("[%s]: failed to copy-from-user\n", __func__); -+ ret = -EFAULT; -+ break; -+ } -+ param.dst = compat_ptr(param32.dst); -+ param.src = param32.src; -+ param.length = param32.length; -+ ret = vc_mem_copy(fb, ¶m); -+ break; -+ } -+ default: -+ ret = bcm2708_ioctl(info, cmd, arg); -+ break; -+ } -+ return ret; -+} -+#endif -+ - static void bcm2708_fb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) - { -@@ -831,6 +993,9 @@ static struct fb_ops bcm2708_fb_ops = { - .fb_imageblit = bcm2708_fb_imageblit, - .fb_pan_display = bcm2708_fb_pan_display, - .fb_ioctl = bcm2708_ioctl, -+#ifdef CONFIG_COMPAT -+ .fb_compat_ioctl = bcm2708_compat_ioctl, -+#endif - }; - - static int bcm2708_fb_register(struct bcm2708_fb *fb) ---- a/drivers/video/fbdev/core/fbmem.c -+++ b/drivers/video/fbdev/core/fbmem.c -@@ -1080,6 +1080,30 @@ fb_blank(struct fb_info *info, int blank - } - EXPORT_SYMBOL(fb_blank); - -+static int fb_copyarea_user(struct fb_info *info, -+ struct fb_copyarea *copy) -+{ -+ int ret = 0; -+ lock_fb_info(info); -+ if (copy->dx >= info->var.xres || -+ copy->sx >= info->var.xres || -+ copy->width > info->var.xres || -+ copy->dy >= info->var.yres || -+ copy->sy >= info->var.yres || -+ copy->height > info->var.yres || -+ copy->dx + copy->width > info->var.xres || -+ copy->sx + copy->width > info->var.xres || -+ copy->dy + copy->height > info->var.yres || -+ copy->sy + copy->height > info->var.yres) { -+ ret = -EINVAL; -+ goto out; -+ } -+ info->fbops->fb_copyarea(info, copy); -+out: -+ unlock_fb_info(info); -+ return ret; -+} -+ - static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg) - { -@@ -1088,6 +1112,7 @@ static long do_fb_ioctl(struct fb_info * - struct fb_fix_screeninfo fix; - struct fb_cmap cmap_from; - struct fb_cmap_user cmap; -+ struct fb_copyarea copy; - void __user *argp = (void __user *)arg; - long ret = 0; - -@@ -1163,6 +1188,15 @@ static long do_fb_ioctl(struct fb_info * - unlock_fb_info(info); - console_unlock(); - break; -+ case FBIOCOPYAREA: -+ if (info->flags & FBINFO_HWACCEL_COPYAREA) { -+ /* only provide this ioctl if it is accelerated */ -+ if (copy_from_user(©, argp, sizeof(copy))) -+ return -EFAULT; -+ ret = fb_copyarea_user(info, ©); -+ break; -+ } -+ /* fall through */ - default: - lock_fb_info(info); - fb = info->fbops; -@@ -1308,6 +1342,7 @@ static long fb_compat_ioctl(struct file - case FBIOPAN_DISPLAY: - case FBIOGET_CON2FBMAP: - case FBIOPUT_CON2FBMAP: -+ case FBIOCOPYAREA: - arg = (unsigned long) compat_ptr(arg); - /* fall through */ - case FBIOBLANK: ---- a/include/uapi/linux/fb.h -+++ b/include/uapi/linux/fb.h -@@ -35,6 +35,12 @@ - #define FBIOPUT_MODEINFO 0x4617 - #define FBIOGET_DISPINFO 0x4618 - #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) -+/* -+ * HACK: use 'z' in order not to clash with any other ioctl numbers which might -+ * be concurrently added to the mainline kernel -+ */ -+#define FBIOCOPYAREA _IOW('z', 0x21, struct fb_copyarea) -+#define FBIODMACOPY _IOW('z', 0x22, struct fb_dmacopy) - - #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ - #define FB_TYPE_PLANES 1 /* Non interleaved planes */ -@@ -347,6 +353,12 @@ struct fb_copyarea { - __u32 sy; - }; - -+struct fb_dmacopy { -+ void *dst; -+ __u32 src; -+ __u32 length; -+}; -+ - struct fb_fillrect { - __u32 dx; /* screen-relative */ - __u32 dy; |