Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / external / bsd / drm / dist / bsd-core / drm_scatter.c
blob631d6cde54cdc87ac251158da6662a12ef5f69b7
1 /*-
2 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
3 * All Rights Reserved.
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:
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.
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
19 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
24 * Authors:
25 * Gareth Hughes <gareth@valinux.com>
26 * Eric Anholt <anholt@FreeBSD.org>
30 /** @file drm_scatter.c
31 * Allocation of memory for scatter-gather mappings by the graphics chip.
33 * The memory allocated here is then made into an aperture in the card
34 * by drm_ati_pcigart_init().
37 #include "drmP.h"
39 #if defined(__FreeBSD__)
40 static void drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs,
41 int nsegs, int error);
42 #endif
44 int
45 drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather *request)
47 struct drm_sg_mem *entry;
48 struct drm_dma_handle *dmah;
49 unsigned long pages;
50 int ret;
51 #if defined(__NetBSD__)
52 int nsegs, i, npage;
53 #endif
55 if (dev->sg)
56 return EINVAL;
58 entry = malloc(sizeof(*entry), DRM_MEM_SGLISTS, M_WAITOK | M_ZERO);
59 if (!entry)
60 return ENOMEM;
62 pages = round_page(request->size) / PAGE_SIZE;
63 DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages);
65 entry->pages = pages;
67 entry->busaddr = malloc(pages * sizeof(*entry->busaddr), DRM_MEM_PAGES,
68 M_WAITOK | M_ZERO);
69 if (!entry->busaddr) {
70 free(entry, DRM_MEM_SGLISTS);
71 return ENOMEM;
74 #if defined(__FreeBSD__)
75 dmah = malloc(sizeof(struct drm_dma_handle), DRM_MEM_DMA,
76 M_ZERO | M_NOWAIT);
77 if (dmah == NULL) {
78 free(entry->busaddr, DRM_MEM_PAGES);
79 free(entry, DRM_MEM_SGLISTS);
80 return ENOMEM;
83 ret = bus_dma_tag_create(NULL, PAGE_SIZE, 0, /* tag, align, boundary */
84 BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */
85 NULL, NULL, /* filtfunc, filtfuncargs */
86 request->size, pages, /* maxsize, nsegs */
87 PAGE_SIZE, 0, /* maxsegsize, flags */
88 NULL, NULL, /* lockfunc, lockfuncargs */
89 &dmah->tag);
90 if (ret != 0) {
91 free(dmah, DRM_MEM_DMA);
92 free(entry->busaddr, DRM_MEM_PAGES);
93 free(entry, DRM_MEM_SGLISTS);
94 return ENOMEM;
97 ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr,
98 BUS_DMA_WAITOK | BUS_DMA_ZERO, &dmah->map);
99 if (ret != 0) {
100 bus_dma_tag_destroy(dmah->tag);
101 free(dmah, DRM_MEM_DMA);
102 free(entry->busaddr, DRM_MEM_PAGES);
103 free(entry, DRM_MEM_SGLISTS);
104 return ENOMEM;
107 ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr,
108 request->size, drm_sg_alloc_cb, entry,
109 BUS_DMA_NOWAIT | BUS_DMA_NOCACHE);
110 if (ret != 0) {
111 bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
112 bus_dma_tag_destroy(dmah->tag);
113 free(dmah, DRM_MEM_DMA);
114 free(entry->busaddr, DRM_MEM_PAGES);
115 free(entry, DRM_MEM_SGLISTS);
116 return ENOMEM;
118 #elif defined(__NetBSD__)
119 dmah = malloc(sizeof(struct drm_dma_handle) +
120 (pages - 1) * sizeof(bus_dma_segment_t),
121 DRM_MEM_DMA, M_ZERO | M_NOWAIT);
122 if (dmah == NULL) {
123 free(entry->busaddr, DRM_MEM_PAGES);
124 free(entry, DRM_MEM_SGLISTS);
125 return ENOMEM;
128 dmah->tag = dev->pa.pa_dmat;
130 if ((ret = bus_dmamem_alloc(dmah->tag, request->size, PAGE_SIZE, 0,
131 dmah->segs, pages, &nsegs,
132 BUS_DMA_WAITOK) != 0)) {
133 printf("drm: Unable to allocate %lu bytes of DMA, error %d\n",
134 request->size, ret);
135 dmah->tag = NULL;
136 free(dmah, DRM_MEM_DMA);
137 free(entry->busaddr, DRM_MEM_PAGES);
138 free(entry, DRM_MEM_SGLISTS);
139 return ENOMEM;
141 DRM_DEBUG("nsegs = %d\n", nsegs);
142 dmah->nsegs = nsegs;
143 if ((ret = bus_dmamem_map(dmah->tag, dmah->segs, nsegs, request->size,
144 &dmah->vaddr, BUS_DMA_NOWAIT |
145 BUS_DMA_NOCACHE | BUS_DMA_COHERENT)) != 0) {
146 printf("drm: Unable to map DMA, error %d\n", ret);
147 bus_dmamem_free(dmah->tag, dmah->segs, dmah->nsegs);
148 dmah->tag = NULL;
149 free(dmah, DRM_MEM_DMA);
150 free(entry->busaddr, DRM_MEM_PAGES);
151 free(entry, DRM_MEM_SGLISTS);
152 return ENOMEM;
154 if ((ret = bus_dmamap_create(dmah->tag, request->size, nsegs,
155 request->size, 0, BUS_DMA_NOWAIT,
156 &dmah->map)) != 0) {
157 printf("drm: Unable to create DMA map, error %d\n", ret);
158 bus_dmamem_unmap(dmah->tag, dmah->vaddr, request->size);
159 bus_dmamem_free(dmah->tag, dmah->segs, nsegs);
160 dmah->tag = NULL;
161 free(dmah, DRM_MEM_DMA);
162 free(entry->busaddr, DRM_MEM_PAGES);
163 free(entry, DRM_MEM_SGLISTS);
164 return ENOMEM;
166 if ((ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr,
167 request->size, NULL,
168 BUS_DMA_NOWAIT | BUS_DMA_NOCACHE)) != 0) {
169 printf("drm: Unable to load DMA map, error %d\n", ret);
170 bus_dmamap_destroy(dmah->tag, dmah->map);
171 bus_dmamem_unmap(dmah->tag, dmah->vaddr, request->size);
172 bus_dmamem_free(dmah->tag, dmah->segs, dmah->nsegs);
173 dmah->tag = NULL;
174 free(dmah, DRM_MEM_DMA);
175 return ENOMEM;
178 * We are expected to return address for each page here.
179 * If bus_dmamem_alloc did not return each page in own segment
180 * (likely not), split them as if they were separate segments.
182 for (i = 0, npage = 0 ; (i < nsegs) && (npage < pages) ; i++) {
183 bus_addr_t base = dmah->map->dm_segs[i].ds_addr;
184 bus_size_t offs;
186 for (offs = 0;
187 (offs + PAGE_SIZE <= dmah->map->dm_segs[i].ds_len) &&
188 (npage < pages);
189 offs += PAGE_SIZE)
190 entry->busaddr[npage++] = base + offs;
192 KASSERT(i == nsegs);
193 KASSERT(npage == pages);
194 dmah->size = request->size;
195 memset(dmah->vaddr, 0, request->size);
196 #endif
198 entry->sg_dmah = dmah;
199 entry->handle = (unsigned long)dmah->vaddr;
201 DRM_DEBUG("sg alloc handle = %08lx\n", entry->handle);
203 entry->virtual = (void *)entry->handle;
204 request->handle = entry->handle;
206 DRM_LOCK();
207 if (dev->sg) {
208 DRM_UNLOCK();
209 drm_sg_cleanup(entry);
210 return EINVAL;
212 dev->sg = entry;
213 DRM_UNLOCK();
215 return 0;
218 #if defined(__FreeBSD__)
219 static void
220 drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
222 struct drm_sg_mem *entry = arg;
223 int i;
225 if (error != 0)
226 return;
228 for(i = 0 ; i < nsegs ; i++) {
229 entry->busaddr[i] = segs[i].ds_addr;
232 #endif
235 drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
236 struct drm_file *file_priv)
238 struct drm_scatter_gather *request = data;
240 DRM_DEBUG("\n");
242 return drm_sg_alloc(dev, request);
245 void
246 drm_sg_cleanup(struct drm_sg_mem *entry)
248 struct drm_dma_handle *dmah = entry->sg_dmah;
250 #if defined(__FreeBSD__)
251 bus_dmamap_unload(dmah->tag, dmah->map);
252 bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
253 bus_dma_tag_destroy(dmah->tag);
254 #elif defined(__NetBSD__)
255 bus_dmamap_unload(dmah->tag, dmah->map);
256 bus_dmamap_destroy(dmah->tag, dmah->map);
257 bus_dmamem_unmap(dmah->tag, dmah->vaddr, dmah->size);
258 bus_dmamem_free(dmah->tag, dmah->segs, dmah->nsegs);
259 dmah->tag = NULL;
260 #endif
261 free(dmah, DRM_MEM_DMA);
262 free(entry->busaddr, DRM_MEM_PAGES);
263 free(entry, DRM_MEM_SGLISTS);
267 drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
269 struct drm_scatter_gather *request = data;
270 struct drm_sg_mem *entry;
272 DRM_LOCK();
273 entry = dev->sg;
274 dev->sg = NULL;
275 DRM_UNLOCK();
277 if (!entry || entry->handle != request->handle)
278 return EINVAL;
280 DRM_DEBUG("sg free virtual = 0x%lx\n", entry->handle);
282 drm_sg_cleanup(entry);
284 return 0;