0531-bcm2708_fb-Add-ioctl-for-reading-gpu-memory-through-.patch 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. From 26a7e2d3d11c23acc6f87414da736c07a3b9cc52 Mon Sep 17 00:00:00 2001
  2. From: popcornmix <popcornmix@gmail.com>
  3. Date: Sat, 5 Nov 2016 14:14:43 +0000
  4. Subject: [PATCH] bcm2708_fb: Add ioctl for reading gpu memory through dma
  5. ---
  6. drivers/video/fbdev/bcm2708_fb.c | 109 +++++++++++++++++++++++++++++++++++++++
  7. include/uapi/linux/fb.h | 7 +++
  8. 2 files changed, 116 insertions(+)
  9. --- a/drivers/video/fbdev/bcm2708_fb.c
  10. +++ b/drivers/video/fbdev/bcm2708_fb.c
  11. @@ -31,8 +31,10 @@
  12. #include <linux/console.h>
  13. #include <linux/debugfs.h>
  14. #include <asm/sizes.h>
  15. +#include <asm/uaccess.h>
  16. #include <linux/io.h>
  17. #include <linux/dma-mapping.h>
  18. +#include <linux/cred.h>
  19. #include <soc/bcm2835/raspberrypi-firmware.h>
  20. //#define BCM2708_FB_DEBUG
  21. @@ -429,6 +431,110 @@ static int bcm2708_fb_pan_display(struct
  22. return result;
  23. }
  24. +static void dma_memcpy(struct bcm2708_fb *fb, dma_addr_t dst, dma_addr_t src, int size)
  25. +{
  26. + int burst_size = (fb->dma_chan == 0) ? 8 : 2;
  27. + struct bcm2708_dma_cb *cb = fb->cb_base;
  28. +
  29. + cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH |
  30. + BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
  31. + BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE;
  32. + cb->dst = dst;
  33. + cb->src = src;
  34. + cb->length = size;
  35. + cb->stride = 0;
  36. + cb->pad[0] = 0;
  37. + cb->pad[1] = 0;
  38. + cb->next = 0;
  39. +
  40. + if (size < dma_busy_wait_threshold) {
  41. + bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
  42. + bcm_dma_wait_idle(fb->dma_chan_base);
  43. + } else {
  44. + void __iomem *dma_chan = fb->dma_chan_base;
  45. + cb->info |= BCM2708_DMA_INT_EN;
  46. + bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
  47. + while (bcm_dma_is_busy(dma_chan)) {
  48. + wait_event_interruptible(
  49. + fb->dma_waitq,
  50. + !bcm_dma_is_busy(dma_chan));
  51. + }
  52. + fb->stats.dma_irqs++;
  53. + }
  54. + fb->stats.dma_copies++;
  55. +}
  56. +
  57. +#define INTALIAS_NORMAL(x) ((x)&~0xc0000000) // address with no aliases
  58. +#define INTALIAS_L1L2_NONALLOCATING(x) (((x)&~0xc0000000)|0x80000000) // cache coherent but non-allocating in L1 and L2
  59. +
  60. +static long vc_mem_copy(struct bcm2708_fb *fb, unsigned long arg)
  61. +{
  62. + struct fb_dmacopy ioparam;
  63. + size_t size = PAGE_SIZE;
  64. + u32 *buf = NULL;
  65. + dma_addr_t bus_addr;
  66. + long rc = 0;
  67. + size_t offset;
  68. + struct { u32 base, length; } gpu = {};
  69. +
  70. + /* restrict this to root user */
  71. + if (!uid_eq(current_euid(), GLOBAL_ROOT_UID))
  72. + {
  73. + rc = -EFAULT;
  74. + goto out;
  75. + }
  76. +
  77. + /* Get the parameter data.
  78. + */
  79. + if (copy_from_user
  80. + (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
  81. + pr_err("[%s]: failed to copy-from-user\n",
  82. + __func__);
  83. + rc = -EFAULT;
  84. + goto out;
  85. + }
  86. +
  87. + rc = rpi_firmware_property(fb->fw,
  88. + RPI_FIRMWARE_GET_VC_MEMORY,
  89. + &gpu, sizeof(gpu));
  90. + if (rc != 0 || gpu.base == 0 || gpu.length == 0) {
  91. + pr_err("[%s]: Unable to determine gpu memory %ld,%x,%x)\n", __func__, rc, gpu.base, gpu.length);
  92. + return -EFAULT;
  93. + }
  94. +
  95. + if (INTALIAS_NORMAL(ioparam.src) < gpu.base || INTALIAS_NORMAL(ioparam.src) >= gpu.base + gpu.length) {
  96. + pr_err("[%s]: Invalid memory access %x (%x-%x)", __func__, INTALIAS_NORMAL(ioparam.src), gpu.base, gpu.base + gpu.length);
  97. + return -EFAULT;
  98. + }
  99. +
  100. + buf = dma_alloc_coherent(NULL, PAGE_ALIGN(size), &bus_addr,
  101. + GFP_ATOMIC);
  102. + if (!buf) {
  103. + pr_err("[%s]: failed to dma_alloc_coherent(%d)\n",
  104. + __func__, size);
  105. + rc = -ENOMEM;
  106. + goto out;
  107. + }
  108. +
  109. + for (offset = 0; offset < ioparam.length; offset += size) {
  110. + size_t remaining = ioparam.length - offset;
  111. + size_t s = min(size, remaining);
  112. + unsigned char *p = (unsigned char *)ioparam.src + offset;
  113. + unsigned char *q = (unsigned char *)ioparam.dst + offset;
  114. + dma_memcpy(fb, (dma_addr_t)buf, INTALIAS_L1L2_NONALLOCATING((dma_addr_t)p), size);
  115. + if (copy_to_user(q, buf, s) != 0) {
  116. + pr_err("[%s]: failed to copy-to-user\n",
  117. + __func__);
  118. + rc = -EFAULT;
  119. + goto out;
  120. + }
  121. + }
  122. +out:
  123. + if (buf)
  124. + dma_free_coherent(NULL, PAGE_ALIGN(size), buf, bus_addr);
  125. + return rc;
  126. +}
  127. +
  128. static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
  129. {
  130. struct bcm2708_fb *fb = to_bcm2708(info);
  131. @@ -441,6 +547,9 @@ static int bcm2708_ioctl(struct fb_info
  132. RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC,
  133. &dummy, sizeof(dummy));
  134. break;
  135. + case FBIODMACOPY:
  136. + ret = vc_mem_copy(fb, arg);
  137. + break;
  138. default:
  139. dev_dbg(info->device, "Unknown ioctl 0x%x\n", cmd);
  140. return -ENOTTY;
  141. --- a/include/uapi/linux/fb.h
  142. +++ b/include/uapi/linux/fb.h
  143. @@ -39,6 +39,7 @@
  144. * be concurrently added to the mainline kernel
  145. */
  146. #define FBIOCOPYAREA _IOW('z', 0x21, struct fb_copyarea)
  147. +#define FBIODMACOPY _IOW('z', 0x22, struct fb_dmacopy)
  148. #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
  149. #define FB_TYPE_PLANES 1 /* Non interleaved planes */
  150. @@ -351,6 +352,12 @@ struct fb_copyarea {
  151. __u32 sy;
  152. };
  153. +struct fb_dmacopy {
  154. + dma_addr_t dst;
  155. + dma_addr_t src;
  156. + __u32 length;
  157. +};
  158. +
  159. struct fb_fillrect {
  160. __u32 dx; /* screen-relative */
  161. __u32 dy;