at v2.6.15 449 lines 12 kB view raw
1/** 2 * \file drm_memory.h 3 * Memory management wrappers for DRM. 4 * 5 * \author Rickard E. (Rik) Faith <faith@valinux.com> 6 * \author Gareth Hughes <gareth@valinux.com> 7 */ 8 9/* 10 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 11 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 12 * All Rights Reserved. 13 * 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: 20 * 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 23 * Software. 24 * 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. 32 */ 33 34#include <linux/config.h> 35#include "drmP.h" 36 37typedef struct drm_mem_stats { 38 const char *name; 39 int succeed_count; 40 int free_count; 41 int fail_count; 42 unsigned long bytes_allocated; 43 unsigned long bytes_freed; 44} drm_mem_stats_t; 45 46static DEFINE_SPINLOCK(DRM(mem_lock)); 47static unsigned long DRM(ram_available) = 0; /* In pages */ 48static unsigned long DRM(ram_used) = 0; 49static drm_mem_stats_t DRM(mem_stats)[] = 50{ 51 [DRM_MEM_DMA] = { 52 "dmabufs"},[DRM_MEM_SAREA] = { 53 "sareas"},[DRM_MEM_DRIVER] = { 54 "driver"},[DRM_MEM_MAGIC] = { 55 "magic"},[DRM_MEM_IOCTLS] = { 56 "ioctltab"},[DRM_MEM_MAPS] = { 57 "maplist"},[DRM_MEM_VMAS] = { 58 "vmalist"},[DRM_MEM_BUFS] = { 59 "buflist"},[DRM_MEM_SEGS] = { 60 "seglist"},[DRM_MEM_PAGES] = { 61 "pagelist"},[DRM_MEM_FILES] = { 62 "files"},[DRM_MEM_QUEUES] = { 63 "queues"},[DRM_MEM_CMDS] = { 64 "commands"},[DRM_MEM_MAPPINGS] = { 65 "mappings"},[DRM_MEM_BUFLISTS] = { 66 "buflists"},[DRM_MEM_AGPLISTS] = { 67 "agplist"},[DRM_MEM_SGLISTS] = { 68 "sglist"},[DRM_MEM_TOTALAGP] = { 69 "totalagp"},[DRM_MEM_BOUNDAGP] = { 70 "boundagp"},[DRM_MEM_CTXBITMAP] = { 71 "ctxbitmap"},[DRM_MEM_CTXLIST] = { 72 "ctxlist"},[DRM_MEM_STUB] = { 73 "stub"}, { 74 NULL, 0,} /* Last entry must be null */ 75}; 76 77void DRM(mem_init) (void) { 78 drm_mem_stats_t *mem; 79 struct sysinfo si; 80 81 for (mem = DRM(mem_stats); mem->name; ++mem) { 82 mem->succeed_count = 0; 83 mem->free_count = 0; 84 mem->fail_count = 0; 85 mem->bytes_allocated = 0; 86 mem->bytes_freed = 0; 87 } 88 89 si_meminfo(&si); 90 DRM(ram_available) = si.totalram; 91 DRM(ram_used) = 0; 92} 93 94/* drm_mem_info is called whenever a process reads /dev/drm/mem. */ 95 96static int DRM(_mem_info) (char *buf, char **start, off_t offset, 97 int request, int *eof, void *data) { 98 drm_mem_stats_t *pt; 99 int len = 0; 100 101 if (offset > DRM_PROC_LIMIT) { 102 *eof = 1; 103 return 0; 104 } 105 106 *eof = 0; 107 *start = &buf[offset]; 108 109 DRM_PROC_PRINT(" total counts " 110 " | outstanding \n"); 111 DRM_PROC_PRINT("type alloc freed fail bytes freed" 112 " | allocs bytes\n\n"); 113 DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", 114 "system", 0, 0, 0, 115 DRM(ram_available) << (PAGE_SHIFT - 10)); 116 DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", 117 "locked", 0, 0, 0, DRM(ram_used) >> 10); 118 DRM_PROC_PRINT("\n"); 119 for (pt = DRM(mem_stats); pt->name; pt++) { 120 DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n", 121 pt->name, 122 pt->succeed_count, 123 pt->free_count, 124 pt->fail_count, 125 pt->bytes_allocated, 126 pt->bytes_freed, 127 pt->succeed_count - pt->free_count, 128 (long)pt->bytes_allocated 129 - (long)pt->bytes_freed); 130 } 131 132 if (len > request + offset) 133 return request; 134 *eof = 1; 135 return len - offset; 136} 137 138int DRM(mem_info) (char *buf, char **start, off_t offset, 139 int len, int *eof, void *data) { 140 int ret; 141 142 spin_lock(&DRM(mem_lock)); 143 ret = DRM(_mem_info) (buf, start, offset, len, eof, data); 144 spin_unlock(&DRM(mem_lock)); 145 return ret; 146} 147 148void *DRM(alloc) (size_t size, int area) { 149 void *pt; 150 151 if (!size) { 152 DRM_MEM_ERROR(area, "Allocating 0 bytes\n"); 153 return NULL; 154 } 155 156 if (!(pt = kmalloc(size, GFP_KERNEL))) { 157 spin_lock(&DRM(mem_lock)); 158 ++DRM(mem_stats)[area].fail_count; 159 spin_unlock(&DRM(mem_lock)); 160 return NULL; 161 } 162 spin_lock(&DRM(mem_lock)); 163 ++DRM(mem_stats)[area].succeed_count; 164 DRM(mem_stats)[area].bytes_allocated += size; 165 spin_unlock(&DRM(mem_lock)); 166 return pt; 167} 168 169void *DRM(calloc) (size_t nmemb, size_t size, int area) { 170 void *addr; 171 172 addr = DRM(alloc) (nmemb * size, area); 173 if (addr != NULL) 174 memset((void *)addr, 0, size * nmemb); 175 176 return addr; 177} 178 179void *DRM(realloc) (void *oldpt, size_t oldsize, size_t size, int area) { 180 void *pt; 181 182 if (!(pt = DRM(alloc) (size, area))) 183 return NULL; 184 if (oldpt && oldsize) { 185 memcpy(pt, oldpt, oldsize); 186 DRM(free) (oldpt, oldsize, area); 187 } 188 return pt; 189} 190 191void DRM(free) (void *pt, size_t size, int area) { 192 int alloc_count; 193 int free_count; 194 195 if (!pt) 196 DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n"); 197 else 198 kfree(pt); 199 spin_lock(&DRM(mem_lock)); 200 DRM(mem_stats)[area].bytes_freed += size; 201 free_count = ++DRM(mem_stats)[area].free_count; 202 alloc_count = DRM(mem_stats)[area].succeed_count; 203 spin_unlock(&DRM(mem_lock)); 204 if (free_count > alloc_count) { 205 DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n", 206 free_count, alloc_count); 207 } 208} 209 210unsigned long DRM(alloc_pages) (int order, int area) { 211 unsigned long address; 212 unsigned long bytes = PAGE_SIZE << order; 213 unsigned long addr; 214 unsigned int sz; 215 216 spin_lock(&DRM(mem_lock)); 217 if ((DRM(ram_used) >> PAGE_SHIFT) 218 > (DRM_RAM_PERCENT * DRM(ram_available)) / 100) { 219 spin_unlock(&DRM(mem_lock)); 220 return 0; 221 } 222 spin_unlock(&DRM(mem_lock)); 223 224 address = __get_free_pages(GFP_KERNEL|__GFP_COMP, order); 225 if (!address) { 226 spin_lock(&DRM(mem_lock)); 227 ++DRM(mem_stats)[area].fail_count; 228 spin_unlock(&DRM(mem_lock)); 229 return 0; 230 } 231 spin_lock(&DRM(mem_lock)); 232 ++DRM(mem_stats)[area].succeed_count; 233 DRM(mem_stats)[area].bytes_allocated += bytes; 234 DRM(ram_used) += bytes; 235 spin_unlock(&DRM(mem_lock)); 236 237 /* Zero outside the lock */ 238 memset((void *)address, 0, bytes); 239 240 /* Reserve */ 241 for (addr = address, sz = bytes; 242 sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { 243 SetPageReserved(virt_to_page(addr)); 244 } 245 246 return address; 247} 248 249void DRM(free_pages) (unsigned long address, int order, int area) { 250 unsigned long bytes = PAGE_SIZE << order; 251 int alloc_count; 252 int free_count; 253 unsigned long addr; 254 unsigned int sz; 255 256 if (!address) { 257 DRM_MEM_ERROR(area, "Attempt to free address 0\n"); 258 } else { 259 /* Unreserve */ 260 for (addr = address, sz = bytes; 261 sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { 262 ClearPageReserved(virt_to_page(addr)); 263 } 264 free_pages(address, order); 265 } 266 267 spin_lock(&DRM(mem_lock)); 268 free_count = ++DRM(mem_stats)[area].free_count; 269 alloc_count = DRM(mem_stats)[area].succeed_count; 270 DRM(mem_stats)[area].bytes_freed += bytes; 271 DRM(ram_used) -= bytes; 272 spin_unlock(&DRM(mem_lock)); 273 if (free_count > alloc_count) { 274 DRM_MEM_ERROR(area, 275 "Excess frees: %d frees, %d allocs\n", 276 free_count, alloc_count); 277 } 278} 279 280void *DRM(ioremap) (unsigned long offset, unsigned long size, 281 drm_device_t * dev) { 282 void *pt; 283 284 if (!size) { 285 DRM_MEM_ERROR(DRM_MEM_MAPPINGS, 286 "Mapping 0 bytes at 0x%08lx\n", offset); 287 return NULL; 288 } 289 290 if (!(pt = drm_ioremap(offset, size, dev))) { 291 spin_lock(&DRM(mem_lock)); 292 ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; 293 spin_unlock(&DRM(mem_lock)); 294 return NULL; 295 } 296 spin_lock(&DRM(mem_lock)); 297 ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; 298 DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; 299 spin_unlock(&DRM(mem_lock)); 300 return pt; 301} 302 303void *DRM(ioremap_nocache) (unsigned long offset, unsigned long size, 304 drm_device_t * dev) { 305 void *pt; 306 307 if (!size) { 308 DRM_MEM_ERROR(DRM_MEM_MAPPINGS, 309 "Mapping 0 bytes at 0x%08lx\n", offset); 310 return NULL; 311 } 312 313 if (!(pt = drm_ioremap_nocache(offset, size, dev))) { 314 spin_lock(&DRM(mem_lock)); 315 ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; 316 spin_unlock(&DRM(mem_lock)); 317 return NULL; 318 } 319 spin_lock(&DRM(mem_lock)); 320 ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; 321 DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; 322 spin_unlock(&DRM(mem_lock)); 323 return pt; 324} 325 326void DRM(ioremapfree) (void *pt, unsigned long size, drm_device_t * dev) { 327 int alloc_count; 328 int free_count; 329 330 if (!pt) 331 DRM_MEM_ERROR(DRM_MEM_MAPPINGS, 332 "Attempt to free NULL pointer\n"); 333 else 334 drm_ioremapfree(pt, size, dev); 335 336 spin_lock(&DRM(mem_lock)); 337 DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_freed += size; 338 free_count = ++DRM(mem_stats)[DRM_MEM_MAPPINGS].free_count; 339 alloc_count = DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; 340 spin_unlock(&DRM(mem_lock)); 341 if (free_count > alloc_count) { 342 DRM_MEM_ERROR(DRM_MEM_MAPPINGS, 343 "Excess frees: %d frees, %d allocs\n", 344 free_count, alloc_count); 345 } 346} 347 348#if __OS_HAS_AGP 349 350DRM_AGP_MEM *DRM(alloc_agp) (int pages, u32 type) { 351 DRM_AGP_MEM *handle; 352 353 if (!pages) { 354 DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n"); 355 return NULL; 356 } 357 358 if ((handle = DRM(agp_allocate_memory) (pages, type))) { 359 spin_lock(&DRM(mem_lock)); 360 ++DRM(mem_stats)[DRM_MEM_TOTALAGP].succeed_count; 361 DRM(mem_stats)[DRM_MEM_TOTALAGP].bytes_allocated 362 += pages << PAGE_SHIFT; 363 spin_unlock(&DRM(mem_lock)); 364 return handle; 365 } 366 spin_lock(&DRM(mem_lock)); 367 ++DRM(mem_stats)[DRM_MEM_TOTALAGP].fail_count; 368 spin_unlock(&DRM(mem_lock)); 369 return NULL; 370} 371 372int DRM(free_agp) (DRM_AGP_MEM * handle, int pages) { 373 int alloc_count; 374 int free_count; 375 int retval = -EINVAL; 376 377 if (!handle) { 378 DRM_MEM_ERROR(DRM_MEM_TOTALAGP, 379 "Attempt to free NULL AGP handle\n"); 380 return retval; 381 } 382 383 if (DRM(agp_free_memory) (handle)) { 384 spin_lock(&DRM(mem_lock)); 385 free_count = ++DRM(mem_stats)[DRM_MEM_TOTALAGP].free_count; 386 alloc_count = DRM(mem_stats)[DRM_MEM_TOTALAGP].succeed_count; 387 DRM(mem_stats)[DRM_MEM_TOTALAGP].bytes_freed 388 += pages << PAGE_SHIFT; 389 spin_unlock(&DRM(mem_lock)); 390 if (free_count > alloc_count) { 391 DRM_MEM_ERROR(DRM_MEM_TOTALAGP, 392 "Excess frees: %d frees, %d allocs\n", 393 free_count, alloc_count); 394 } 395 return 0; 396 } 397 return retval; 398} 399 400int DRM(bind_agp) (DRM_AGP_MEM * handle, unsigned int start) { 401 int retcode = -EINVAL; 402 403 if (!handle) { 404 DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, 405 "Attempt to bind NULL AGP handle\n"); 406 return retcode; 407 } 408 409 if (!(retcode = DRM(agp_bind_memory) (handle, start))) { 410 spin_lock(&DRM(mem_lock)); 411 ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].succeed_count; 412 DRM(mem_stats)[DRM_MEM_BOUNDAGP].bytes_allocated 413 += handle->page_count << PAGE_SHIFT; 414 spin_unlock(&DRM(mem_lock)); 415 return retcode; 416 } 417 spin_lock(&DRM(mem_lock)); 418 ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].fail_count; 419 spin_unlock(&DRM(mem_lock)); 420 return retcode; 421} 422 423int DRM(unbind_agp) (DRM_AGP_MEM * handle) { 424 int alloc_count; 425 int free_count; 426 int retcode = -EINVAL; 427 428 if (!handle) { 429 DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, 430 "Attempt to unbind NULL AGP handle\n"); 431 return retcode; 432 } 433 434 if ((retcode = DRM(agp_unbind_memory) (handle))) 435 return retcode; 436 spin_lock(&DRM(mem_lock)); 437 free_count = ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].free_count; 438 alloc_count = DRM(mem_stats)[DRM_MEM_BOUNDAGP].succeed_count; 439 DRM(mem_stats)[DRM_MEM_BOUNDAGP].bytes_freed 440 += handle->page_count << PAGE_SHIFT; 441 spin_unlock(&DRM(mem_lock)); 442 if (free_count > alloc_count) { 443 DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, 444 "Excess frees: %d frees, %d allocs\n", 445 free_count, alloc_count); 446 } 447 return retcode; 448} 449#endif