xref: /openbsd/sys/arch/sparc64/dev/ebus.c (revision db3296cf)
1 /*	$OpenBSD: ebus.c,v 1.12 2003/06/12 05:57:43 henric Exp $	*/
2 /*	$NetBSD: ebus.c,v 1.24 2001/07/25 03:49:54 eeh Exp $	*/
3 
4 /*
5  * Copyright (c) 1999, 2000 Matthew R. Green
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * UltraSPARC 5 and beyond ebus support.
34  *
35  * note that this driver is not complete:
36  *	- ebus2 dma code is completely unwritten
37  *	- interrupt establish is written and appears to work
38  *	- bus map code is written and appears to work
39  */
40 
41 #ifdef DEBUG
42 #define	EDB_PROM	0x01
43 #define EDB_CHILD	0x02
44 #define	EDB_INTRMAP	0x04
45 #define EDB_BUSMAP	0x08
46 #define EDB_BUSDMA	0x10
47 #define EDB_INTR	0x20
48 int ebus_debug = 0x0;
49 #define DPRINTF(l, s)   do { if (ebus_debug & l) printf s; } while (0)
50 #else
51 #define DPRINTF(l, s)
52 #endif
53 
54 #include <sys/param.h>
55 #include <sys/conf.h>
56 #include <sys/device.h>
57 #include <sys/errno.h>
58 #include <sys/extent.h>
59 #include <sys/malloc.h>
60 #include <sys/systm.h>
61 #include <sys/time.h>
62 
63 #define _SPARC_BUS_DMA_PRIVATE
64 #include <machine/bus.h>
65 #include <machine/autoconf.h>
66 #include <machine/openfirm.h>
67 
68 #include <dev/pci/pcivar.h>
69 #include <dev/pci/pcireg.h>
70 #include <dev/pci/pcidevs.h>
71 
72 #include <sparc64/dev/iommureg.h>
73 #include <sparc64/dev/iommuvar.h>
74 #include <sparc64/dev/psychoreg.h>
75 #include <sparc64/dev/psychovar.h>
76 #include <sparc64/dev/ebusreg.h>
77 #include <sparc64/dev/ebusvar.h>
78 #include <sparc64/sparc64/cache.h>
79 
80 int	ebus_match(struct device *, void *, void *);
81 void	ebus_attach(struct device *, struct device *, void *);
82 
83 struct cfattach ebus_ca = {
84 	sizeof(struct ebus_softc), ebus_match, ebus_attach
85 };
86 
87 struct cfdriver ebus_cd = {
88 	NULL, "ebus", DV_DULL
89 };
90 
91 
92 int	ebus_setup_attach_args(struct ebus_softc *, int,
93 	    struct ebus_attach_args *);
94 void	ebus_destroy_attach_args(struct ebus_attach_args *);
95 int	ebus_print(void *, const char *);
96 void	ebus_find_ino(struct ebus_softc *, struct ebus_attach_args *);
97 int	ebus_find_node(struct pci_attach_args *);
98 
99 /*
100  * here are our bus space and bus dma routines.
101  */
102 static paddr_t ebus_bus_mmap(bus_space_tag_t, bus_space_tag_t, bus_addr_t,
103     off_t, int, int);
104 static int _ebus_bus_map(bus_space_tag_t, bus_space_tag_t, bus_addr_t,
105     bus_size_t, int, bus_space_handle_t *);
106 bus_space_tag_t ebus_alloc_mem_tag(struct ebus_softc *, bus_space_tag_t);
107 bus_space_tag_t ebus_alloc_io_tag(struct ebus_softc *, bus_space_tag_t);
108 bus_space_tag_t _ebus_alloc_bus_tag(struct ebus_softc *sc, const char *,
109     bus_space_tag_t, int);
110 
111 
112 int
113 ebus_match(struct device *parent, void *match, void *aux)
114 {
115 	struct pci_attach_args *pa = aux;
116 	char name[10];
117 	int node;
118 
119 	/* Only attach if there's a PROM node. */
120 	node = PCITAG_NODE(pa->pa_tag);
121 	if (node == -1) return (0);
122 
123 	/* Match a real ebus */
124 	OF_getprop(node, "name", &name, sizeof(name));
125 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
126 	    PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN &&
127 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_EBUS &&
128 		strcmp(name, "ebus") == 0)
129 		return (1);
130 
131 	/* Or a real ebus III */
132 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
133 	    PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN &&
134 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_EBUSIII &&
135 		strcmp(name, "ebus") == 0)
136 		return (1);
137 
138 	/* Or a PCI-ISA bridge XXX I hope this is on-board. */
139 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
140 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA) {
141 		return (1);
142 	}
143 
144 	return (0);
145 }
146 
147 /*
148  * attach an ebus and all it's children.  this code is modeled
149  * after the sbus code which does similar things.
150  */
151 void
152 ebus_attach(struct device *parent, struct device *self, void *aux)
153 {
154 	struct ebus_softc *sc = (struct ebus_softc *)self;
155 	struct pci_attach_args *pa = aux;
156 	struct ebus_attach_args eba;
157 	struct ebus_interrupt_map_mask *immp;
158 	int node, nmapmask, error;
159 
160 	printf("\n");
161 
162 	sc->sc_memtag = ebus_alloc_mem_tag(sc, pa->pa_memt);
163 	sc->sc_iotag = ebus_alloc_io_tag(sc, pa->pa_iot);
164 	sc->sc_dmatag = ebus_alloc_dma_tag(sc, pa->pa_dmat);
165 
166 	node = PCITAG_NODE(pa->pa_tag);
167 	if (node == -1)
168 		panic("could not find ebus node");
169 
170 	sc->sc_node = node;
171 
172 	/*
173 	 * fill in our softc with information from the prom
174 	 */
175 	sc->sc_intmap = NULL;
176 	sc->sc_range = NULL;
177 	error = getprop(node, "interrupt-map",
178 			sizeof(struct ebus_interrupt_map),
179 			&sc->sc_nintmap, (void **)&sc->sc_intmap);
180 	switch (error) {
181 	case 0:
182 		immp = &sc->sc_intmapmask;
183 		error = getprop(node, "interrupt-map-mask",
184 			    sizeof(struct ebus_interrupt_map_mask), &nmapmask,
185 			    (void **)&immp);
186 		if (error)
187 			panic("could not get ebus interrupt-map-mask");
188 		if (nmapmask != 1)
189 			panic("ebus interrupt-map-mask is broken");
190 		break;
191 	case ENOENT:
192 		break;
193 	default:
194 		panic("ebus interrupt-map: error %d", error);
195 		break;
196 	}
197 
198 	error = getprop(node, "ranges", sizeof(struct ebus_ranges),
199 	    &sc->sc_nrange, (void **)&sc->sc_range);
200 	if (error)
201 		panic("ebus ranges: error %d", error);
202 
203 	/*
204 	 * now attach all our children
205 	 */
206 	DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node));
207 	for (node = firstchild(node); node; node = nextsibling(node)) {
208 		char *name = getpropstring(node, "name");
209 
210 		if (ebus_setup_attach_args(sc, node, &eba) != 0) {
211 			printf("ebus_attach: %s: incomplete\n", name);
212 			continue;
213 		} else {
214 			DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n",
215 			    eba.ea_name));
216 			(void)config_found(self, &eba, ebus_print);
217 		}
218 		ebus_destroy_attach_args(&eba);
219 	}
220 }
221 
222 int
223 ebus_setup_attach_args(struct ebus_softc *sc, int node,
224     struct ebus_attach_args *ea)
225 {
226 	int	n, rv;
227 
228 	bzero(ea, sizeof(struct ebus_attach_args));
229 	rv = getprop(node, "name", 1, &n, (void **)&ea->ea_name);
230 	if (rv != 0)
231 		return (rv);
232 	ea->ea_name[n] = '\0';
233 
234 	ea->ea_node = node;
235 	ea->ea_memtag = sc->sc_memtag;
236 	ea->ea_iotag = sc->sc_iotag;
237 	ea->ea_dmatag = sc->sc_dmatag;
238 
239 	rv = getprop(node, "reg", sizeof(struct ebus_regs), &ea->ea_nregs,
240 	    (void **)&ea->ea_regs);
241 	if (rv)
242 		return (rv);
243 
244 	rv = getprop(node, "address", sizeof(u_int32_t), &ea->ea_nvaddrs,
245 	    (void **)&ea->ea_vaddrs);
246 	if (rv != ENOENT) {
247 		if (rv)
248 			return (rv);
249 
250 		if (ea->ea_nregs != ea->ea_nvaddrs)
251 			printf("ebus loses: device %s: %d regs and %d addrs\n",
252 			    ea->ea_name, ea->ea_nregs, ea->ea_nvaddrs);
253 	} else
254 		ea->ea_nvaddrs = 0;
255 
256 	if (getprop(node, "interrupts", sizeof(u_int32_t), &ea->ea_nintrs,
257 	    (void **)&ea->ea_intrs))
258 		ea->ea_nintrs = 0;
259 	else
260 		ebus_find_ino(sc, ea);
261 
262 	return (0);
263 }
264 
265 void
266 ebus_destroy_attach_args(struct ebus_attach_args *ea)
267 {
268 	if (ea->ea_name)
269 		free((void *)ea->ea_name, M_DEVBUF);
270 	if (ea->ea_regs)
271 		free((void *)ea->ea_regs, M_DEVBUF);
272 	if (ea->ea_intrs)
273 		free((void *)ea->ea_intrs, M_DEVBUF);
274 	if (ea->ea_vaddrs)
275 		free((void *)ea->ea_vaddrs, M_DEVBUF);
276 }
277 
278 int
279 ebus_print(void *aux, const char *p)
280 {
281 	struct ebus_attach_args *ea = aux;
282 	int i;
283 
284 	if (p)
285 		printf("%s at %s", ea->ea_name, p);
286 	for (i = 0; i < ea->ea_nregs; i++)
287 		printf("%s %x-%x", i == 0 ? " addr" : ",",
288 		    ea->ea_regs[i].lo,
289 		    ea->ea_regs[i].lo + ea->ea_regs[i].size - 1);
290 	for (i = 0; i < ea->ea_nintrs; i++)
291 		printf(" ipl %d", ea->ea_intrs[i]);
292 	return (UNCONF);
293 }
294 
295 
296 /*
297  * find the INO values for each interrupt and fill them in.
298  *
299  * for each "reg" property of this device, mask it's hi and lo
300  * values with the "interrupt-map-mask"'s hi/lo values, and also
301  * mask the interrupt number with the interrupt mask.  search the
302  * "interrupt-map" list for matching values of hi, lo and interrupt
303  * to give the INO for this interrupt.
304  */
305 void
306 ebus_find_ino(struct ebus_softc *sc, struct ebus_attach_args *ea)
307 {
308 	u_int32_t hi, lo, intr;
309 	int i, j, k;
310 
311 	if (sc->sc_nintmap == 0) {
312 		for (i = 0; i < ea->ea_nintrs; i++) {
313 			OF_mapintr(ea->ea_node, &ea->ea_intrs[i],
314 				sizeof(ea->ea_intrs[0]),
315 				sizeof(ea->ea_intrs[0]));
316 		}
317 		return;
318 	}
319 
320 	DPRINTF(EDB_INTRMAP,
321 	    ("ebus_find_ino: searching %d interrupts", ea->ea_nintrs));
322 
323 	for (j = 0; j < ea->ea_nintrs; j++) {
324 
325 		intr = ea->ea_intrs[j] & sc->sc_intmapmask.intr;
326 
327 		DPRINTF(EDB_INTRMAP,
328 		    ("; intr %x masked to %x", ea->ea_intrs[j], intr));
329 		for (i = 0; i < ea->ea_nregs; i++) {
330 			hi = ea->ea_regs[i].hi & sc->sc_intmapmask.hi;
331 			lo = ea->ea_regs[i].lo & sc->sc_intmapmask.lo;
332 
333 			DPRINTF(EDB_INTRMAP,
334 			    ("; reg hi.lo %08x.%08x masked to %08x.%08x",
335 			    ea->ea_regs[i].hi, ea->ea_regs[i].lo, hi, lo));
336 			for (k = 0; k < sc->sc_nintmap; k++) {
337 				DPRINTF(EDB_INTRMAP,
338 				    ("; checking hi.lo %08x.%08x intr %x",
339 				    sc->sc_intmap[k].hi, sc->sc_intmap[k].lo,
340 				    sc->sc_intmap[k].intr));
341 				if (hi == sc->sc_intmap[k].hi &&
342 				    lo == sc->sc_intmap[k].lo &&
343 				    intr == sc->sc_intmap[k].intr) {
344 					ea->ea_intrs[j] =
345 					    sc->sc_intmap[k].cintr;
346 					DPRINTF(EDB_INTRMAP,
347 					    ("; FOUND IT! changing to %d\n",
348 					    sc->sc_intmap[k].cintr));
349 					goto next_intr;
350 				}
351 			}
352 		}
353 next_intr:;
354 	}
355 }
356 
357 bus_space_tag_t
358 ebus_alloc_mem_tag(struct ebus_softc *sc, bus_space_tag_t parent)
359 {
360         return (_ebus_alloc_bus_tag(sc, "mem", parent,
361             0x02));	/* 32-bit mem space (where's the #define???) */
362 }
363 
364 bus_space_tag_t
365 ebus_alloc_io_tag(struct ebus_softc *sc, bus_space_tag_t parent)
366 {
367         return (_ebus_alloc_bus_tag(sc, "io", parent,
368             0x01));	/* IO space (where's the #define???) */
369 }
370 
371 /*
372  * bus space and bus dma below here
373  */
374 bus_space_tag_t
375 _ebus_alloc_bus_tag(struct ebus_softc *sc, const char *name,
376     bus_space_tag_t parent, int ss)
377 {
378 	struct sparc_bus_space_tag *bt;
379 
380 	bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT);
381 	if (bt == NULL)
382 		panic("could not allocate ebus bus tag");
383 
384 	bzero(bt, sizeof *bt);
385 	snprintf(bt->name, sizeof(bt->name), "%s_%s",
386 		sc->sc_dev.dv_xname, name);
387 	bt->cookie = sc;
388 	bt->parent = parent;
389 	bt->default_type = ss;
390 	bt->asi = parent->asi;
391 	bt->sasi = parent->sasi;
392 	bt->sparc_bus_map = _ebus_bus_map;
393 	bt->sparc_bus_mmap = ebus_bus_mmap;
394 
395 	return (bt);
396 }
397 
398 bus_dma_tag_t
399 ebus_alloc_dma_tag(struct ebus_softc *sc, bus_dma_tag_t pdt)
400 {
401 	bus_dma_tag_t dt;
402 
403 	dt = (bus_dma_tag_t)
404 		malloc(sizeof(struct sparc_bus_dma_tag), M_DEVBUF, M_NOWAIT);
405 	if (dt == NULL)
406 		panic("could not allocate ebus dma tag");
407 
408 	bzero(dt, sizeof *dt);
409 	dt->_cookie = sc;
410 	dt->_parent = pdt;
411 	sc->sc_dmatag = dt;
412 	return (dt);
413 }
414 
415 /*
416  * bus space support.  <sparc64/dev/psychoreg.h> has a discussion
417  * about PCI physical addresses, which also applies to ebus.
418  */
419 static int
420 _ebus_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
421     bus_size_t size, int flags, bus_space_handle_t *hp)
422 {
423 	struct ebus_softc *sc = t->cookie;
424 	bus_addr_t hi, lo;
425 	int i;
426 
427 	DPRINTF(EDB_BUSMAP,
428 	    ("\n_ebus_bus_map: type %d off %016llx sz %x flags %d",
429 	    (int)t->default_type, (unsigned long long)offset, (int)size,
430 	    (int)flags));
431 
432 	if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
433 		printf("\n_ebus_bus_map: invalid parent");
434 		return (EINVAL);
435 	}
436 
437 	t = t->parent;
438 
439 	if (flags & BUS_SPACE_MAP_PROMADDRESS) {
440 		return ((*t->sparc_bus_map)
441 		    (t, t0, offset, size, flags, hp));
442 	}
443 
444 	hi = offset >> 32UL;
445 	lo = offset & 0xffffffff;
446 
447 	DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo));
448 	for (i = 0; i < sc->sc_nrange; i++) {
449 		bus_addr_t pciaddr;
450 
451 		if (hi != sc->sc_range[i].child_hi)
452 			continue;
453 		if (lo < sc->sc_range[i].child_lo ||
454 		    (lo + size) >
455 		      (sc->sc_range[i].child_lo + sc->sc_range[i].size))
456 			continue;
457 
458 		if(((sc->sc_range[i].phys_hi >> 24) & 3) != t->default_type)
459 			continue;
460 
461 		pciaddr = ((bus_addr_t)sc->sc_range[i].phys_mid << 32UL) |
462 				       sc->sc_range[i].phys_lo;
463 		pciaddr += lo;
464 		DPRINTF(EDB_BUSMAP,
465 		    ("\n_ebus_bus_map: mapping space %x paddr offset %qx "
466 		    "pciaddr %qx\n", (int)t->default_type,
467 		    (unsigned long long)offset, (unsigned long long)pciaddr));
468 		/* pass it onto the psycho */
469                 return ((*t->sparc_bus_map)(t, t0, pciaddr, size, flags, hp));
470 	}
471 	DPRINTF(EDB_BUSMAP, (": FAILED\n"));
472 	return (EINVAL);
473 }
474 
475 static paddr_t
476 ebus_bus_mmap(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t paddr,
477     off_t off, int prot, int flags)
478 {
479 	bus_addr_t offset = paddr;
480 	struct ebus_softc *sc = t->cookie;
481 	int i;
482 
483 	if (t->parent == 0 || t->parent->sparc_bus_mmap == 0) {
484 		printf("\nebus_bus_mmap: invalid parent");
485 		return (-1);
486         }
487 
488 	t = t->parent;
489 
490 	for (i = 0; i < sc->sc_nrange; i++) {
491 		bus_addr_t paddr =
492 		    ((bus_addr_t)sc->sc_range[i].child_hi << 32) |
493 		    sc->sc_range[i].child_lo;
494 
495 		if (offset != paddr)
496 			continue;
497 
498 		DPRINTF(EDB_BUSMAP, ("\n_ebus_bus_mmap: mapping paddr %qx\n",
499 		    (unsigned long long)paddr));
500 		return ((*t->sparc_bus_mmap)(t, t0, paddr, off, prot, flags));
501 	}
502 
503 	return (-1);
504 }
505 
506