1 /* $OpenBSD: drm_scatter.c,v 1.15 2011/06/02 18:22:00 weerd Exp $ */ 2 /*- 3 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 * 25 * Authors: 26 * Gareth Hughes <gareth@valinux.com> 27 * Eric Anholt <anholt@FreeBSD.org> 28 * 29 */ 30 31 /* 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 #include "drmP.h" 38 39 void 40 drm_sg_cleanup(struct drm_device *dev, struct drm_sg_mem *entry) 41 { 42 if (entry == NULL) 43 return; 44 45 drm_dmamem_free(dev->dmat, entry->mem); 46 drm_free(entry); 47 } 48 49 int 50 drm_sg_alloc(struct drm_device * dev, struct drm_scatter_gather *request) 51 { 52 struct drm_sg_mem *entry; 53 bus_size_t size; 54 unsigned long pages; 55 56 if (dev->sg != NULL) 57 return (EINVAL); 58 59 entry = drm_calloc(1, sizeof(*entry)); 60 if (entry == NULL) 61 return (ENOMEM); 62 63 pages = round_page(request->size) / PAGE_SIZE; 64 size = pages << PAGE_SHIFT; 65 66 DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages); 67 68 if ((entry->mem = drm_dmamem_alloc(dev->dmat, size, PAGE_SIZE, pages, 69 PAGE_SIZE, 0, 0)) == NULL) 70 return (ENOMEM); 71 72 request->handle = entry->handle = (unsigned long)entry->mem->kva; 73 DRM_DEBUG("sg alloc handle = %08lx\n", entry->handle); 74 75 DRM_LOCK(); 76 if (dev->sg) { 77 DRM_UNLOCK(); 78 drm_sg_cleanup(dev, entry); 79 return EINVAL; 80 } 81 dev->sg = entry; 82 DRM_UNLOCK(); 83 84 return (0); 85 } 86 87 int 88 drm_sg_alloc_ioctl(struct drm_device *dev, void *data, 89 struct drm_file *file_priv) 90 { 91 struct drm_scatter_gather *request = data; 92 int ret; 93 94 DRM_DEBUG("\n"); 95 96 ret = drm_sg_alloc(dev, request); 97 return ret; 98 } 99 100 int 101 drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv) 102 { 103 struct drm_scatter_gather *request = data; 104 struct drm_sg_mem *entry; 105 106 DRM_LOCK(); 107 entry = dev->sg; 108 dev->sg = NULL; 109 DRM_UNLOCK(); 110 111 if (entry == NULL || entry->handle != request->handle) 112 return EINVAL; 113 114 DRM_DEBUG("sg free virtual = 0x%lx\n", entry->handle); 115 116 drm_sg_cleanup(dev, entry); 117 118 return 0; 119 } 120