xref: /netbsd/sys/dev/vme/vme.c (revision c4a72b64)
1 /* $NetBSD: vme.c,v 1.9 2002/10/02 16:53:13 thorpej 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.9 2002/10/02 16:53:13 thorpej 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 CFATTACH_DECL(vme, sizeof(struct vmebus_softc),
61     vmematch, vmeattach, NULL, NULL);
62 
63 const struct cfattach vme_slv_ca = {
64 	0	/* never used */
65 };
66 
67 static void
68 vme_extractlocators(loc, aa)
69 	int *loc;
70 	struct vme_attach_args *aa;
71 {
72 	int i = 0;
73 
74 	/* XXX can't use constants in locators.h this way */
75 
76 	while (i < VME_NUMCFRANGES && i < VME_MAXCFRANGES &&
77 	       loc[i] != -1) {
78 		aa->r[i].offset = (vme_addr_t)loc[i];
79 		aa->r[i].size = (vme_size_t)loc[3 + i];
80 		aa->r[i].am = (vme_am_t)loc[6 + i];
81 		i++;
82 	}
83 	aa->numcfranges = i;
84 	aa->ilevel = loc[9];
85 	aa->ivector = loc[10];
86 }
87 
88 static int
89 vmeprint(v, dummy)
90 	struct vme_attach_args *v;
91 	char *dummy;
92 {
93 	int i;
94 
95 	for (i = 0; i < v->numcfranges; i++) {
96 		printf(" addr %x", v->r[i].offset);
97 		if (v->r[i].size != -1)
98 			printf("-%x", v->r[i].offset + v->r[i].size - 1);
99 		if (v->r[i].am != -1)
100 			printf(" am %02x", v->r[i].am);
101 	}
102 	if (v->ilevel != -1) {
103 		printf(" irq %d", v->ilevel);
104 		if (v->ivector != -1)
105 			printf(" vector %x", v->ivector);
106 	}
107 	return (UNCONF);
108 }
109 
110 /*
111  * This looks for a (dummy) vme device "VME_SLAVE_DUMMYDRV".
112  * A callback provided by the bus's parent is called for every such
113  * entry in the config database.
114  * This is a special hack allowing to communicate the address settings
115  * of the VME master's slave side to its driver via the normal
116  * configuration mechanism.
117  * Needed in following cases:
118  *  -DMA windows are hardware settable but not readable by software
119  *   (driver gets offsets for DMA address calculations this way)
120  *  -DMA windows are software settable, but not persistent
121  *   (hardware is set up from config file entry)
122  *  -other adapter VME slave ranges which should be kept track of
123  *   for address space accounting
124  * In any case, the adapter driver must get the data before VME
125  * devices are attached.
126  */
127 static int
128 vmesubmatch1(bus, dev, aux)
129 	struct device *bus;
130 	struct cfdata *dev;
131 	void *aux;
132 {
133 	struct vmebus_softc *sc = (struct vmebus_softc*)bus;
134 	struct vme_attach_args v;
135 
136 	if (strcmp(dev->cf_name, VME_SLAVE_DUMMYDRV))
137 		return (0);
138 
139 	vme_extractlocators(dev->cf_loc, &v);
140 
141 	v.va_vct = sc->sc_vct; /* for space allocation */
142 
143 	(*sc->slaveconfig)(bus->dv_parent, &v);
144 	return (0);
145 }
146 
147 static int
148 vmesubmatch(bus, dev, aux)
149 	struct device *bus;
150 	struct cfdata *dev;
151 	void *aux;
152 {
153 	struct vmebus_softc *sc = (struct vmebus_softc*)bus;
154 	struct vme_attach_args v;
155 
156 	if (!strcmp(dev->cf_name, VME_SLAVE_DUMMYDRV))
157 		return (0);
158 
159 	vme_extractlocators(dev->cf_loc, &v);
160 
161 	v.va_vct = sc->sc_vct;
162 	v.va_bdt = sc->sc_bdt;
163 
164 	if (config_match(bus, dev, &v)) {
165 		config_attach(bus, dev, &v, (cfprint_t)vmeprint);
166 		return (1);
167 	}
168 	return (0);
169 }
170 
171 int
172 vmematch(parent, match, aux)
173 	struct device *parent;
174 	struct cfdata *match;
175 	void *aux;
176 {
177 	return (1);
178 }
179 
180 void
181 vmeattach(parent, self, aux)
182 	struct device *parent, *self;
183 	void *aux;
184 {
185 	struct vmebus_softc *sc = (struct vmebus_softc *)self;
186 
187 	struct vmebus_attach_args *aa =
188 	    (struct vmebus_attach_args*)aux;
189 
190 	sc->sc_vct = aa->va_vct;
191 	sc->sc_bdt = aa->va_bdt;
192 
193 	/* the "bus" are we ourselves */
194 	sc->sc_vct->bus = sc;
195 
196 	sc->slaveconfig = aa->va_slaveconfig;
197 
198 	printf("\n");
199 
200 	/*
201 	 * set up address space accounting - assume incomplete decoding
202 	 */
203 	sc->vme32ext = extent_create("vme32", 0, 0xffffffff,
204 				     M_DEVBUF, 0, 0, 0);
205 	if (!sc->vme32ext) {
206 		printf("error creating A32 map\n");
207 		return;
208 	}
209 
210 	sc->vme24ext = extent_create("vme24", 0, 0x00ffffff,
211 				     M_DEVBUF, 0, 0, 0);
212 	if (!sc->vme24ext) {
213 		printf("error creating A24 map\n");
214 		return;
215 	}
216 
217 	sc->vme16ext = extent_create("vme16", 0, 0x0000ffff,
218 				     M_DEVBUF, 0, 0, 0);
219 	if (!sc->vme16ext) {
220 		printf("error creating A16 map\n");
221 		return;
222 	}
223 
224 	if (sc->slaveconfig) {
225 		/* first get info about the bus master's slave side,
226 		 if present */
227 		config_search((cfmatch_t)vmesubmatch1, self, 0);
228 	}
229 	config_search((cfmatch_t)vmesubmatch, self, 0);
230 
231 #ifdef VMEDEBUG
232 	if (sc->vme32ext)
233 		extent_print(sc->vme32ext);
234 	if (sc->vme24ext)
235 		extent_print(sc->vme24ext);
236 	if (sc->vme16ext)
237 		extent_print(sc->vme16ext);
238 #endif
239 }
240 
241 #ifdef notyet
242 int
243 vmedetach(dev)
244 	struct device *dev;
245 {
246 	struct vmebus_softc *sc = (struct vmebus_softc*)dev;
247 
248 	if (sc->slaveconfig) {
249 		/* allow bus master to free its bus ressources */
250 		(*sc->slaveconfig)(dev->dv_parent, 0);
251 	}
252 
253 	/* extent maps should be empty now */
254 
255 	if (sc->vme32ext) {
256 #ifdef VMEDEBUG
257 		extent_print(sc->vme32ext);
258 #endif
259 		extent_destroy(sc->vme32ext);
260 	}
261 	if (sc->vme24ext) {
262 #ifdef VMEDEBUG
263 		extent_print(sc->vme24ext);
264 #endif
265 		extent_destroy(sc->vme24ext);
266 	}
267 	if (sc->vme16ext) {
268 #ifdef VMEDEBUG
269 		extent_print(sc->vme16ext);
270 #endif
271 		extent_destroy(sc->vme16ext);
272 	}
273 
274 	return (0);
275 }
276 #endif
277 
278 static struct extent *
279 vme_select_map(sc, ams)
280 	struct vmebus_softc *sc;
281 	vme_am_t ams;
282 {
283 	if ((ams & VME_AM_ADRSIZEMASK) == VME_AM_A32)
284 		return (sc->vme32ext);
285 	else if ((ams & VME_AM_ADRSIZEMASK) == VME_AM_A24)
286 		return (sc->vme24ext);
287 	else if ((ams & VME_AM_ADRSIZEMASK) == VME_AM_A16)
288 		return (sc->vme16ext);
289 	else
290 		return (0);
291 }
292 
293 int
294 _vme_space_alloc(sc, addr, len, ams)
295 	struct vmebus_softc *sc;
296 	vme_addr_t addr;
297 	vme_size_t len;
298 	vme_am_t ams;
299 {
300 	struct extent *ex;
301 
302 	ex = vme_select_map(sc, ams);
303 	if (!ex)
304 		return (EINVAL);
305 
306 	return (extent_alloc_region(ex, addr, len, EX_NOWAIT));
307 }
308 
309 void
310 _vme_space_free(sc, addr, len, ams)
311 	struct vmebus_softc *sc;
312 	vme_addr_t addr;
313 	vme_size_t len;
314 	vme_am_t ams;
315 {
316 	struct extent *ex;
317 
318 	ex = vme_select_map(sc, ams);
319 	if (!ex) {
320 		panic("vme_space_free: invalid am %x", ams);
321 		return;
322 	}
323 
324 	extent_free(ex, addr, len, EX_NOWAIT);
325 }
326 
327 int
328 _vme_space_get(sc, len, ams, align, addr)
329 	struct vmebus_softc *sc;
330 	vme_size_t len;
331 	vme_am_t ams;
332 	u_long align;
333 	vme_addr_t *addr;
334 {
335 	struct extent *ex;
336 
337 	ex = vme_select_map(sc, ams);
338 	if (!ex)
339 		return (EINVAL);
340 
341 	return (extent_alloc(ex, len, align, EX_NOBOUNDARY, EX_NOWAIT,
342 			     (u_long *)addr));
343 }
344