drm_scatter.c revision 190282
1145132Sanholt/*- 2145132Sanholt * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 3145132Sanholt * All Rights Reserved. 4145132Sanholt * 5145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a 6145132Sanholt * copy of this software and associated documentation files (the "Software"), 7145132Sanholt * to deal in the Software without restriction, including without limitation 8145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the 10145132Sanholt * Software is furnished to do so, subject to the following conditions: 11145132Sanholt * 12145132Sanholt * The above copyright notice and this permission notice (including the next 13145132Sanholt * paragraph) shall be included in all copies or substantial portions of the 14145132Sanholt * Software. 15145132Sanholt * 16145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17145132Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18145132Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19145132Sanholt * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20145132Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21145132Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22145132Sanholt * DEALINGS IN THE SOFTWARE. 23145132Sanholt * 24145132Sanholt * Authors: 25145132Sanholt * Gareth Hughes <gareth@valinux.com> 26145132Sanholt * Eric Anholt <anholt@FreeBSD.org> 27145132Sanholt * 28145132Sanholt */ 29145132Sanholt 30152909Sanholt#include <sys/cdefs.h> 31152909Sanholt__FBSDID("$FreeBSD: head/sys/dev/drm/drm_scatter.c 190282 2009-03-22 20:58:29Z rnoland $"); 32152909Sanholt 33182080Srnoland/** @file drm_scatter.c 34182080Srnoland * Allocation of memory for scatter-gather mappings by the graphics chip. 35182080Srnoland * 36182080Srnoland * The memory allocated here is then made into an aperture in the card 37182080Srnoland * by drm_ati_pcigart_init(). 38182080Srnoland */ 39182080Srnoland 40145132Sanholt#include "dev/drm/drmP.h" 41145132Sanholt 42186295Srnolandstatic void drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs, 43186295Srnoland int nsegs, int error); 44145132Sanholt 45186295Srnolandint 46186295Srnolanddrm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather *request) 47145132Sanholt{ 48186295Srnoland struct drm_sg_mem *entry; 49186295Srnoland struct drm_dma_handle *dmah; 50145132Sanholt unsigned long pages; 51186295Srnoland int ret; 52145132Sanholt 53183573Srnoland if (dev->sg) 54145132Sanholt return EINVAL; 55145132Sanholt 56183833Srnoland entry = malloc(sizeof(*entry), DRM_MEM_SGLISTS, M_WAITOK | M_ZERO); 57183573Srnoland if (!entry) 58145132Sanholt return ENOMEM; 59145132Sanholt 60182080Srnoland pages = round_page(request->size) / PAGE_SIZE; 61183573Srnoland DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages); 62145132Sanholt 63145132Sanholt entry->pages = pages; 64145132Sanholt 65183833Srnoland entry->busaddr = malloc(pages * sizeof(*entry->busaddr), DRM_MEM_PAGES, 66145132Sanholt M_WAITOK | M_ZERO); 67183573Srnoland if (!entry->busaddr) { 68186295Srnoland free(entry, DRM_MEM_SGLISTS); 69145132Sanholt return ENOMEM; 70145132Sanholt } 71145132Sanholt 72186295Srnoland dmah = malloc(sizeof(struct drm_dma_handle), DRM_MEM_DMA, 73186295Srnoland M_ZERO | M_NOWAIT); 74186295Srnoland if (dmah == NULL) { 75186295Srnoland free(entry->busaddr, DRM_MEM_PAGES); 76186295Srnoland free(entry, DRM_MEM_SGLISTS); 77145132Sanholt return ENOMEM; 78145132Sanholt } 79145132Sanholt 80186295Srnoland ret = bus_dma_tag_create(NULL, PAGE_SIZE, 0, /* tag, align, boundary */ 81186295Srnoland BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */ 82186295Srnoland NULL, NULL, /* filtfunc, filtfuncargs */ 83186295Srnoland request->size, pages, /* maxsize, nsegs */ 84186295Srnoland PAGE_SIZE, 0, /* maxsegsize, flags */ 85186295Srnoland NULL, NULL, /* lockfunc, lockfuncargs */ 86186295Srnoland &dmah->tag); 87186295Srnoland if (ret != 0) { 88186295Srnoland free(dmah, DRM_MEM_DMA); 89186295Srnoland free(entry->busaddr, DRM_MEM_PAGES); 90186295Srnoland free(entry, DRM_MEM_SGLISTS); 91186295Srnoland return ENOMEM; 92152909Sanholt } 93145132Sanholt 94186295Srnoland ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr, 95190282Srnoland BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_NOCACHE, &dmah->map); 96186295Srnoland if (ret != 0) { 97186295Srnoland bus_dma_tag_destroy(dmah->tag); 98186295Srnoland free(dmah, DRM_MEM_DMA); 99186295Srnoland free(entry->busaddr, DRM_MEM_PAGES); 100186295Srnoland free(entry, DRM_MEM_SGLISTS); 101186295Srnoland return ENOMEM; 102186295Srnoland } 103186295Srnoland 104186295Srnoland ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, 105190282Srnoland request->size, drm_sg_alloc_cb, entry, BUS_DMA_NOWAIT); 106186295Srnoland if (ret != 0) { 107186295Srnoland bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); 108186295Srnoland bus_dma_tag_destroy(dmah->tag); 109186295Srnoland free(dmah, DRM_MEM_DMA); 110186295Srnoland free(entry->busaddr, DRM_MEM_PAGES); 111186295Srnoland free(entry, DRM_MEM_SGLISTS); 112186295Srnoland return ENOMEM; 113186295Srnoland } 114186295Srnoland 115186295Srnoland entry->sg_dmah = dmah; 116186295Srnoland entry->handle = (unsigned long)dmah->vaddr; 117186295Srnoland 118183573Srnoland DRM_DEBUG("sg alloc handle = %08lx\n", entry->handle); 119145132Sanholt 120158682Sanholt entry->virtual = (void *)entry->handle; 121182080Srnoland request->handle = entry->handle; 122145132Sanholt 123145132Sanholt DRM_LOCK(); 124145132Sanholt if (dev->sg) { 125145132Sanholt DRM_UNLOCK(); 126145132Sanholt drm_sg_cleanup(entry); 127145132Sanholt return EINVAL; 128145132Sanholt } 129145132Sanholt dev->sg = entry; 130145132Sanholt DRM_UNLOCK(); 131145132Sanholt 132145132Sanholt return 0; 133145132Sanholt} 134145132Sanholt 135186295Srnolandstatic void 136186295Srnolanddrm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 137145132Sanholt{ 138186295Srnoland struct drm_sg_mem *entry = arg; 139186295Srnoland int i; 140186295Srnoland 141186295Srnoland if (error != 0) 142186295Srnoland return; 143186295Srnoland 144186295Srnoland for(i = 0 ; i < nsegs ; i++) { 145186295Srnoland entry->busaddr[i] = segs[i].ds_addr; 146186295Srnoland } 147186295Srnoland} 148186295Srnoland 149186295Srnolandint 150186295Srnolanddrm_sg_alloc_ioctl(struct drm_device *dev, void *data, 151186295Srnoland struct drm_file *file_priv) 152186295Srnoland{ 153183573Srnoland struct drm_scatter_gather *request = data; 154182080Srnoland 155186295Srnoland DRM_DEBUG("\n"); 156182080Srnoland 157186295Srnoland return drm_sg_alloc(dev, request); 158182080Srnoland} 159182080Srnoland 160186295Srnolandvoid 161186295Srnolanddrm_sg_cleanup(struct drm_sg_mem *entry) 162182080Srnoland{ 163186295Srnoland struct drm_dma_handle *dmah = entry->sg_dmah; 164186295Srnoland 165186295Srnoland bus_dmamap_unload(dmah->tag, dmah->map); 166186295Srnoland bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); 167186295Srnoland bus_dma_tag_destroy(dmah->tag); 168186295Srnoland free(dmah, DRM_MEM_DMA); 169186295Srnoland free(entry->busaddr, DRM_MEM_PAGES); 170186295Srnoland free(entry, DRM_MEM_SGLISTS); 171186295Srnoland} 172186295Srnoland 173186295Srnolandint 174186295Srnolanddrm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv) 175186295Srnoland{ 176183573Srnoland struct drm_scatter_gather *request = data; 177186295Srnoland struct drm_sg_mem *entry; 178145132Sanholt 179145132Sanholt DRM_LOCK(); 180145132Sanholt entry = dev->sg; 181145132Sanholt dev->sg = NULL; 182145132Sanholt DRM_UNLOCK(); 183145132Sanholt 184183573Srnoland if (!entry || entry->handle != request->handle) 185145132Sanholt return EINVAL; 186145132Sanholt 187183573Srnoland DRM_DEBUG("sg free virtual = 0x%lx\n", entry->handle); 188145132Sanholt 189145132Sanholt drm_sg_cleanup(entry); 190145132Sanholt 191145132Sanholt return 0; 192145132Sanholt} 193