xref: /netbsd/sys/dev/vme/vme.c (revision bf9ec67e)
1 /* $NetBSD: vme.c,v 1.4 2001/11/13 06:17:08 lukem 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.4 2001/11/13 06:17:08 lukem 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