1 /*- 2 * Copyright 2003 Eric Anholt. 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 THE 19 * AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24 #include "drmP.h" 25 26 /* 27 * Allocate a physically contiguous DMA-accessible consistent 28 * memory block. 29 */ 30 drm_dma_handle_t * 31 drm_pci_alloc(struct drm_device *dev, size_t size, size_t align, 32 dma_addr_t maxaddr) 33 { 34 drm_dma_handle_t *dmah; 35 int ret, nsegs; 36 37 /* Need power-of-two alignment, so fail the allocation if it isn't. */ 38 if ((align & (align - 1)) != 0) { 39 DRM_ERROR("drm_pci_alloc with non-power-of-two alignment %d\n", 40 (int)align); 41 return NULL; 42 } 43 44 dmah = drm_alloc(sizeof(*dmah), DRM_MEM_DMA); 45 if (dmah == NULL) 46 return NULL; 47 48 if (bus_dmamap_create(dev->pa.pa_dmat, size, 1, size, 0, 49 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &dmah->dmamap) != 0) 50 goto dmahfree; 51 52 if (bus_dmamem_alloc(dev->pa.pa_dmat, size, align, 0, 53 &dmah->seg, 1, &nsegs, BUS_DMA_NOWAIT) != 0) { 54 DRM_ERROR("bus_dmamem_alloc(%zd, %zd) returned %d\n", 55 size, align, ret); 56 goto destroy; 57 } 58 if (nsegs != 1) { 59 DRM_ERROR("bus_dmamem_alloc(%zd) returned %d segments\n", 60 size, nsegs); 61 goto free; 62 } 63 64 if (bus_dmamem_map(dev->pa.pa_dmat, &dmah->seg, 1, size, 65 (caddr_t*)&dmah->addr, BUS_DMA_NOWAIT) != 0) { 66 DRM_ERROR("bus_dmamem_map() failed %d\n", ret); 67 goto free; 68 } 69 70 if (bus_dmamap_load(dev->pa.pa_dmat, dmah->dmamap, dmah->addr, size, 71 NULL, BUS_DMA_NOWAIT) != 0) 72 goto unmap; 73 74 dmah->busaddr = dmah->dmamap->dm_segs[0].ds_addr; 75 dmah->vaddr = dmah->addr; 76 dmah->size = size; 77 78 return dmah; 79 80 unmap: 81 bus_dmamem_unmap(dev->pa.pa_dmat, dmah->addr, size); 82 free: 83 bus_dmamem_free(dev->pa.pa_dmat, &dmah->seg, 1); 84 destroy: 85 bus_dmamap_destroy(dev->pa.pa_dmat, dmah->dmamap); 86 dmahfree: 87 drm_free(dmah, sizeof(*dmah), DRM_MEM_DMA); 88 89 return (NULL); 90 91 } 92 93 /* 94 * Free a DMA-accessible consistent memory block. 95 */ 96 void 97 drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah) 98 { 99 if (dmah == NULL) 100 return; 101 102 bus_dmamap_unload(dev->pa.pa_dmat, dmah->dmamap); 103 bus_dmamem_unmap(dev->pa.pa_dmat, dmah->vaddr, dmah->size); 104 bus_dmamem_free(dev->pa.pa_dmat, &dmah->seg, 1); 105 bus_dmamap_destroy(dev->pa.pa_dmat, dmah->dmamap); 106 107 drm_free(dmah, sizeof(*dmah), DRM_MEM_DMA); 108 } 109