drm_memory.c revision 1.1.2.1 1 /* $NetBSD: drm_memory.c,v 1.1.2.1 2013/07/24 02:23:06 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2013 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Taylor R. Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: drm_memory.c,v 1.1.2.1 2013/07/24 02:23:06 riastradh Exp $");
34
35 /* XXX Cargo-culted from the old drm_memory.c. */
36
37 #ifdef _KERNEL_OPT
38 #include "agp_i810.h"
39 #include "genfb.h"
40 #else
41 #define NAGP_I810 1 /* XXX WTF? */
42 #define NGENFB 0 /* XXX WTF? */
43 #endif
44
45 #include <sys/bus.h>
46
47 #if NAGP_I810 > 0
48 /* XXX include order botch -- shouldn't need to include pcivar.h */
49 #include <dev/pci/pcivar.h>
50 #include <dev/pci/agpvar.h>
51 #endif
52
53 #if NGENFB > 0
54 #include <dev/wsfb/genfbvar.h>
55 #endif
56
57 #include <drm/drmP.h>
58
59 /*
60 * XXX drm_bus_borrow is a horrible kludge!
61 */
62 static bool
63 drm_bus_borrow(bus_addr_t base, bus_space_handle_t *handlep)
64 {
65
66 #if NAGP_I810 > 0
67 if (agp_i810_borrow(base, handlep))
68 return true;
69 #endif
70
71 #if NGENFB > 0
72 if (genfb_borrow(base, handlep))
73 return true;
74 #endif
75
76 return false;
77 }
78
79 void *
80 drm_ioremap(struct drm_device *dev, struct drm_local_map *map)
81 {
82 const bus_space_tag_t bst = dev->bst;
83 unsigned int unit;
84 int error;
85
86 /*
87 * Search dev's bus maps for a match.
88 */
89 for (unit = 0; unit < dev->bus_nmaps; unit++) {
90 struct drm_bus_map *const bm = &dev->bus_maps[unit];
91
92 /* Reject maps starting after the request. */
93 if (map->offset < bm->bm_base)
94 continue;
95
96 /* Reject maps smaller than the request. */
97 if (bm->bm_size < map->size)
98 continue;
99
100 /*
101 * Reject maps that the request doesn't fit in. (Make
102 * sure to avoid integer overflow.)
103 */
104 if ((bm->bm_size - map->size) <
105 (map->offset - bm->bm_base))
106 continue;
107
108 /* Has it been mapped yet? If not, map it. */
109 if (bm->bm_mapped == 0) {
110 KASSERT(ISSET(bm->bm_flags, BUS_SPACE_MAP_LINEAR));
111 error = bus_space_map(bst, bm->bm_base,
112 bm->bm_size, bm->bm_flags, &bm->bm_bsh);
113 if (error) {
114 if (drm_bus_borrow(map->offset, &map->bsh)) {
115 map->bus_map = NULL;
116 goto win;
117 }
118 return NULL;
119 }
120 }
121
122 /* Mark it used and make a subregion just for the request. */
123 bm->bm_mapped++;
124 error = bus_space_subregion(bst, bm->bm_bsh,
125 map->offset - bm->bm_base, map->size, &map->bsh);
126 if (error) {
127 /*
128 * Back out: unmark it and, if nobody else was
129 * using it, unmap it.
130 */
131 if (--bm->bm_mapped == 0)
132 bus_space_unmap(bst, bm->bm_bsh,
133 bm->bm_size);
134 return NULL;
135 }
136
137 /* Got it! */
138 map->bus_map = bm;
139 goto win;
140 }
141
142 /*
143 * No dice. Try mapping it directly ourselves.
144 *
145 * XXX Is this sensible? What prevents us from clobbering some
146 * existing map? And what does this have to do with agp?
147 */
148 for (unit = 0; unit < dev->agp_nmaps; unit++) {
149 struct drm_bus_map *const bm = &dev->agp_maps[unit];
150
151 /* Is this one allocated? */
152 if (bm->bm_mapped > 0) {
153 /*
154 * Make sure it has the same base.
155 *
156 * XXX Why must it be the same base? Can't we
157 * subregion here too?
158 */
159 if (bm->bm_base != map->offset)
160 continue;
161
162 /* Make sure it's big enough. */
163 if (bm->bm_size < map->size)
164 continue;
165
166 /* Mark it used and return it. */
167 bm->bm_mapped++;
168
169 /* XXX size is an input/output parameter too...? */
170 map->size = bm->bm_size;
171
172 map->bsh = bm->bm_bsh;
173 map->bus_map = bm;
174 goto win;
175 } else {
176 const int flags = BUS_SPACE_MAP_PREFETCHABLE |
177 BUS_SPACE_MAP_LINEAR;
178
179 /* Try mapping the request. */
180 error = bus_space_map(bst, map->offset, map->size,
181 flags, &bm->bm_bsh);
182 if (error)
183 return NULL; /* XXX Why not continue? */
184
185 /* Got it. Allocate this bus map. */
186 bm->bm_mapped++;
187 bm->bm_base = map->offset;
188 bm->bm_size = map->size;
189 bm->bm_flags = flags; /* XXX What for? */
190
191 map->bsh = bm->bm_bsh;
192 map->bus_map = bm;
193 goto win;
194 }
195 }
196
197 return NULL;
198
199 win:
200 return bus_space_vaddr(bst, map->bsh);
201 }
202
203 void
204 drm_iounmap(struct drm_device *dev, struct drm_local_map *map)
205 {
206 const bus_space_tag_t bst = dev->bst;
207 struct drm_bus_map *const bm = map->bus_map;
208
209 /*
210 * bm may be null if we have committed the horrible deed of
211 * borrowing from agp_i810 or genfb.
212 */
213 if (bm != NULL) {
214 KASSERT(bm->bm_mapped > 0);
215 if (--bm->bm_mapped)
216 bus_space_unmap(bst, bm->bm_bsh, bm->bm_size);
217 }
218 }
219