]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/drm/drm_scatter.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / drm / drm_scatter.c
1 /*-
2  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
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
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.
23  *
24  * Authors:
25  *   Gareth Hughes <gareth@valinux.com>
26  *   Eric Anholt <anholt@FreeBSD.org>
27  *
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 /** @file drm_scatter.c
34  * Allocation of memory for scatter-gather mappings by the graphics chip.
35  *
36  * The memory allocated here is then made into an aperture in the card
37  * by drm_ati_pcigart_init().
38  */
39
40 #include "dev/drm/drmP.h"
41
42 static void drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs,
43                             int nsegs, int error);
44
45 int
46 drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather *request)
47 {
48         struct drm_sg_mem *entry;
49         struct drm_dma_handle *dmah;
50         unsigned long pages;
51         int ret;
52
53         if (dev->sg)
54                 return EINVAL;
55
56         entry = malloc(sizeof(*entry), DRM_MEM_SGLISTS, M_WAITOK | M_ZERO);
57         if (!entry)
58                 return ENOMEM;
59
60         pages = round_page(request->size) / PAGE_SIZE;
61         DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages);
62
63         entry->pages = pages;
64
65         entry->busaddr = malloc(pages * sizeof(*entry->busaddr), DRM_MEM_PAGES,
66             M_WAITOK | M_ZERO);
67         if (!entry->busaddr) {
68                 free(entry, DRM_MEM_SGLISTS);
69                 return ENOMEM;
70         }
71
72         dmah = malloc(sizeof(struct drm_dma_handle), DRM_MEM_DMA,
73             M_ZERO | M_NOWAIT);
74         if (dmah == NULL) {
75                 free(entry->busaddr, DRM_MEM_PAGES);
76                 free(entry, DRM_MEM_SGLISTS);
77                 return ENOMEM;
78         }
79
80         ret = bus_dma_tag_create(NULL, PAGE_SIZE, 0, /* tag, align, boundary */
81             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */
82             NULL, NULL, /* filtfunc, filtfuncargs */
83             request->size, pages, /* maxsize, nsegs */
84             PAGE_SIZE, 0, /* maxsegsize, flags */
85             NULL, NULL, /* lockfunc, lockfuncargs */
86             &dmah->tag);
87         if (ret != 0) {
88                 free(dmah, DRM_MEM_DMA);
89                 free(entry->busaddr, DRM_MEM_PAGES);
90                 free(entry, DRM_MEM_SGLISTS);
91                 return ENOMEM;
92         }
93
94         ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr,
95             BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_NOCACHE, &dmah->map);
96         if (ret != 0) {
97                 bus_dma_tag_destroy(dmah->tag);
98                 free(dmah, DRM_MEM_DMA);
99                 free(entry->busaddr, DRM_MEM_PAGES);
100                 free(entry, DRM_MEM_SGLISTS);
101                 return ENOMEM;
102         }
103
104         ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr,
105             request->size, drm_sg_alloc_cb, entry, BUS_DMA_NOWAIT);
106         if (ret != 0) {
107                 bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
108                 bus_dma_tag_destroy(dmah->tag);
109                 free(dmah, DRM_MEM_DMA);
110                 free(entry->busaddr, DRM_MEM_PAGES);
111                 free(entry, DRM_MEM_SGLISTS);
112                 return ENOMEM;
113         }
114
115         entry->dmah = dmah;
116         entry->handle = (unsigned long)dmah->vaddr;
117         
118         DRM_DEBUG("sg alloc handle  = %08lx\n", entry->handle);
119
120         entry->virtual = (void *)entry->handle;
121         request->handle = entry->handle;
122
123         DRM_LOCK();
124         if (dev->sg) {
125                 DRM_UNLOCK();
126                 drm_sg_cleanup(entry);
127                 return EINVAL;
128         }
129         dev->sg = entry;
130         DRM_UNLOCK();
131
132         return 0;
133 }
134
135 static void
136 drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
137 {
138         struct drm_sg_mem *entry = arg;
139         int i;
140
141         if (error != 0)
142             return;
143
144         for(i = 0 ; i < nsegs ; i++) {
145                 entry->busaddr[i] = segs[i].ds_addr;
146         }
147 }
148
149 int
150 drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
151                    struct drm_file *file_priv)
152 {
153         struct drm_scatter_gather *request = data;
154
155         DRM_DEBUG("\n");
156
157         return drm_sg_alloc(dev, request);
158 }
159
160 void
161 drm_sg_cleanup(struct drm_sg_mem *entry)
162 {
163         struct drm_dma_handle *dmah = entry->dmah;
164
165         bus_dmamap_unload(dmah->tag, dmah->map);
166         bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
167         bus_dma_tag_destroy(dmah->tag);
168         free(dmah, DRM_MEM_DMA);
169         free(entry->busaddr, DRM_MEM_PAGES);
170         free(entry, DRM_MEM_SGLISTS);
171 }
172
173 int
174 drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
175 {
176         struct drm_scatter_gather *request = data;
177         struct drm_sg_mem *entry;
178
179         DRM_LOCK();
180         entry = dev->sg;
181         dev->sg = NULL;
182         DRM_UNLOCK();
183
184         if (!entry || entry->handle != request->handle)
185                 return EINVAL;
186
187         DRM_DEBUG("sg free virtual = 0x%lx\n", entry->handle);
188
189         drm_sg_cleanup(entry);
190
191         return 0;
192 }