drm_scatter.c revision 198694
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 198694 2009-10-30 18:02:10Z 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; 50186295Srnoland int ret; 51145132Sanholt 52183573Srnoland if (dev->sg) 53145132Sanholt return EINVAL; 54145132Sanholt 55183833Srnoland entry = malloc(sizeof(*entry), DRM_MEM_SGLISTS, M_WAITOK | M_ZERO); 56198694Srnoland entry->pages = round_page(request->size) / PAGE_SIZE; 57198694Srnoland DRM_DEBUG("sg size=%ld pages=%d\n", request->size, entry->pages); 58145132Sanholt 59198694Srnoland entry->busaddr = malloc(entry->pages * sizeof(*entry->busaddr), 60198694Srnoland DRM_MEM_PAGES, M_WAITOK | M_ZERO); 61198694Srnoland dmah = malloc(sizeof(struct drm_dma_handle), DRM_MEM_DMA, 62145132Sanholt M_WAITOK | M_ZERO); 63198694Srnoland entry->dmah = dmah; 64145132Sanholt 65186295Srnoland ret = bus_dma_tag_create(NULL, PAGE_SIZE, 0, /* tag, align, boundary */ 66186295Srnoland BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */ 67186295Srnoland NULL, NULL, /* filtfunc, filtfuncargs */ 68186295Srnoland request->size, pages, /* maxsize, nsegs */ 69186295Srnoland PAGE_SIZE, 0, /* maxsegsize, flags */ 70186295Srnoland NULL, NULL, /* lockfunc, lockfuncargs */ 71186295Srnoland &dmah->tag); 72186295Srnoland if (ret != 0) { 73198694Srnoland drm_sg_cleanup(entry); 74186295Srnoland return ENOMEM; 75152909Sanholt } 76145132Sanholt 77186295Srnoland ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr, 78190282Srnoland BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_NOCACHE, &dmah->map); 79186295Srnoland if (ret != 0) { 80198694Srnoland drm_sg_cleanup(entry); 81186295Srnoland return ENOMEM; 82186295Srnoland } 83186295Srnoland 84198694Srnoland entry->handle = (unsigned long)dmah->vaddr; 85198694Srnoland entry->virtual = dmah->vaddr; 86198694Srnoland 87186295Srnoland ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, 88190282Srnoland request->size, drm_sg_alloc_cb, entry, BUS_DMA_NOWAIT); 89186295Srnoland if (ret != 0) { 90198694Srnoland drm_sg_cleanup(entry); 91186295Srnoland return ENOMEM; 92186295Srnoland } 93186295Srnoland 94145132Sanholt DRM_LOCK(); 95145132Sanholt if (dev->sg) { 96145132Sanholt DRM_UNLOCK(); 97145132Sanholt drm_sg_cleanup(entry); 98145132Sanholt return EINVAL; 99145132Sanholt } 100145132Sanholt dev->sg = entry; 101145132Sanholt DRM_UNLOCK(); 102145132Sanholt 103198694Srnoland DRM_DEBUG("handle=%08lx, kva=%p, contents=%08lx\n", entry->handle, 104198694Srnoland entry->virtual, *(unsigned long *)entry->virtual); 105198694Srnoland 106198694Srnoland request->handle = entry->handle; 107198694Srnoland 108145132Sanholt return 0; 109145132Sanholt} 110145132Sanholt 111186295Srnolandstatic void 112186295Srnolanddrm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 113145132Sanholt{ 114186295Srnoland struct drm_sg_mem *entry = arg; 115186295Srnoland int i; 116186295Srnoland 117186295Srnoland if (error != 0) 118186295Srnoland return; 119186295Srnoland 120186295Srnoland for(i = 0 ; i < nsegs ; i++) { 121186295Srnoland entry->busaddr[i] = segs[i].ds_addr; 122198694Srnoland DRM_DEBUG("segment %d @ 0x%016lx\n", i, 123198694Srnoland (unsigned long)segs[i].ds_addr); 124186295Srnoland } 125186295Srnoland} 126186295Srnoland 127186295Srnolandint 128186295Srnolanddrm_sg_alloc_ioctl(struct drm_device *dev, void *data, 129186295Srnoland struct drm_file *file_priv) 130186295Srnoland{ 131183573Srnoland struct drm_scatter_gather *request = data; 132182080Srnoland 133186295Srnoland DRM_DEBUG("\n"); 134182080Srnoland 135186295Srnoland return drm_sg_alloc(dev, request); 136182080Srnoland} 137182080Srnoland 138186295Srnolandvoid 139186295Srnolanddrm_sg_cleanup(struct drm_sg_mem *entry) 140182080Srnoland{ 141190399Srnoland struct drm_dma_handle *dmah = entry->dmah; 142186295Srnoland 143198694Srnoland if (dmah->map != NULL) 144198694Srnoland bus_dmamap_unload(dmah->tag, dmah->map); 145198694Srnoland if (dmah->vaddr != NULL) 146198694Srnoland bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); 147198694Srnoland if (dmah->tag != NULL) 148198694Srnoland bus_dma_tag_destroy(dmah->tag); 149186295Srnoland free(dmah, DRM_MEM_DMA); 150186295Srnoland free(entry->busaddr, DRM_MEM_PAGES); 151186295Srnoland free(entry, DRM_MEM_SGLISTS); 152186295Srnoland} 153186295Srnoland 154186295Srnolandint 155186295Srnolanddrm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv) 156186295Srnoland{ 157183573Srnoland struct drm_scatter_gather *request = data; 158186295Srnoland struct drm_sg_mem *entry; 159145132Sanholt 160145132Sanholt DRM_LOCK(); 161145132Sanholt entry = dev->sg; 162145132Sanholt dev->sg = NULL; 163145132Sanholt DRM_UNLOCK(); 164145132Sanholt 165183573Srnoland if (!entry || entry->handle != request->handle) 166145132Sanholt return EINVAL; 167145132Sanholt 168183573Srnoland DRM_DEBUG("sg free virtual = 0x%lx\n", entry->handle); 169145132Sanholt 170145132Sanholt drm_sg_cleanup(entry); 171145132Sanholt 172145132Sanholt return 0; 173145132Sanholt} 174