ebus.c revision 1.44 1 /* $NetBSD: ebus.c,v 1.44 2004/03/21 12:50:14 martin Exp $ */
2
3 /*
4 * Copyright (c) 1999, 2000, 2001 Matthew R. Green
5 * 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,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: ebus.c,v 1.44 2004/03/21 12:50:14 martin Exp $");
33
34 #include "opt_ddb.h"
35
36 /*
37 * UltraSPARC 5 and beyond ebus support.
38 *
39 * note that this driver is not complete:
40 * - interrupt establish is written and appears to work
41 * - bus map code is written and appears to work
42 * - ebus2 DMA code is completely unwritten, we just punt to
43 * the iommu.
44 */
45
46 #ifdef DEBUG
47 #define EDB_PROM 0x01
48 #define EDB_CHILD 0x02
49 #define EDB_INTRMAP 0x04
50 #define EDB_BUSMAP 0x08
51 int ebus_debug = 0;
52 #define DPRINTF(l, s) do { if (ebus_debug & l) printf s; } while (0)
53 #else
54 #define DPRINTF(l, s)
55 #endif
56
57 #include <sys/param.h>
58 #include <sys/conf.h>
59 #include <sys/device.h>
60 #include <sys/errno.h>
61 #include <sys/extent.h>
62 #include <sys/malloc.h>
63 #include <sys/systm.h>
64 #include <sys/time.h>
65
66 #define _SPARC_BUS_DMA_PRIVATE
67 #include <machine/bus.h>
68 #include <machine/autoconf.h>
69 #include <machine/openfirm.h>
70
71 #include <dev/pci/pcivar.h>
72 #include <dev/pci/pcireg.h>
73 #include <dev/pci/pcidevs.h>
74
75 #include <sparc64/dev/iommureg.h>
76 #include <sparc64/dev/iommuvar.h>
77 #include <sparc64/dev/psychoreg.h>
78 #include <sparc64/dev/psychovar.h>
79 #include <dev/ebus/ebusreg.h>
80 #include <dev/ebus/ebusvar.h>
81 #include <sparc64/sparc64/cache.h>
82
83 struct ebus_softc {
84 struct device sc_dev;
85
86 int sc_node;
87
88 bus_space_tag_t sc_memtag; /* from pci */
89 bus_space_tag_t sc_iotag; /* from pci */
90 bus_space_tag_t sc_childbustag; /* pass to children */
91 bus_dma_tag_t sc_dmatag;
92
93 struct ebus_ranges *sc_range;
94 struct ebus_interrupt_map *sc_intmap;
95 struct ebus_interrupt_map_mask sc_intmapmask;
96
97 int sc_nrange; /* counters */
98 int sc_nintmap;
99 };
100
101 int ebus_match __P((struct device *, struct cfdata *, void *));
102 void ebus_attach __P((struct device *, struct device *, void *));
103
104 CFATTACH_DECL(ebus, sizeof(struct ebus_softc),
105 ebus_match, ebus_attach, NULL, NULL);
106
107 bus_space_tag_t ebus_alloc_bus_tag __P((struct ebus_softc *, int));
108
109 int ebus_setup_attach_args __P((struct ebus_softc *, int,
110 struct ebus_attach_args *));
111 void ebus_destroy_attach_args __P((struct ebus_attach_args *));
112 int ebus_print __P((void *, const char *));
113 void ebus_find_ino __P((struct ebus_softc *, struct ebus_attach_args *));
114 int ebus_find_node __P((struct pci_attach_args *));
115
116 /*
117 * here are our bus space and bus DMA routines.
118 */
119 static paddr_t ebus_bus_mmap __P((bus_space_tag_t, bus_addr_t, off_t, int, int));
120 static int _ebus_bus_map __P((bus_space_tag_t, bus_addr_t, bus_size_t, int,
121 vaddr_t, bus_space_handle_t *));
122 static void *ebus_intr_establish __P((bus_space_tag_t, int, int,
123 int (*) __P((void *)), void *, void(*)__P((void))));
124
125 int
126 ebus_match(parent, match, aux)
127 struct device *parent;
128 struct cfdata *match;
129 void *aux;
130 {
131 struct pci_attach_args *pa = aux;
132 char name[10];
133 int node;
134
135 /* Only attach if there's a PROM node. */
136 node = PCITAG_NODE(pa->pa_tag);
137 if (node == -1) return (0);
138
139 /* Match a real ebus */
140 OF_getprop(node, "name", &name, sizeof(name));
141 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
142 PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN &&
143 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_EBUS &&
144 strcmp(name, "ebus") == 0)
145 return (1);
146
147 /* Or a real ebus III */
148 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
149 PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN &&
150 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_EBUSIII &&
151 strcmp(name, "ebus") == 0)
152 return (1);
153
154 /* Or a PCI-ISA bridge XXX I hope this is on-board. */
155 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
156 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA) {
157 return (1);
158 }
159
160 return (0);
161 }
162
163 /*
164 * attach an ebus and all it's children. this code is modeled
165 * after the sbus code which does similar things.
166 */
167 void
168 ebus_attach(parent, self, aux)
169 struct device *parent, *self;
170 void *aux;
171 {
172 struct ebus_softc *sc = (struct ebus_softc *)self;
173 struct pci_attach_args *pa = aux;
174 struct ebus_attach_args eba;
175 struct ebus_interrupt_map_mask *immp;
176 int node, nmapmask, error;
177 char devinfo[256];
178
179 printf("\n");
180
181 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
182 printf("%s: %s, revision 0x%02x\n", self->dv_xname, devinfo,
183 PCI_REVISION(pa->pa_class));
184
185 sc->sc_memtag = pa->pa_memt;
186 sc->sc_iotag = pa->pa_iot;
187 sc->sc_childbustag = ebus_alloc_bus_tag(sc, PCI_MEMORY_BUS_SPACE);
188 sc->sc_dmatag = pa->pa_dmat;
189
190 node = PCITAG_NODE(pa->pa_tag);
191 if (node == -1)
192 panic("could not find ebus node");
193
194 sc->sc_node = node;
195
196 /*
197 * fill in our softc with information from the prom
198 */
199 sc->sc_intmap = NULL;
200 sc->sc_range = NULL;
201 sc->sc_nintmap = 0;
202 error = prom_getprop(node, "interrupt-map",
203 sizeof(struct ebus_interrupt_map),
204 &sc->sc_nintmap, &sc->sc_intmap);
205 switch (error) {
206 case 0:
207 immp = &sc->sc_intmapmask;
208 nmapmask = sizeof(*immp);
209 error = prom_getprop(node, "interrupt-map-mask",
210 sizeof(struct ebus_interrupt_map_mask), &nmapmask,
211 &immp);
212 if (error)
213 panic("could not get ebus interrupt-map-mask, error %d",
214 error);
215 if (nmapmask != 1)
216 panic("ebus interrupt-map-mask is broken");
217 break;
218 case ENOENT:
219 break;
220 default:
221 panic("ebus interrupt-map: error %d", error);
222 break;
223 }
224
225 error = prom_getprop(node, "ranges", sizeof(struct ebus_ranges),
226 &sc->sc_nrange, &sc->sc_range);
227 if (error)
228 panic("ebus ranges: error %d", error);
229
230 /*
231 * now attach all our children
232 */
233 DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node));
234 for (node = firstchild(node); node; node = nextsibling(node)) {
235 char *name = prom_getpropstring(node, "name");
236
237 if (ebus_setup_attach_args(sc, node, &eba) != 0) {
238 printf("ebus_attach: %s: incomplete\n", name);
239 continue;
240 } else {
241 DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n",
242 eba.ea_name));
243 (void)config_found(self, &eba, ebus_print);
244 }
245 ebus_destroy_attach_args(&eba);
246 }
247 }
248
249 int
250 ebus_setup_attach_args(sc, node, ea)
251 struct ebus_softc *sc;
252 int node;
253 struct ebus_attach_args *ea;
254 {
255 int n, rv;
256
257 memset(ea, 0, sizeof(struct ebus_attach_args));
258 n = 0;
259 rv = prom_getprop(node, "name", 1, &n, &ea->ea_name);
260 if (rv != 0)
261 return (rv);
262 ea->ea_name[n] = '\0';
263
264 ea->ea_node = node;
265 ea->ea_bustag = sc->sc_childbustag;
266 ea->ea_dmatag = sc->sc_dmatag;
267
268 rv = prom_getprop(node, "reg", sizeof(struct ebus_regs), &ea->ea_nreg,
269 &ea->ea_reg);
270 if (rv)
271 return (rv);
272
273 rv = prom_getprop(node, "address", sizeof(u_int32_t), &ea->ea_nvaddr,
274 &ea->ea_vaddr);
275 if (rv != ENOENT) {
276 if (rv)
277 return (rv);
278
279 if (ea->ea_nreg != ea->ea_nvaddr)
280 printf("ebus loses: device %s: %d regs and %d addrs\n",
281 ea->ea_name, ea->ea_nreg, ea->ea_nvaddr);
282 } else
283 ea->ea_nvaddr = 0;
284
285 if (prom_getprop(node, "interrupts", sizeof(u_int32_t), &ea->ea_nintr,
286 &ea->ea_intr))
287 ea->ea_nintr = 0;
288 else
289 ebus_find_ino(sc, ea);
290
291 return (0);
292 }
293
294 void
295 ebus_destroy_attach_args(ea)
296 struct ebus_attach_args *ea;
297 {
298
299 if (ea->ea_name)
300 free((void *)ea->ea_name, M_DEVBUF);
301 if (ea->ea_reg)
302 free((void *)ea->ea_reg, M_DEVBUF);
303 if (ea->ea_intr)
304 free((void *)ea->ea_intr, M_DEVBUF);
305 if (ea->ea_vaddr)
306 free((void *)ea->ea_vaddr, M_DEVBUF);
307 }
308
309 int
310 ebus_print(aux, p)
311 void *aux;
312 const char *p;
313 {
314 struct ebus_attach_args *ea = aux;
315 int i;
316
317 if (p)
318 aprint_normal("%s at %s", ea->ea_name, p);
319 for (i = 0; i < ea->ea_nreg; i++)
320 aprint_normal("%s %x-%x", i == 0 ? " addr" : ",",
321 ea->ea_reg[i].lo,
322 ea->ea_reg[i].lo + ea->ea_reg[i].size - 1);
323 for (i = 0; i < ea->ea_nintr; i++)
324 aprint_normal(" ipl %d", ea->ea_intr[i]);
325 return (UNCONF);
326 }
327
328
329 /*
330 * find the INO values for each interrupt and fill them in.
331 *
332 * for each "reg" property of this device, mask it's hi and lo
333 * values with the "interrupt-map-mask"'s hi/lo values, and also
334 * mask the interrupt number with the interrupt mask. search the
335 * "interrupt-map" list for matching values of hi, lo and interrupt
336 * to give the INO for this interrupt.
337 */
338 void
339 ebus_find_ino(sc, ea)
340 struct ebus_softc *sc;
341 struct ebus_attach_args *ea;
342 {
343 u_int32_t hi, lo, intr;
344 int i, j, k;
345
346 if (sc->sc_nintmap == 0) {
347 for (i = 0; i < ea->ea_nintr; i++) {
348 OF_mapintr(ea->ea_node, &ea->ea_intr[i],
349 sizeof(ea->ea_intr[0]),
350 sizeof(ea->ea_intr[0]));
351 }
352 return;
353 }
354
355 DPRINTF(EDB_INTRMAP,
356 ("ebus_find_ino: searching %d interrupts", ea->ea_nintr));
357
358 for (j = 0; j < ea->ea_nintr; j++) {
359
360 intr = ea->ea_intr[j] & sc->sc_intmapmask.intr;
361
362 DPRINTF(EDB_INTRMAP,
363 ("; intr %x masked to %x", ea->ea_intr[j], intr));
364 for (i = 0; i < ea->ea_nreg; i++) {
365 hi = ea->ea_reg[i].hi & sc->sc_intmapmask.hi;
366 lo = ea->ea_reg[i].lo & sc->sc_intmapmask.lo;
367
368 DPRINTF(EDB_INTRMAP,
369 ("; reg hi.lo %08x.%08x masked to %08x.%08x",
370 ea->ea_reg[i].hi, ea->ea_reg[i].lo, hi, lo));
371 for (k = 0; k < sc->sc_nintmap; k++) {
372 DPRINTF(EDB_INTRMAP,
373 ("; checking hi.lo %08x.%08x intr %x",
374 sc->sc_intmap[k].hi, sc->sc_intmap[k].lo,
375 sc->sc_intmap[k].intr));
376 if (hi == sc->sc_intmap[k].hi &&
377 lo == sc->sc_intmap[k].lo &&
378 intr == sc->sc_intmap[k].intr) {
379 ea->ea_intr[j] =
380 sc->sc_intmap[k].cintr;
381 DPRINTF(EDB_INTRMAP,
382 ("; FOUND IT! changing to %d\n",
383 sc->sc_intmap[k].cintr));
384 goto next_intr;
385 }
386 }
387 }
388 next_intr:;
389 }
390 }
391
392 /*
393 * bus space support. <sparc64/dev/psychoreg.h> has a discussion
394 * about PCI physical addresses, which also applies to ebus.
395 */
396 bus_space_tag_t
397 ebus_alloc_bus_tag(sc, type)
398 struct ebus_softc *sc;
399 int type;
400 {
401 bus_space_tag_t bt;
402
403 bt = (bus_space_tag_t)
404 malloc(sizeof(struct sparc_bus_space_tag), M_DEVBUF, M_NOWAIT);
405 if (bt == NULL)
406 panic("could not allocate ebus bus tag");
407
408 memset(bt, 0, sizeof *bt);
409 bt->cookie = sc;
410 bt->parent = sc->sc_memtag;
411 bt->type = type;
412 bt->sparc_bus_map = _ebus_bus_map;
413 bt->sparc_bus_mmap = ebus_bus_mmap;
414 bt->sparc_intr_establish = ebus_intr_establish;
415 return (bt);
416 }
417
418 static int
419 _ebus_bus_map(t, ba, size, flags, va, hp)
420 bus_space_tag_t t;
421 bus_addr_t ba;
422 bus_size_t size;
423 int flags;
424 vaddr_t va;
425 bus_space_handle_t *hp;
426 {
427 struct ebus_softc *sc = t->cookie;
428 paddr_t offset;
429 u_int bar;
430 int i, ss;
431
432 bar = BUS_ADDR_IOSPACE(ba);
433 offset = BUS_ADDR_PADDR(ba);
434
435 DPRINTF(EDB_BUSMAP,
436 ("\n_ebus_bus_map: bar %d offset %08x sz %x flags %x va %p\n",
437 (int)bar, (u_int32_t)offset, (u_int32_t)size,
438 flags, (void *)va));
439
440 for (i = 0; i < sc->sc_nrange; i++) {
441 bus_addr_t pciaddr;
442
443 if (bar != sc->sc_range[i].child_hi)
444 continue;
445 if (offset < sc->sc_range[i].child_lo ||
446 (offset + size) >
447 (sc->sc_range[i].child_lo + sc->sc_range[i].size))
448 continue;
449
450 /* Isolate address space and find the right tag */
451 ss = (sc->sc_range[i].phys_hi>>24)&3;
452 switch (ss) {
453 case 1: /* I/O space */
454 t = sc->sc_iotag;
455 break;
456 case 2: /* Memory space */
457 t = sc->sc_memtag;
458 break;
459 case 0: /* Config space */
460 case 3: /* 64-bit Memory space */
461 default: /* WTF? */
462 /* We don't handle these */
463 panic("_ebus_bus_map: illegal space %x", ss);
464 break;
465 }
466 pciaddr = ((bus_addr_t)sc->sc_range[i].phys_mid << 32UL) |
467 sc->sc_range[i].phys_lo;
468 pciaddr += offset;
469
470 DPRINTF(EDB_BUSMAP,
471 ("_ebus_bus_map: mapping to PCI addr %x\n",
472 (u_int32_t)pciaddr));
473
474 /* pass it onto the psycho */
475 return (bus_space_map(t, pciaddr, size, flags, hp));
476 }
477 DPRINTF(EDB_BUSMAP, (": FAILED\n"));
478 return (EINVAL);
479 }
480
481 static paddr_t
482 ebus_bus_mmap(t, paddr, off, prot, flags)
483 bus_space_tag_t t;
484 bus_addr_t paddr;
485 off_t off;
486 int prot;
487 int flags;
488 {
489 bus_addr_t offset = paddr;
490 struct ebus_softc *sc = t->cookie;
491 int i;
492
493 for (i = 0; i < sc->sc_nrange; i++) {
494 bus_addr_t paddr = ((bus_addr_t)sc->sc_range[i].child_hi << 32) |
495 sc->sc_range[i].child_lo;
496
497 if (offset != paddr)
498 continue;
499
500 DPRINTF(EDB_BUSMAP, ("\n_ebus_bus_mmap: mapping paddr %qx\n",
501 (unsigned long long)paddr));
502 return (bus_space_mmap(sc->sc_memtag, paddr, off,
503 prot, flags));
504 }
505
506 return (-1);
507 }
508
509 /*
510 * install an interrupt handler for a ebus device
511 */
512 void *
513 ebus_intr_establish(t, pri, level, handler, arg, fastvec)
514 bus_space_tag_t t;
515 int pri;
516 int level;
517 int (*handler) __P((void *));
518 void *arg;
519 void (*fastvec) __P((void)); /* ignored */
520 {
521
522 return (bus_intr_establish(t->parent, pri, level, handler, arg));
523 }
524