xref: /openbsd-src/sys/dev/pci/drm/drm_pci.c (revision 850e275390052b330d93020bf619a739a3c277ac)
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