drm_scatter.h
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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