vme.c revision 1.3.14.1 1 /* $NetBSD: vme.c,v 1.3.14.1 2001/11/14 19:16:24 nathanw Exp $ */
2
3 /*
4 * Copyright (c) 1999
5 * Matthias Drochner. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: vme.c,v 1.3.14.1 2001/11/14 19:16:24 nathanw Exp $");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37 #include <sys/malloc.h>
38 #include <sys/extent.h>
39 #include <machine/bus.h>
40
41 #include <dev/vme/vmereg.h>
42 #include <dev/vme/vmevar.h>
43
44 static void vme_extractlocators __P((int*, struct vme_attach_args*));
45 static int vmeprint __P((struct vme_attach_args*, char*));
46 static int vmesubmatch1 __P((struct device*, struct cfdata*, void*));
47 static int vmesubmatch __P((struct device*, struct cfdata*, void*));
48 int vmematch __P((struct device *, struct cfdata *, void *));
49 void vmeattach __P((struct device*, struct device*,void*));
50 static struct extent *vme_select_map __P((struct vmebus_softc*, vme_am_t));
51
52 #ifdef notyet
53 int vmedetach __P((struct device*));
54 #endif
55
56 #define VME_SLAVE_DUMMYDRV "vme_slv"
57
58 #define VME_NUMCFRANGES 3 /* cf. "files.vme" */
59
60 struct cfattach vme_ca = {
61 sizeof(struct vmebus_softc), vmematch, vmeattach,
62 };
63
64 struct cfattach vme_slv_ca = {
65 0 /* never used */
66 };
67
68 static void
69 vme_extractlocators(loc, aa)
70 int *loc;
71 struct vme_attach_args *aa;
72 {
73 int i = 0;
74
75 /* XXX can't use constants in locators.h this way */
76
77 while (i < VME_NUMCFRANGES && i < VME_MAXCFRANGES &&
78 loc[i] != -1) {
79 aa->r[i].offset = (vme_addr_t)loc[i];
80 aa->r[i].size = (vme_size_t)loc[3 + i];
81 aa->r[i].am = (vme_am_t)loc[6 + i];
82 i++;
83 }
84 aa->numcfranges = i;
85 aa->ilevel = loc[9];
86 aa->ivector = loc[10];
87 }
88
89 static int
90 vmeprint(v, dummy)
91 struct vme_attach_args *v;
92 char *dummy;
93 {
94 int i;
95
96 for (i = 0; i < v->numcfranges; i++) {
97 printf(" addr %x", v->r[i].offset);
98 if (v->r[i].size != -1)
99 printf("-%x", v->r[i].offset + v->r[i].size - 1);
100 if (v->r[i].am != -1)
101 printf(" am %02x", v->r[i].am);
102 }
103 if (v->ilevel != -1) {
104 printf(" irq %d", v->ilevel);
105 if (v->ivector != -1)
106 printf(" vector %x", v->ivector);
107 }
108 return (UNCONF);
109 }
110
111 /*
112 * This looks for a (dummy) vme device "VME_SLAVE_DUMMYDRV".
113 * A callback provided by the bus's parent is called for every such
114 * entry in the config database.
115 * This is a special hack allowing to communicate the address settings
116 * of the VME master's slave side to its driver via the normal
117 * configuration mechanism.
118 * Needed in following cases:
119 * -DMA windows are hardware settable but not readable by software
120 * (driver gets offsets for DMA address calculations this way)
121 * -DMA windows are software settable, but not persistent
122 * (hardware is set up from config file entry)
123 * -other adapter VME slave ranges which should be kept track of
124 * for address space accounting
125 * In any case, the adapter driver must get the data before VME
126 * devices are attached.
127 */
128 static int
129 vmesubmatch1(bus, dev, aux)
130 struct device *bus;
131 struct cfdata *dev;
132 void *aux;
133 {
134 struct vmebus_softc *sc = (struct vmebus_softc*)bus;
135 struct vme_attach_args v;
136
137 if (strcmp(dev->cf_driver->cd_name, VME_SLAVE_DUMMYDRV))
138 return (0);
139
140 vme_extractlocators(dev->cf_loc, &v);
141
142 v.va_vct = sc->sc_vct; /* for space allocation */
143
144 (*sc->slaveconfig)(bus->dv_parent, &v);
145 return (0);
146 }
147
148 static int
149 vmesubmatch(bus, dev, aux)
150 struct device *bus;
151 struct cfdata *dev;
152 void *aux;
153 {
154 struct vmebus_softc *sc = (struct vmebus_softc*)bus;
155 struct vme_attach_args v;
156
157 if (!strcmp(dev->cf_driver->cd_name, VME_SLAVE_DUMMYDRV))
158 return (0);
159
160 vme_extractlocators(dev->cf_loc, &v);
161
162 v.va_vct = sc->sc_vct;
163 v.va_bdt = sc->sc_bdt;
164
165 if (dev->cf_attach->ca_match(bus, dev, &v)) {
166 config_attach(bus, dev, &v, (cfprint_t)vmeprint);
167 return (1);
168 }
169 return (0);
170 }
171
172 int
173 vmematch(parent, match, aux)
174 struct device *parent;
175 struct cfdata *match;
176 void *aux;
177 {
178 return (1);
179 }
180
181 void
182 vmeattach(parent, self, aux)
183 struct device *parent, *self;
184 void *aux;
185 {
186 struct vmebus_softc *sc = (struct vmebus_softc *)self;
187
188 struct vmebus_attach_args *aa =
189 (struct vmebus_attach_args*)aux;
190
191 sc->sc_vct = aa->va_vct;
192 sc->sc_bdt = aa->va_bdt;
193
194 /* the "bus" are we ourselves */
195 sc->sc_vct->bus = sc;
196
197 sc->slaveconfig = aa->va_slaveconfig;
198
199 printf("\n");
200
201 /*
202 * set up address space accounting - assume incomplete decoding
203 */
204 sc->vme32ext = extent_create("vme32", 0, 0xffffffff,
205 M_DEVBUF, 0, 0, 0);
206 if (!sc->vme32ext) {
207 printf("error creating A32 map\n");
208 return;
209 }
210
211 sc->vme24ext = extent_create("vme24", 0, 0x00ffffff,
212 M_DEVBUF, 0, 0, 0);
213 if (!sc->vme24ext) {
214 printf("error creating A24 map\n");
215 return;
216 }
217
218 sc->vme16ext = extent_create("vme16", 0, 0x0000ffff,
219 M_DEVBUF, 0, 0, 0);
220 if (!sc->vme16ext) {
221 printf("error creating A16 map\n");
222 return;
223 }
224
225 if (sc->slaveconfig) {
226 /* first get info about the bus master's slave side,
227 if present */
228 config_search((cfmatch_t)vmesubmatch1, self, 0);
229 }
230 config_search((cfmatch_t)vmesubmatch, self, 0);
231
232 #ifdef VMEDEBUG
233 if (sc->vme32ext)
234 extent_print(sc->vme32ext);
235 if (sc->vme24ext)
236 extent_print(sc->vme24ext);
237 if (sc->vme16ext)
238 extent_print(sc->vme16ext);
239 #endif
240 }
241
242 #ifdef notyet
243 int
244 vmedetach(dev)
245 struct device *dev;
246 {
247 struct vmebus_softc *sc = (struct vmebus_softc*)dev;
248
249 if (sc->slaveconfig) {
250 /* allow bus master to free its bus ressources */
251 (*sc->slaveconfig)(dev->dv_parent, 0);
252 }
253
254 /* extent maps should be empty now */
255
256 if (sc->vme32ext) {
257 #ifdef VMEDEBUG
258 extent_print(sc->vme32ext);
259 #endif
260 extent_destroy(sc->vme32ext);
261 }
262 if (sc->vme24ext) {
263 #ifdef VMEDEBUG
264 extent_print(sc->vme24ext);
265 #endif
266 extent_destroy(sc->vme24ext);
267 }
268 if (sc->vme16ext) {
269 #ifdef VMEDEBUG
270 extent_print(sc->vme16ext);
271 #endif
272 extent_destroy(sc->vme16ext);
273 }
274
275 return (0);
276 }
277 #endif
278
279 static struct extent *
280 vme_select_map(sc, ams)
281 struct vmebus_softc *sc;
282 vme_am_t ams;
283 {
284 if ((ams & VME_AM_ADRSIZEMASK) == VME_AM_A32)
285 return (sc->vme32ext);
286 else if ((ams & VME_AM_ADRSIZEMASK) == VME_AM_A24)
287 return (sc->vme24ext);
288 else if ((ams & VME_AM_ADRSIZEMASK) == VME_AM_A16)
289 return (sc->vme16ext);
290 else
291 return (0);
292 }
293
294 int
295 _vme_space_alloc(sc, addr, len, ams)
296 struct vmebus_softc *sc;
297 vme_addr_t addr;
298 vme_size_t len;
299 vme_am_t ams;
300 {
301 struct extent *ex;
302
303 ex = vme_select_map(sc, ams);
304 if (!ex)
305 return (EINVAL);
306
307 return (extent_alloc_region(ex, addr, len, EX_NOWAIT));
308 }
309
310 void
311 _vme_space_free(sc, addr, len, ams)
312 struct vmebus_softc *sc;
313 vme_addr_t addr;
314 vme_size_t len;
315 vme_am_t ams;
316 {
317 struct extent *ex;
318
319 ex = vme_select_map(sc, ams);
320 if (!ex) {
321 panic("vme_space_free: invalid am %x", ams);
322 return;
323 }
324
325 extent_free(ex, addr, len, EX_NOWAIT);
326 }
327
328 int
329 _vme_space_get(sc, len, ams, align, addr)
330 struct vmebus_softc *sc;
331 vme_size_t len;
332 vme_am_t ams;
333 u_long align;
334 vme_addr_t *addr;
335 {
336 struct extent *ex;
337
338 ex = vme_select_map(sc, ams);
339 if (!ex)
340 return (EINVAL);
341
342 return (extent_alloc(ex, len, align, EX_NOBOUNDARY, EX_NOWAIT,
343 (u_long *)addr));
344 }
345