1 /*- 2 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Gareth Hughes <gareth@valinux.com> 26 * Eric Anholt <anholt@FreeBSD.org> 27 * 28 * $DragonFly: src/sys/dev/drm/drm_scatter.c,v 1.1 2008/04/05 18:12:29 hasso Exp $ 29 */ 30 31 /** @file drm_scatter.c 32 * Allocation of memory for scatter-gather mappings by the graphics chip. 33 * 34 * The memory allocated here is then made into an aperture in the card 35 * by drm_ati_pcigart_init(). 36 */ 37 38 #include "drmP.h" 39 40 #define DEBUG_SCATTER 0 41 42 void drm_sg_cleanup(drm_sg_mem_t *entry) 43 { 44 free((void *)entry->handle, M_DRM); 45 free(entry->busaddr, M_DRM); 46 free(entry, M_DRM); 47 } 48 49 int drm_sg_alloc(drm_device_t * dev, drm_scatter_gather_t * request) 50 { 51 drm_sg_mem_t *entry; 52 unsigned long pages; 53 int i; 54 55 if ( dev->sg ) 56 return EINVAL; 57 58 entry = malloc(sizeof(*entry), M_DRM, M_WAITOK | M_ZERO); 59 if ( !entry ) 60 return ENOMEM; 61 62 pages = round_page(request->size) / PAGE_SIZE; 63 DRM_DEBUG( "sg size=%ld pages=%ld\n", request->size, pages ); 64 65 entry->pages = pages; 66 67 entry->busaddr = malloc(pages * sizeof(*entry->busaddr), M_DRM, 68 M_WAITOK | M_ZERO); 69 if ( !entry->busaddr ) { 70 drm_sg_cleanup(entry); 71 return ENOMEM; 72 } 73 74 entry->handle = (long)malloc(pages << PAGE_SHIFT, M_DRM, 75 M_WAITOK | M_ZERO); 76 if (entry->handle == 0) { 77 drm_sg_cleanup(entry); 78 return ENOMEM; 79 } 80 81 for (i = 0; i < pages; i++) { 82 entry->busaddr[i] = vtophys(entry->handle + i * PAGE_SIZE); 83 } 84 85 DRM_DEBUG( "sg alloc handle = %08lx\n", entry->handle ); 86 87 entry->virtual = (void *)entry->handle; 88 request->handle = entry->handle; 89 90 DRM_LOCK(); 91 if (dev->sg) { 92 DRM_UNLOCK(); 93 drm_sg_cleanup(entry); 94 return EINVAL; 95 } 96 dev->sg = entry; 97 DRM_UNLOCK(); 98 99 return 0; 100 } 101 102 int drm_sg_alloc_ioctl(drm_device_t *dev, void *data, struct drm_file *file_priv) 103 { 104 drm_scatter_gather_t *request = data; 105 int ret; 106 107 DRM_DEBUG( "%s\n", __FUNCTION__ ); 108 109 ret = drm_sg_alloc(dev, request); 110 return ret; 111 } 112 113 int drm_sg_free(drm_device_t *dev, void *data, struct drm_file *file_priv) 114 { 115 drm_scatter_gather_t *request = data; 116 drm_sg_mem_t *entry; 117 118 DRM_LOCK(); 119 entry = dev->sg; 120 dev->sg = NULL; 121 DRM_UNLOCK(); 122 123 if ( !entry || entry->handle != request->handle ) 124 return EINVAL; 125 126 DRM_DEBUG( "sg free virtual = 0x%lx\n", entry->handle ); 127 128 drm_sg_cleanup(entry); 129 130 return 0; 131 } 132