drm_scatter.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /**
  2. * \file drm_scatter.h
  3. * IOCTLs to manage scatter/gather memory
  4. *
  5. * \author Gareth Hughes <gareth@valinux.com>
  6. */
  7. /*
  8. * Created: Mon Dec 18 23:20:54 2000 by gareth@valinux.com
  9. *
  10. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  11. * All Rights Reserved.
  12. *
  13. * Permission is hereby granted, free of charge, to any person obtaining a
  14. * copy of this software and associated documentation files (the "Software"),
  15. * to deal in the Software without restriction, including without limitation
  16. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  17. * and/or sell copies of the Software, and to permit persons to whom the
  18. * Software is furnished to do so, subject to the following conditions:
  19. *
  20. * The above copyright notice and this permission notice (including the next
  21. * paragraph) shall be included in all copies or substantial portions of the
  22. * Software.
  23. *
  24. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  25. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  27. * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  28. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  29. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  30. * DEALINGS IN THE SOFTWARE.
  31. */
  32. #include <linux/config.h>
  33. #include <linux/vmalloc.h>
  34. #include "drmP.h"
  35. #define DEBUG_SCATTER 0
  36. void drm_sg_cleanup( drm_sg_mem_t *entry )
  37. {
  38. struct page *page;
  39. int i;
  40. for ( i = 0 ; i < entry->pages ; i++ ) {
  41. page = entry->pagelist[i];
  42. if ( page )
  43. ClearPageReserved( page );
  44. }
  45. vfree( entry->virtual );
  46. drm_free( entry->busaddr,
  47. entry->pages * sizeof(*entry->busaddr),
  48. DRM_MEM_PAGES );
  49. drm_free( entry->pagelist,
  50. entry->pages * sizeof(*entry->pagelist),
  51. DRM_MEM_PAGES );
  52. drm_free( entry,
  53. sizeof(*entry),
  54. DRM_MEM_SGLISTS );
  55. }
  56. int drm_sg_alloc( struct inode *inode, struct file *filp,
  57. unsigned int cmd, unsigned long arg )
  58. {
  59. drm_file_t *priv = filp->private_data;
  60. drm_device_t *dev = priv->head->dev;
  61. drm_scatter_gather_t __user *argp = (void __user *)arg;
  62. drm_scatter_gather_t request;
  63. drm_sg_mem_t *entry;
  64. unsigned long pages, i, j;
  65. DRM_DEBUG( "%s\n", __FUNCTION__ );
  66. if (!drm_core_check_feature(dev, DRIVER_SG))
  67. return -EINVAL;
  68. if ( dev->sg )
  69. return -EINVAL;
  70. if ( copy_from_user( &request, argp, sizeof(request) ) )
  71. return -EFAULT;
  72. entry = drm_alloc( sizeof(*entry), DRM_MEM_SGLISTS );
  73. if ( !entry )
  74. return -ENOMEM;
  75. memset( entry, 0, sizeof(*entry) );
  76. pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
  77. DRM_DEBUG( "sg size=%ld pages=%ld\n", request.size, pages );
  78. entry->pages = pages;
  79. entry->pagelist = drm_alloc( pages * sizeof(*entry->pagelist),
  80. DRM_MEM_PAGES );
  81. if ( !entry->pagelist ) {
  82. drm_free( entry, sizeof(*entry), DRM_MEM_SGLISTS );
  83. return -ENOMEM;
  84. }
  85. memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist));
  86. entry->busaddr = drm_alloc( pages * sizeof(*entry->busaddr),
  87. DRM_MEM_PAGES );
  88. if ( !entry->busaddr ) {
  89. drm_free( entry->pagelist,
  90. entry->pages * sizeof(*entry->pagelist),
  91. DRM_MEM_PAGES );
  92. drm_free( entry,
  93. sizeof(*entry),
  94. DRM_MEM_SGLISTS );
  95. return -ENOMEM;
  96. }
  97. memset( (void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr) );
  98. entry->virtual = vmalloc_32( pages << PAGE_SHIFT );
  99. if ( !entry->virtual ) {
  100. drm_free( entry->busaddr,
  101. entry->pages * sizeof(*entry->busaddr),
  102. DRM_MEM_PAGES );
  103. drm_free( entry->pagelist,
  104. entry->pages * sizeof(*entry->pagelist),
  105. DRM_MEM_PAGES );
  106. drm_free( entry,
  107. sizeof(*entry),
  108. DRM_MEM_SGLISTS );
  109. return -ENOMEM;
  110. }
  111. /* This also forces the mapping of COW pages, so our page list
  112. * will be valid. Please don't remove it...
  113. */
  114. memset( entry->virtual, 0, pages << PAGE_SHIFT );
  115. entry->handle = (unsigned long)entry->virtual;
  116. DRM_DEBUG( "sg alloc handle = %08lx\n", entry->handle );
  117. DRM_DEBUG( "sg alloc virtual = %p\n", entry->virtual );
  118. for ( i = entry->handle, j = 0 ; j < pages ; i += PAGE_SIZE, j++ ) {
  119. entry->pagelist[j] = vmalloc_to_page((void *)i);
  120. if (!entry->pagelist[j])
  121. goto failed;
  122. SetPageReserved(entry->pagelist[j]);
  123. }
  124. request.handle = entry->handle;
  125. if ( copy_to_user( argp, &request, sizeof(request) ) ) {
  126. drm_sg_cleanup( entry );
  127. return -EFAULT;
  128. }
  129. dev->sg = entry;
  130. #if DEBUG_SCATTER
  131. /* Verify that each page points to its virtual address, and vice
  132. * versa.
  133. */
  134. {
  135. int error = 0;
  136. for ( i = 0 ; i < pages ; i++ ) {
  137. unsigned long *tmp;
  138. tmp = page_address( entry->pagelist[i] );
  139. for ( j = 0 ;
  140. j < PAGE_SIZE / sizeof(unsigned long) ;
  141. j++, tmp++ ) {
  142. *tmp = 0xcafebabe;
  143. }
  144. tmp = (unsigned long *)((u8 *)entry->virtual +
  145. (PAGE_SIZE * i));
  146. for( j = 0 ;
  147. j < PAGE_SIZE / sizeof(unsigned long) ;
  148. j++, tmp++ ) {
  149. if ( *tmp != 0xcafebabe && error == 0 ) {
  150. error = 1;
  151. DRM_ERROR( "Scatter allocation error, "
  152. "pagelist does not match "
  153. "virtual mapping\n" );
  154. }
  155. }
  156. tmp = page_address( entry->pagelist[i] );
  157. for(j = 0 ;
  158. j < PAGE_SIZE / sizeof(unsigned long) ;
  159. j++, tmp++) {
  160. *tmp = 0;
  161. }
  162. }
  163. if (error == 0)
  164. DRM_ERROR( "Scatter allocation matches pagelist\n" );
  165. }
  166. #endif
  167. return 0;
  168. failed:
  169. drm_sg_cleanup( entry );
  170. return -ENOMEM;
  171. }
  172. int drm_sg_free( struct inode *inode, struct file *filp,
  173. unsigned int cmd, unsigned long arg )
  174. {
  175. drm_file_t *priv = filp->private_data;
  176. drm_device_t *dev = priv->head->dev;
  177. drm_scatter_gather_t request;
  178. drm_sg_mem_t *entry;
  179. if (!drm_core_check_feature(dev, DRIVER_SG))
  180. return -EINVAL;
  181. if ( copy_from_user( &request,
  182. (drm_scatter_gather_t __user *)arg,
  183. sizeof(request) ) )
  184. return -EFAULT;
  185. entry = dev->sg;
  186. dev->sg = NULL;
  187. if ( !entry || entry->handle != request.handle )
  188. return -EINVAL;
  189. DRM_DEBUG( "sg free virtual = %p\n", entry->virtual );
  190. drm_sg_cleanup( entry );
  191. return 0;
  192. }