2 * \file drm_memory_debug.h
3 * Memory management wrappers for DRM.
5 * \author Rickard E. (Rik) Faith <faith@valinux.com>
6 * \author Gareth Hughes <gareth@valinux.com>
10 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
11 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
12 * All Rights Reserved.
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
21 * The above copyright notice and this permission notice (including the next
22 * paragraph) shall be included in all copies or substantial portions of the
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
31 * OTHER DEALINGS IN THE SOFTWARE.
36 typedef struct drm_mem_stats
{
41 unsigned long bytes_allocated
;
42 unsigned long bytes_freed
;
45 static DEFINE_SPINLOCK(drm_mem_lock
);
46 static unsigned long drm_ram_available
= 0; /* In pages */
47 static unsigned long drm_ram_used
= 0;
48 static drm_mem_stats_t drm_mem_stats
[] =
50 [DRM_MEM_DMA
] = {"dmabufs"},
51 [DRM_MEM_SAREA
] = {"sareas"},
52 [DRM_MEM_DRIVER
] = {"driver"},
53 [DRM_MEM_MAGIC
] = {"magic"},
54 [DRM_MEM_IOCTLS
] = {"ioctltab"},
55 [DRM_MEM_MAPS
] = {"maplist"},
56 [DRM_MEM_VMAS
] = {"vmalist"},
57 [DRM_MEM_BUFS
] = {"buflist"},
58 [DRM_MEM_SEGS
] = {"seglist"},
59 [DRM_MEM_PAGES
] = {"pagelist"},
60 [DRM_MEM_FILES
] = {"files"},
61 [DRM_MEM_QUEUES
] = {"queues"},
62 [DRM_MEM_CMDS
] = {"commands"},
63 [DRM_MEM_MAPPINGS
] = {"mappings"},
64 [DRM_MEM_BUFLISTS
] = {"buflists"},
65 [DRM_MEM_AGPLISTS
] = {"agplist"},
66 [DRM_MEM_SGLISTS
] = {"sglist"},
67 [DRM_MEM_TOTALAGP
] = {"totalagp"},
68 [DRM_MEM_BOUNDAGP
] = {"boundagp"},
69 [DRM_MEM_CTXBITMAP
] = {"ctxbitmap"},
70 [DRM_MEM_CTXLIST
] = {"ctxlist"},
71 [DRM_MEM_STUB
] = {"stub"},
72 {NULL
, 0,} /* Last entry must be null */
75 void drm_mem_init (void) {
79 for (mem
= drm_mem_stats
; mem
->name
; ++mem
) {
80 mem
->succeed_count
= 0;
83 mem
->bytes_allocated
= 0;
88 drm_ram_available
= si
.totalram
;
92 /* drm_mem_info is called whenever a process reads /dev/drm/mem. */
94 static int drm__mem_info (char *buf
, char **start
, off_t offset
,
95 int request
, int *eof
, void *data
) {
99 if (offset
> DRM_PROC_LIMIT
) {
105 *start
= &buf
[offset
];
107 DRM_PROC_PRINT(" total counts "
108 " | outstanding \n");
109 DRM_PROC_PRINT("type alloc freed fail bytes freed"
110 " | allocs bytes\n\n");
111 DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n",
113 drm_ram_available
<< (PAGE_SHIFT
- 10));
114 DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n",
115 "locked", 0, 0, 0, drm_ram_used
>> 10);
116 DRM_PROC_PRINT("\n");
117 for (pt
= drm_mem_stats
; pt
->name
; pt
++) {
118 DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n",
125 pt
->succeed_count
- pt
->free_count
,
126 (long)pt
->bytes_allocated
127 - (long)pt
->bytes_freed
);
130 if (len
> request
+ offset
)
136 int drm_mem_info (char *buf
, char **start
, off_t offset
,
137 int len
, int *eof
, void *data
) {
140 spin_lock(&drm_mem_lock
);
141 ret
= drm__mem_info (buf
, start
, offset
, len
, eof
, data
);
142 spin_unlock(&drm_mem_lock
);
146 void *drm_alloc (size_t size
, int area
) {
150 DRM_MEM_ERROR(area
, "Allocating 0 bytes\n");
154 if (!(pt
= kmalloc(size
, GFP_KERNEL
))) {
155 spin_lock(&drm_mem_lock
);
156 ++drm_mem_stats
[area
].fail_count
;
157 spin_unlock(&drm_mem_lock
);
160 spin_lock(&drm_mem_lock
);
161 ++drm_mem_stats
[area
].succeed_count
;
162 drm_mem_stats
[area
].bytes_allocated
+= size
;
163 spin_unlock(&drm_mem_lock
);
167 void *drm_calloc (size_t nmemb
, size_t size
, int area
) {
170 addr
= drm_alloc (nmemb
* size
, area
);
172 memset((void *)addr
, 0, size
* nmemb
);
177 void *drm_realloc (void *oldpt
, size_t oldsize
, size_t size
, int area
) {
180 if (!(pt
= drm_alloc (size
, area
)))
182 if (oldpt
&& oldsize
) {
183 memcpy(pt
, oldpt
, oldsize
);
184 drm_free (oldpt
, oldsize
, area
);
189 void drm_free (void *pt
, size_t size
, int area
) {
194 DRM_MEM_ERROR(area
, "Attempt to free NULL pointer\n");
197 spin_lock(&drm_mem_lock
);
198 drm_mem_stats
[area
].bytes_freed
+= size
;
199 free_count
= ++drm_mem_stats
[area
].free_count
;
200 alloc_count
= drm_mem_stats
[area
].succeed_count
;
201 spin_unlock(&drm_mem_lock
);
202 if (free_count
> alloc_count
) {
203 DRM_MEM_ERROR(area
, "Excess frees: %d frees, %d allocs\n",
204 free_count
, alloc_count
);
210 DRM_AGP_MEM
*drm_alloc_agp (drm_device_t
*dev
, int pages
, u32 type
) {
214 DRM_MEM_ERROR(DRM_MEM_TOTALAGP
, "Allocating 0 pages\n");
218 if ((handle
= drm_agp_allocate_memory (pages
, type
))) {
219 spin_lock(&drm_mem_lock
);
220 ++drm_mem_stats
[DRM_MEM_TOTALAGP
].succeed_count
;
221 drm_mem_stats
[DRM_MEM_TOTALAGP
].bytes_allocated
222 += pages
<< PAGE_SHIFT
;
223 spin_unlock(&drm_mem_lock
);
226 spin_lock(&drm_mem_lock
);
227 ++drm_mem_stats
[DRM_MEM_TOTALAGP
].fail_count
;
228 spin_unlock(&drm_mem_lock
);
232 int drm_free_agp (DRM_AGP_MEM
* handle
, int pages
) {
235 int retval
= -EINVAL
;
238 DRM_MEM_ERROR(DRM_MEM_TOTALAGP
,
239 "Attempt to free NULL AGP handle\n");
243 if (drm_agp_free_memory (handle
)) {
244 spin_lock(&drm_mem_lock
);
245 free_count
= ++drm_mem_stats
[DRM_MEM_TOTALAGP
].free_count
;
246 alloc_count
= drm_mem_stats
[DRM_MEM_TOTALAGP
].succeed_count
;
247 drm_mem_stats
[DRM_MEM_TOTALAGP
].bytes_freed
248 += pages
<< PAGE_SHIFT
;
249 spin_unlock(&drm_mem_lock
);
250 if (free_count
> alloc_count
) {
251 DRM_MEM_ERROR(DRM_MEM_TOTALAGP
,
252 "Excess frees: %d frees, %d allocs\n",
253 free_count
, alloc_count
);
260 int drm_bind_agp (DRM_AGP_MEM
* handle
, unsigned int start
) {
261 int retcode
= -EINVAL
;
264 DRM_MEM_ERROR(DRM_MEM_BOUNDAGP
,
265 "Attempt to bind NULL AGP handle\n");
269 if (!(retcode
= drm_agp_bind_memory (handle
, start
))) {
270 spin_lock(&drm_mem_lock
);
271 ++drm_mem_stats
[DRM_MEM_BOUNDAGP
].succeed_count
;
272 drm_mem_stats
[DRM_MEM_BOUNDAGP
].bytes_allocated
273 += handle
->page_count
<< PAGE_SHIFT
;
274 spin_unlock(&drm_mem_lock
);
277 spin_lock(&drm_mem_lock
);
278 ++drm_mem_stats
[DRM_MEM_BOUNDAGP
].fail_count
;
279 spin_unlock(&drm_mem_lock
);
283 int drm_unbind_agp (DRM_AGP_MEM
* handle
) {
286 int retcode
= -EINVAL
;
289 DRM_MEM_ERROR(DRM_MEM_BOUNDAGP
,
290 "Attempt to unbind NULL AGP handle\n");
294 if ((retcode
= drm_agp_unbind_memory (handle
)))
296 spin_lock(&drm_mem_lock
);
297 free_count
= ++drm_mem_stats
[DRM_MEM_BOUNDAGP
].free_count
;
298 alloc_count
= drm_mem_stats
[DRM_MEM_BOUNDAGP
].succeed_count
;
299 drm_mem_stats
[DRM_MEM_BOUNDAGP
].bytes_freed
300 += handle
->page_count
<< PAGE_SHIFT
;
301 spin_unlock(&drm_mem_lock
);
302 if (free_count
> alloc_count
) {
303 DRM_MEM_ERROR(DRM_MEM_BOUNDAGP
,
304 "Excess frees: %d frees, %d allocs\n",
305 free_count
, alloc_count
);