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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* memory.c -- Memory management wrappers for DRM -*- linux-c -*-
  2.  * Created: Thu Feb  4 14:00:34 1999 by faith@precisioninsight.com
  3.  *
  4.  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
  5.  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  6.  * All Rights Reserved.
  7.  *
  8.  * Permission is hereby granted, free of charge, to any person obtaining a
  9.  * copy of this software and associated documentation files (the "Software"),
  10.  * to deal in the Software without restriction, including without limitation
  11.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12.  * and/or sell copies of the Software, and to permit persons to whom the
  13.  * Software is furnished to do so, subject to the following conditions:
  14.  * 
  15.  * The above copyright notice and this permission notice (including the next
  16.  * paragraph) shall be included in all copies or substantial portions of the
  17.  * Software.
  18.  * 
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  22.  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  23.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  24.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  25.  * DEALINGS IN THE SOFTWARE.
  26.  * 
  27.  * Authors:
  28.  *    Rickard E. (Rik) Faith <faith@valinux.com>
  29.  *
  30.  */
  31. #define __NO_VERSION__
  32. #include <linux/config.h>
  33. #include "drmP.h"
  34. #include <linux/wrapper.h>
  35. typedef struct drm_mem_stats {
  36. const char   *name;
  37. int   succeed_count;
  38. int   free_count;
  39. int   fail_count;
  40. unsigned long   bytes_allocated;
  41. unsigned long   bytes_freed;
  42. } drm_mem_stats_t;
  43. static spinlock_t   drm_mem_lock     = SPIN_LOCK_UNLOCKED;
  44. static unsigned long   drm_ram_available = 0; /* In pages */
  45. static unsigned long   drm_ram_used     = 0;
  46. static drm_mem_stats_t   drm_mem_stats[]   = {
  47. [DRM_MEM_DMA]     = { "dmabufs"  },
  48. [DRM_MEM_SAREA]     = { "sareas"   },
  49. [DRM_MEM_DRIVER]    = { "driver"   },
  50. [DRM_MEM_MAGIC]     = { "magic"    },
  51. [DRM_MEM_IOCTLS]    = { "ioctltab" },
  52. [DRM_MEM_MAPS]     = { "maplist"  },
  53. [DRM_MEM_VMAS]     = { "vmalist"  },
  54. [DRM_MEM_BUFS]     = { "buflist"  },
  55. [DRM_MEM_SEGS]     = { "seglist"  },
  56. [DRM_MEM_PAGES]     = { "pagelist" },
  57. [DRM_MEM_FILES]     = { "files"    },
  58. [DRM_MEM_QUEUES]    = { "queues"   },
  59. [DRM_MEM_CMDS]     = { "commands" },
  60. [DRM_MEM_MAPPINGS]  = { "mappings" },
  61. [DRM_MEM_BUFLISTS]  = { "buflists" },
  62. [DRM_MEM_AGPLISTS]  = { "agplist"  },
  63. [DRM_MEM_TOTALAGP]  = { "totalagp" },
  64. [DRM_MEM_BOUNDAGP]  = { "boundagp" },
  65. [DRM_MEM_CTXBITMAP] = { "ctxbitmap"},
  66. { NULL, 0, } /* Last entry must be null */
  67. };
  68. void drm_mem_init(void)
  69. {
  70. drm_mem_stats_t *mem;
  71. struct sysinfo si;
  72. for (mem = drm_mem_stats; mem->name; ++mem) {
  73. mem->succeed_count   = 0;
  74. mem->free_count      = 0;
  75. mem->fail_count      = 0;
  76. mem->bytes_allocated = 0;
  77. mem->bytes_freed     = 0;
  78. }
  79. si_meminfo(&si);
  80. #if LINUX_VERSION_CODE < 0x020317
  81. /* Changed to page count in 2.3.23 */
  82. drm_ram_available = si.totalram >> PAGE_SHIFT;
  83. #else
  84. drm_ram_available = si.totalram;
  85. #endif
  86. drm_ram_used   = 0;
  87. }
  88. /* drm_mem_info is called whenever a process reads /dev/drm/mem. */
  89. static int _drm_mem_info(char *buf, char **start, off_t offset, int len,
  90.  int *eof, void *data)
  91. {
  92. drm_mem_stats_t *pt;
  93. if (offset > 0) return 0; /* no partial requests */
  94. len  = 0;
  95. *eof = 1;
  96. DRM_PROC_PRINT("   total counts "
  97.        " |    outstanding  n");
  98. DRM_PROC_PRINT("type    alloc freed fail bytes    freed"
  99.        " | allocs      bytesnn");
  100. DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB         |n",
  101.        "system", 0, 0, 0,
  102.        drm_ram_available << (PAGE_SHIFT - 10));
  103. DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB         |n",
  104.        "locked", 0, 0, 0, drm_ram_used >> 10);
  105. DRM_PROC_PRINT("n");
  106. for (pt = drm_mem_stats; pt->name; pt++) {
  107. DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ldn",
  108.        pt->name,
  109.        pt->succeed_count,
  110.        pt->free_count,
  111.        pt->fail_count,
  112.        pt->bytes_allocated,
  113.        pt->bytes_freed,
  114.        pt->succeed_count - pt->free_count,
  115.        (long)pt->bytes_allocated
  116.        - (long)pt->bytes_freed);
  117. }
  118. return len;
  119. }
  120. int drm_mem_info(char *buf, char **start, off_t offset, int len,
  121.  int *eof, void *data)
  122. {
  123. int ret;
  124. spin_lock(&drm_mem_lock);
  125. ret = _drm_mem_info(buf, start, offset, len, eof, data);
  126. spin_unlock(&drm_mem_lock);
  127. return ret;
  128. }
  129. void *drm_alloc(size_t size, int area)
  130. {
  131. void *pt;
  132. if (!size) {
  133. DRM_MEM_ERROR(area, "Allocating 0 bytesn");
  134. return NULL;
  135. }
  136. if (!(pt = kmalloc(size, GFP_KERNEL))) {
  137. spin_lock(&drm_mem_lock);
  138. ++drm_mem_stats[area].fail_count;
  139. spin_unlock(&drm_mem_lock);
  140. return NULL;
  141. }
  142. spin_lock(&drm_mem_lock);
  143. ++drm_mem_stats[area].succeed_count;
  144. drm_mem_stats[area].bytes_allocated += size;
  145. spin_unlock(&drm_mem_lock);
  146. return pt;
  147. }
  148. void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
  149. {
  150. void *pt;
  151. if (!(pt = drm_alloc(size, area))) return NULL;
  152. if (oldpt && oldsize) {
  153. memcpy(pt, oldpt, oldsize);
  154. drm_free(oldpt, oldsize, area);
  155. }
  156. return pt;
  157. }
  158. char *drm_strdup(const char *s, int area)
  159. {
  160. char *pt;
  161. int  length = s ? strlen(s) : 0;
  162. if (!(pt = drm_alloc(length+1, area))) return NULL;
  163. strcpy(pt, s);
  164. return pt;
  165. }
  166. void drm_strfree(const char *s, int area)
  167. {
  168. unsigned int size;
  169. if (!s) return;
  170. size = 1 + (s ? strlen(s) : 0);
  171. drm_free((void *)s, size, area);
  172. }
  173. void drm_free(void *pt, size_t size, int area)
  174. {
  175. int alloc_count;
  176. int free_count;
  177. if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointern");
  178. else  kfree(pt);
  179. spin_lock(&drm_mem_lock);
  180. drm_mem_stats[area].bytes_freed += size;
  181. free_count  = ++drm_mem_stats[area].free_count;
  182. alloc_count = drm_mem_stats[area].succeed_count;
  183. spin_unlock(&drm_mem_lock);
  184. if (free_count > alloc_count) {
  185. DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocsn",
  186.       free_count, alloc_count);
  187. }
  188. }
  189. unsigned long drm_alloc_pages(int order, int area)
  190. {
  191. unsigned long address;
  192. unsigned long bytes   = PAGE_SIZE << order;
  193. unsigned long addr;
  194. unsigned int  sz;
  195. spin_lock(&drm_mem_lock);
  196. if ((drm_ram_used >> PAGE_SHIFT)
  197.     > (DRM_RAM_PERCENT * drm_ram_available) / 100) {
  198. spin_unlock(&drm_mem_lock);
  199. return 0;
  200. }
  201. spin_unlock(&drm_mem_lock);
  202. address = __get_free_pages(GFP_KERNEL, order);
  203. if (!address) {
  204. spin_lock(&drm_mem_lock);
  205. ++drm_mem_stats[area].fail_count;
  206. spin_unlock(&drm_mem_lock);
  207. return 0;
  208. }
  209. spin_lock(&drm_mem_lock);
  210. ++drm_mem_stats[area].succeed_count;
  211. drm_mem_stats[area].bytes_allocated += bytes;
  212. drm_ram_used             += bytes;
  213. spin_unlock(&drm_mem_lock);
  214. /* Zero outside the lock */
  215. memset((void *)address, 0, bytes);
  216. /* Reserve */
  217. for (addr = address, sz = bytes;
  218.      sz > 0;
  219.      addr += PAGE_SIZE, sz -= PAGE_SIZE) {
  220. #if LINUX_VERSION_CODE >= 0x020400
  221. /* Argument type changed in 2.4.0-test6/pre8 */
  222. mem_map_reserve(virt_to_page(addr));
  223. #else
  224. mem_map_reserve(MAP_NR(addr));
  225. #endif
  226. }
  227. return address;
  228. }
  229. void drm_free_pages(unsigned long address, int order, int area)
  230. {
  231. unsigned long bytes = PAGE_SIZE << order;
  232. int   alloc_count;
  233. int   free_count;
  234. unsigned long addr;
  235. unsigned int  sz;
  236. if (!address) {
  237. DRM_MEM_ERROR(area, "Attempt to free address 0n");
  238. } else {
  239. /* Unreserve */
  240. for (addr = address, sz = bytes;
  241.      sz > 0;
  242.      addr += PAGE_SIZE, sz -= PAGE_SIZE) {
  243. #if LINUX_VERSION_CODE >= 0x020400
  244. /* Argument type changed in 2.4.0-test6/pre8 */
  245. mem_map_unreserve(virt_to_page(addr));
  246. #else
  247. mem_map_unreserve(MAP_NR(addr));
  248. #endif
  249. }
  250. free_pages(address, order);
  251. }
  252. spin_lock(&drm_mem_lock);
  253. free_count  = ++drm_mem_stats[area].free_count;
  254. alloc_count = drm_mem_stats[area].succeed_count;
  255. drm_mem_stats[area].bytes_freed += bytes;
  256. drm_ram_used -= bytes;
  257. spin_unlock(&drm_mem_lock);
  258. if (free_count > alloc_count) {
  259. DRM_MEM_ERROR(area,
  260.       "Excess frees: %d frees, %d allocsn",
  261.       free_count, alloc_count);
  262. }
  263. }
  264. void *drm_ioremap(unsigned long offset, unsigned long size)
  265. {
  266. void *pt;
  267. if (!size) {
  268. DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
  269.       "Mapping 0 bytes at 0x%08lxn", offset);
  270. return NULL;
  271. }
  272. if (!(pt = ioremap(offset, size))) {
  273. spin_lock(&drm_mem_lock);
  274. ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
  275. spin_unlock(&drm_mem_lock);
  276. return NULL;
  277. }
  278. spin_lock(&drm_mem_lock);
  279. ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
  280. drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
  281. spin_unlock(&drm_mem_lock);
  282. return pt;
  283. }
  284. void drm_ioremapfree(void *pt, unsigned long size)
  285. {
  286. int alloc_count;
  287. int free_count;
  288. if (!pt)
  289. DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
  290.       "Attempt to free NULL pointern");
  291. else
  292. iounmap(pt);
  293. spin_lock(&drm_mem_lock);
  294. drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
  295. free_count  = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
  296. alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
  297. spin_unlock(&drm_mem_lock);
  298. if (free_count > alloc_count) {
  299. DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
  300.       "Excess frees: %d frees, %d allocsn",
  301.       free_count, alloc_count);
  302. }
  303. }
  304. #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
  305. agp_memory *drm_alloc_agp(int pages, u32 type)
  306. {
  307. agp_memory *handle;
  308. if (!pages) {
  309. DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pagesn");
  310. return NULL;
  311. }
  312. if ((handle = drm_agp_allocate_memory(pages, type))) {
  313. spin_lock(&drm_mem_lock);
  314. ++drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count;
  315. drm_mem_stats[DRM_MEM_TOTALAGP].bytes_allocated
  316. += pages << PAGE_SHIFT;
  317. spin_unlock(&drm_mem_lock);
  318. return handle;
  319. }
  320. spin_lock(&drm_mem_lock);
  321. ++drm_mem_stats[DRM_MEM_TOTALAGP].fail_count;
  322. spin_unlock(&drm_mem_lock);
  323. return NULL;
  324. }
  325. int drm_free_agp(agp_memory *handle, int pages)
  326. {
  327. int           alloc_count;
  328. int           free_count;
  329. int           retval = -EINVAL;
  330. if (!handle) {
  331. DRM_MEM_ERROR(DRM_MEM_TOTALAGP,
  332.       "Attempt to free NULL AGP handlen");
  333. return retval;;
  334. }
  335. if (drm_agp_free_memory(handle)) {
  336. spin_lock(&drm_mem_lock);
  337. free_count  = ++drm_mem_stats[DRM_MEM_TOTALAGP].free_count;
  338. alloc_count =   drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count;
  339. drm_mem_stats[DRM_MEM_TOTALAGP].bytes_freed
  340. += pages << PAGE_SHIFT;
  341. spin_unlock(&drm_mem_lock);
  342. if (free_count > alloc_count) {
  343. DRM_MEM_ERROR(DRM_MEM_TOTALAGP,
  344.       "Excess frees: %d frees, %d allocsn",
  345.       free_count, alloc_count);
  346. }
  347. return 0;
  348. }
  349. return retval;
  350. }
  351. int drm_bind_agp(agp_memory *handle, unsigned int start)
  352. {
  353. int retcode = -EINVAL;
  354. if (!handle) {
  355. DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
  356.       "Attempt to bind NULL AGP handlen");
  357. return retcode;
  358. }
  359. if (!(retcode = drm_agp_bind_memory(handle, start))) {
  360. spin_lock(&drm_mem_lock);
  361. ++drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
  362. drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_allocated
  363. += handle->page_count << PAGE_SHIFT;
  364. spin_unlock(&drm_mem_lock);
  365. return retcode;
  366. }
  367. spin_lock(&drm_mem_lock);
  368. ++drm_mem_stats[DRM_MEM_BOUNDAGP].fail_count;
  369. spin_unlock(&drm_mem_lock);
  370. return retcode;
  371. }
  372. int drm_unbind_agp(agp_memory *handle)
  373. {
  374. int alloc_count;
  375. int free_count;
  376. int retcode = -EINVAL;
  377. if (!handle) {
  378. DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
  379.       "Attempt to unbind NULL AGP handlen");
  380. return retcode;
  381. }
  382. if ((retcode = drm_agp_unbind_memory(handle))) return retcode;
  383. spin_lock(&drm_mem_lock);
  384. free_count  = ++drm_mem_stats[DRM_MEM_BOUNDAGP].free_count;
  385. alloc_count = drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
  386. drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_freed
  387. += handle->page_count << PAGE_SHIFT;
  388. spin_unlock(&drm_mem_lock);
  389. if (free_count > alloc_count) {
  390. DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
  391.       "Excess frees: %d frees, %d allocsn",
  392.       free_count, alloc_count);
  393. }
  394. return retcode;
  395. }
  396. #endif