sbus.c revision 1.43 1 /* $NetBSD: sbus.c,v 1.43 2001/07/20 00:07:13 eeh Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Paul Kranenburg.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1992, 1993
41 * The Regents of the University of California. All rights reserved.
42 *
43 * This software was developed by the Computer Systems Engineering group
44 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
45 * contributed to Berkeley.
46 *
47 * All advertising materials mentioning features or use of this software
48 * must display the following acknowledgement:
49 * This product includes software developed by the University of
50 * California, Lawrence Berkeley Laboratory.
51 *
52 * Redistribution and use in source and binary forms, with or without
53 * modification, are permitted provided that the following conditions
54 * are met:
55 * 1. Redistributions of source code must retain the above copyright
56 * notice, this list of conditions and the following disclaimer.
57 * 2. Redistributions in binary form must reproduce the above copyright
58 * notice, this list of conditions and the following disclaimer in the
59 * documentation and/or other materials provided with the distribution.
60 * 3. All advertising materials mentioning features or use of this software
61 * must display the following acknowledgement:
62 * This product includes software developed by the University of
63 * California, Berkeley and its contributors.
64 * 4. Neither the name of the University nor the names of its contributors
65 * may be used to endorse or promote products derived from this software
66 * without specific prior written permission.
67 *
68 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
69 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
70 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
71 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
72 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
73 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
74 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
75 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
76 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
77 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
78 * SUCH DAMAGE.
79 *
80 * @(#)sbus.c 8.1 (Berkeley) 6/11/93
81 */
82
83 /*
84 * Copyright (c) 1999 Eduardo Horvath
85 *
86 * Redistribution and use in source and binary forms, with or without
87 * modification, are permitted provided that the following conditions
88 * are met:
89 * 1. Redistributions of source code must retain the above copyright
90 * notice, this list of conditions and the following disclaimer.
91 *
92 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
93 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
95 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
96 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
97 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
98 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
99 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
100 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
101 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
102 * SUCH DAMAGE.
103 *
104 */
105
106
107 /*
108 * Sbus stuff.
109 */
110 #include "opt_ddb.h"
111
112 #include <sys/param.h>
113 #include <sys/extent.h>
114 #include <sys/malloc.h>
115 #include <sys/systm.h>
116 #include <sys/device.h>
117 #include <sys/reboot.h>
118
119 #include <machine/bus.h>
120 #include <sparc64/sparc64/cache.h>
121 #include <sparc64/dev/iommureg.h>
122 #include <sparc64/dev/iommuvar.h>
123 #include <sparc64/dev/sbusreg.h>
124 #include <dev/sbus/sbusvar.h>
125
126 #include <machine/autoconf.h>
127 #include <machine/cpu.h>
128 #include <machine/sparc64.h>
129
130 #ifdef DEBUG
131 #define SDB_DVMA 0x1
132 #define SDB_INTR 0x2
133 int sbus_debug = 0;
134 #define DPRINTF(l, s) do { if (sbus_debug & l) printf s; } while (0)
135 #else
136 #define DPRINTF(l, s)
137 #endif
138
139 void sbusreset __P((int));
140
141 static bus_space_tag_t sbus_alloc_bustag __P((struct sbus_softc *));
142 static bus_dma_tag_t sbus_alloc_dmatag __P((struct sbus_softc *));
143 static int sbus_get_intr __P((struct sbus_softc *, int,
144 struct sbus_intr **, int *, int));
145 static int sbus_bus_mmap __P((bus_space_tag_t, bus_type_t, bus_addr_t,
146 int, bus_space_handle_t *));
147 static int sbus_overtemp __P((void *));
148 static int _sbus_bus_map __P((
149 bus_space_tag_t,
150 bus_type_t,
151 bus_addr_t, /*offset*/
152 bus_size_t, /*size*/
153 int, /*flags*/
154 vaddr_t, /*preferred virtual address */
155 bus_space_handle_t *));
156 static void *sbus_intr_establish __P((
157 bus_space_tag_t,
158 int, /*Sbus interrupt level*/
159 int, /*`device class' priority*/
160 int, /*flags*/
161 int (*) __P((void *)), /*handler*/
162 void *)); /*handler arg*/
163
164
165 /* autoconfiguration driver */
166 int sbus_match __P((struct device *, struct cfdata *, void *));
167 void sbus_attach __P((struct device *, struct device *, void *));
168
169
170 struct cfattach sbus_ca = {
171 sizeof(struct sbus_softc), sbus_match, sbus_attach
172 };
173
174 extern struct cfdriver sbus_cd;
175
176 /*
177 * DVMA routines
178 */
179 int sbus_dmamap_load __P((bus_dma_tag_t, bus_dmamap_t, void *,
180 bus_size_t, struct proc *, int));
181 void sbus_dmamap_unload __P((bus_dma_tag_t, bus_dmamap_t));
182 int sbus_dmamap_load_raw __P((bus_dma_tag_t, bus_dmamap_t,
183 bus_dma_segment_t *, int, bus_size_t, int));
184 void sbus_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
185 bus_size_t, int));
186 int sbus_dmamem_alloc __P((bus_dma_tag_t tag, bus_size_t size,
187 bus_size_t alignment, bus_size_t boundary,
188 bus_dma_segment_t *segs, int nsegs, int *rsegs,
189 int flags));
190 void sbus_dmamem_free __P((bus_dma_tag_t tag, bus_dma_segment_t *segs,
191 int nsegs));
192 int sbus_dmamem_map __P((bus_dma_tag_t tag, bus_dma_segment_t *segs,
193 int nsegs, size_t size, caddr_t *kvap, int flags));
194 void sbus_dmamem_unmap __P((bus_dma_tag_t tag, caddr_t kva,
195 size_t size));
196
197 /*
198 * Child devices receive the Sbus interrupt level in their attach
199 * arguments. We translate these to CPU IPLs using the following
200 * tables. Note: obio bus interrupt levels are identical to the
201 * processor IPL.
202 *
203 * The second set of tables is used when the Sbus interrupt level
204 * cannot be had from the PROM as an `interrupt' property. We then
205 * fall back on the `intr' property which contains the CPU IPL.
206 */
207
208 /* Translate Sbus interrupt level to processor IPL */
209 static int intr_sbus2ipl_4c[] = {
210 0, 1, 2, 3, 5, 7, 8, 9
211 };
212 static int intr_sbus2ipl_4m[] = {
213 0, 2, 3, 5, 7, 9, 11, 13
214 };
215
216 /*
217 * This value is or'ed into the attach args' interrupt level cookie
218 * if the interrupt level comes from an `intr' property, i.e. it is
219 * not an Sbus interrupt level.
220 */
221 #define SBUS_INTR_COMPAT 0x80000000
222
223
224 /*
225 * Print the location of some sbus-attached device (called just
226 * before attaching that device). If `sbus' is not NULL, the
227 * device was found but not configured; print the sbus as well.
228 * Return UNCONF (config_find ignores this if the device was configured).
229 */
230 int
231 sbus_print(args, busname)
232 void *args;
233 const char *busname;
234 {
235 struct sbus_attach_args *sa = args;
236 int i;
237
238 if (busname)
239 printf("%s at %s", sa->sa_name, busname);
240 printf(" slot %ld offset 0x%lx", (long)sa->sa_slot,
241 (u_long)sa->sa_offset);
242 for (i = 0; i < sa->sa_nintr; i++) {
243 struct sbus_intr *sbi = &sa->sa_intr[i];
244
245 printf(" vector %lx ipl %ld",
246 (u_long)sbi->sbi_vec,
247 (long)INTLEV(sbi->sbi_pri));
248 }
249 return (UNCONF);
250 }
251
252 int
253 sbus_match(parent, cf, aux)
254 struct device *parent;
255 struct cfdata *cf;
256 void *aux;
257 {
258 struct mainbus_attach_args *ma = aux;
259
260 return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0);
261 }
262
263 /*
264 * Attach an Sbus.
265 */
266 void
267 sbus_attach(parent, self, aux)
268 struct device *parent;
269 struct device *self;
270 void *aux;
271 {
272 struct sbus_softc *sc = (struct sbus_softc *)self;
273 struct mainbus_attach_args *ma = aux;
274 struct intrhand *ih;
275 int ipl;
276 char *name;
277 int node = ma->ma_node;
278
279 int node0, error;
280 bus_space_tag_t sbt;
281 struct sbus_attach_args sa;
282
283 sc->sc_bustag = ma->ma_bustag;
284 sc->sc_dmatag = ma->ma_dmatag;
285 sc->sc_sysio = (struct sysioreg*)(u_long)ma->ma_address[0]; /* Use prom mapping for sysio. */
286 sc->sc_ign = ma->ma_interrupts[0] & INTMAP_IGN; /* Find interrupt group no */
287
288 /* Setup interrupt translation tables */
289 sc->sc_intr2ipl = CPU_ISSUN4C
290 ? intr_sbus2ipl_4c
291 : intr_sbus2ipl_4m;
292
293 /*
294 * Record clock frequency for synchronous SCSI.
295 * IS THIS THE CORRECT DEFAULT??
296 */
297 sc->sc_clockfreq = getpropint(node, "clock-frequency", 25*1000*1000);
298 printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq));
299
300 sbt = sbus_alloc_bustag(sc);
301 sc->sc_dmatag = sbus_alloc_dmatag(sc);
302
303 /*
304 * Get the SBus burst transfer size if burst transfers are supported
305 */
306 sc->sc_burst = getpropint(node, "burst-sizes", 0);
307
308 /*
309 * Collect address translations from the OBP.
310 */
311 error = getprop(node, "ranges", sizeof(struct sbus_range),
312 &sc->sc_nrange, (void **)&sc->sc_range);
313 if (error)
314 panic("%s: error getting ranges property", sc->sc_dev.dv_xname);
315
316 /* initailise the IOMMU */
317
318 /* punch in our copies */
319 sc->sc_is.is_bustag = sc->sc_bustag;
320 sc->sc_is.is_iommu = &sc->sc_sysio->sys_iommu;
321 sc->sc_is.is_sb = &sc->sc_sysio->sys_strbuf;
322
323 /* give us a nice name.. */
324 name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
325 if (name == 0)
326 panic("couldn't malloc iommu name");
327 snprintf(name, 32, "%s dvma", sc->sc_dev.dv_xname);
328
329 iommu_init(name, &sc->sc_is, 0, -1);
330
331 /* Enable the over temp intr */
332 ih = (struct intrhand *)
333 malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT);
334 ih->ih_map = &sc->sc_sysio->therm_int_map;
335 ih->ih_clr = NULL; /* &sc->sc_sysio->therm_clr_int; */
336 ih->ih_fun = sbus_overtemp;
337 ipl = 1;
338 ih->ih_pil = (1<<ipl);
339 ih->ih_number = INTVEC(*(ih->ih_map));
340 intr_establish(ipl, ih);
341 *(ih->ih_map) |= INTMAP_V;
342
343 /*
344 * Note: the stupid SBUS IOMMU ignores the high bits of an address, so a
345 * NULL DMA pointer will be translated by the first page of the IOTSB.
346 * To avoid bugs we'll alloc and ignore the first entry in the IOTSB.
347 */
348 {
349 u_long dummy;
350
351 if (extent_alloc_subregion(sc->sc_is.is_dvmamap,
352 sc->sc_is.is_dvmabase, sc->sc_is.is_dvmabase + NBPG, NBPG,
353 NBPG, 0, EX_NOWAIT|EX_BOUNDZERO, (u_long *)&dummy) != 0)
354 panic("sbus iommu: can't toss first dvma page");
355 }
356
357 /*
358 * Loop through ROM children, fixing any relative addresses
359 * and then configuring each device.
360 * `specials' is an array of device names that are treated
361 * specially:
362 */
363 node0 = firstchild(node);
364 for (node = node0; node; node = nextsibling(node)) {
365 char *name = getpropstring(node, "name");
366
367 if (sbus_setup_attach_args(sc, sbt, sc->sc_dmatag,
368 node, &sa) != 0) {
369 printf("sbus_attach: %s: incomplete\n", name);
370 continue;
371 }
372 (void) config_found(&sc->sc_dev, (void *)&sa, sbus_print);
373 sbus_destroy_attach_args(&sa);
374 }
375 }
376
377 int
378 sbus_setup_attach_args(sc, bustag, dmatag, node, sa)
379 struct sbus_softc *sc;
380 bus_space_tag_t bustag;
381 bus_dma_tag_t dmatag;
382 int node;
383 struct sbus_attach_args *sa;
384 {
385 /*struct sbus_reg sbusreg;*/
386 /*int base;*/
387 int error;
388 int n;
389
390 bzero(sa, sizeof(struct sbus_attach_args));
391 error = getprop(node, "name", 1, &n, (void **)&sa->sa_name);
392 if (error != 0)
393 return (error);
394 sa->sa_name[n] = '\0';
395
396 sa->sa_bustag = bustag;
397 sa->sa_dmatag = dmatag;
398 sa->sa_node = node;
399 sa->sa_frequency = sc->sc_clockfreq;
400
401 error = getprop(node, "reg", sizeof(struct sbus_reg),
402 &sa->sa_nreg, (void **)&sa->sa_reg);
403 if (error != 0) {
404 char buf[32];
405 if (error != ENOENT ||
406 !node_has_property(node, "device_type") ||
407 strcmp(getpropstringA(node, "device_type", buf),
408 "hierarchical") != 0)
409 return (error);
410 }
411 for (n = 0; n < sa->sa_nreg; n++) {
412 /* Convert to relative addressing, if necessary */
413 u_int32_t base = sa->sa_reg[n].sbr_offset;
414 if (SBUS_ABS(base)) {
415 sa->sa_reg[n].sbr_slot = SBUS_ABS_TO_SLOT(base);
416 sa->sa_reg[n].sbr_offset = SBUS_ABS_TO_OFFSET(base);
417 }
418 }
419
420 if ((error = sbus_get_intr(sc, node, &sa->sa_intr, &sa->sa_nintr,
421 sa->sa_slot)) != 0)
422 return (error);
423
424 error = getprop(node, "address", sizeof(u_int32_t),
425 &sa->sa_npromvaddrs, (void **)&sa->sa_promvaddrs);
426 if (error != 0 && error != ENOENT)
427 return (error);
428
429 return (0);
430 }
431
432 void
433 sbus_destroy_attach_args(sa)
434 struct sbus_attach_args *sa;
435 {
436 if (sa->sa_name != NULL)
437 free(sa->sa_name, M_DEVBUF);
438
439 if (sa->sa_nreg != 0)
440 free(sa->sa_reg, M_DEVBUF);
441
442 if (sa->sa_intr)
443 free(sa->sa_intr, M_DEVBUF);
444
445 if (sa->sa_promvaddrs)
446 free((void *)sa->sa_promvaddrs, M_DEVBUF);
447
448 bzero(sa, sizeof(struct sbus_attach_args)); /*DEBUG*/
449 }
450
451
452 int
453 _sbus_bus_map(t, btype, offset, size, flags, vaddr, hp)
454 bus_space_tag_t t;
455 bus_type_t btype;
456 bus_addr_t offset;
457 bus_size_t size;
458 int flags;
459 vaddr_t vaddr;
460 bus_space_handle_t *hp;
461 {
462 struct sbus_softc *sc = t->cookie;
463 int64_t slot = btype;
464 int i;
465
466 for (i = 0; i < sc->sc_nrange; i++) {
467 bus_addr_t paddr;
468
469 if (sc->sc_range[i].cspace != slot)
470 continue;
471
472 /* We've found the connection to the parent bus */
473 paddr = sc->sc_range[i].poffset + offset;
474 paddr |= ((bus_addr_t)sc->sc_range[i].pspace<<32);
475 DPRINTF(SDB_DVMA,
476 ("\n_sbus_bus_map: mapping paddr slot %lx offset %lx poffset %lx paddr %lx\n",
477 (long)slot, (long)offset, (long)sc->sc_range[i].poffset,
478 (long)paddr));
479 return (bus_space_map2(sc->sc_bustag, 0, paddr,
480 size, flags, vaddr, hp));
481 }
482
483 return (EINVAL);
484 }
485
486 int
487 sbus_bus_mmap(t, btype, paddr, flags, hp)
488 bus_space_tag_t t;
489 bus_type_t btype;
490 bus_addr_t paddr;
491 int flags;
492 bus_space_handle_t *hp;
493 {
494 bus_addr_t offset = paddr;
495 int slot = btype;
496 struct sbus_softc *sc = t->cookie;
497 int i;
498
499 for (i = 0; i < sc->sc_nrange; i++) {
500 bus_addr_t paddr;
501
502 if (sc->sc_range[i].cspace != slot)
503 continue;
504
505 paddr = sc->sc_range[i].poffset + offset;
506 paddr |= ((bus_addr_t)sc->sc_range[i].pspace<<32);
507 return (bus_space_mmap(sc->sc_bustag, 0, paddr,
508 flags, hp));
509 }
510
511 return (-1);
512 }
513
514
515 /*
516 * Each attached device calls sbus_establish after it initializes
517 * its sbusdev portion.
518 */
519 void
520 sbus_establish(sd, dev)
521 register struct sbusdev *sd;
522 register struct device *dev;
523 {
524 register struct sbus_softc *sc;
525 register struct device *curdev;
526
527 /*
528 * We have to look for the sbus by name, since it is not necessarily
529 * our immediate parent (i.e. sun4m /iommu/sbus/espdma/esp)
530 * We don't just use the device structure of the above-attached
531 * sbus, since we might (in the future) support multiple sbus's.
532 */
533 for (curdev = dev->dv_parent; ; curdev = curdev->dv_parent) {
534 if (!curdev || !curdev->dv_xname)
535 panic("sbus_establish: can't find sbus parent for %s",
536 sd->sd_dev->dv_xname
537 ? sd->sd_dev->dv_xname
538 : "<unknown>" );
539
540 if (strncmp(curdev->dv_xname, "sbus", 4) == 0)
541 break;
542 }
543 sc = (struct sbus_softc *) curdev;
544
545 sd->sd_dev = dev;
546 sd->sd_bchain = sc->sc_sbdev;
547 sc->sc_sbdev = sd;
548 }
549
550 /*
551 * Reset the given sbus.
552 */
553 void
554 sbusreset(sbus)
555 int sbus;
556 {
557 register struct sbusdev *sd;
558 struct sbus_softc *sc = sbus_cd.cd_devs[sbus];
559 struct device *dev;
560
561 printf("reset %s:", sc->sc_dev.dv_xname);
562 for (sd = sc->sc_sbdev; sd != NULL; sd = sd->sd_bchain) {
563 if (sd->sd_reset) {
564 dev = sd->sd_dev;
565 (*sd->sd_reset)(dev);
566 printf(" %s", dev->dv_xname);
567 }
568 }
569 /* Reload iommu regs */
570 iommu_reset(&sc->sc_is);
571 }
572
573 /*
574 * Handle an overtemp situation.
575 *
576 * SPARCs have temperature sensors which generate interrupts
577 * if the machine's temperature exceeds a certain threshold.
578 * This handles the interrupt and powers off the machine.
579 * The same needs to be done to PCI controller drivers.
580 */
581 int
582 sbus_overtemp(arg)
583 void *arg;
584 {
585 /* Should try a clean shutdown first */
586 printf("DANGER: OVER TEMPERATURE detected\nShutting down...\n");
587 delay(20);
588 cpu_reboot(RB_POWERDOWN|RB_HALT, NULL);
589 }
590
591 /*
592 * Get interrupt attributes for an Sbus device.
593 */
594 int
595 sbus_get_intr(sc, node, ipp, np, slot)
596 struct sbus_softc *sc;
597 int node;
598 struct sbus_intr **ipp;
599 int *np;
600 int slot;
601 {
602 int *ipl;
603 int n, i;
604 char buf[32];
605
606 /*
607 * The `interrupts' property contains the Sbus interrupt level.
608 */
609 ipl = NULL;
610 if (getprop(node, "interrupts", sizeof(int), np, (void **)&ipl) == 0) {
611 struct sbus_intr *ip;
612 int pri;
613
614 /* Default to interrupt level 2 -- otherwise unused */
615 pri = INTLEVENCODE(2);
616
617 /* Change format to an `struct sbus_intr' array */
618 ip = malloc(*np * sizeof(struct sbus_intr), M_DEVBUF, M_NOWAIT);
619 if (ip == NULL)
620 return (ENOMEM);
621
622 /*
623 * Now things get ugly. We need to take this value which is
624 * the interrupt vector number and encode the IPL into it
625 * somehow. Luckily, the interrupt vector has lots of free
626 * space and we can easily stuff the IPL in there for a while.
627 */
628 getpropstringA(node, "device_type", buf);
629 if (!buf[0])
630 getpropstringA(node, "name", buf);
631
632 for (i = 0; intrmap[i].in_class; i++)
633 if (strcmp(intrmap[i].in_class, buf) == 0) {
634 pri = INTLEVENCODE(intrmap[i].in_lev);
635 break;
636 }
637
638 /*
639 * Sbus card devices need the slot number encoded into
640 * the vector as this is generally not done.
641 */
642 if ((ipl[0] & INTMAP_OBIO) == 0)
643 pri |= slot << 3;
644
645 for (n = 0; n < *np; n++) {
646 /*
647 * We encode vector and priority into sbi_pri so we
648 * can pass them as a unit. This will go away if
649 * sbus_establish ever takes an sbus_intr instead
650 * of an integer level.
651 * Stuff the real vector in sbi_vec.
652 */
653
654 ip[n].sbi_pri = pri|ipl[n];
655 ip[n].sbi_vec = ipl[n];
656 }
657 free(ipl, M_DEVBUF);
658 *ipp = ip;
659 }
660
661 return (0);
662 }
663
664
665 /*
666 * Install an interrupt handler for an Sbus device.
667 */
668 void *
669 sbus_intr_establish(t, pri, level, flags, handler, arg)
670 bus_space_tag_t t;
671 int pri;
672 int level;
673 int flags;
674 int (*handler) __P((void *));
675 void *arg;
676 {
677 struct sbus_softc *sc = t->cookie;
678 struct intrhand *ih;
679 int ipl;
680 long vec = pri;
681
682 ih = (struct intrhand *)
683 malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT);
684 if (ih == NULL)
685 return (NULL);
686
687 if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) != 0)
688 ipl = vec;
689 else if ((vec & SBUS_INTR_COMPAT) != 0)
690 ipl = vec & ~SBUS_INTR_COMPAT;
691 else {
692 /* Decode and remove IPL */
693 ipl = INTLEV(vec);
694 vec = INTVEC(vec);
695 DPRINTF(SDB_INTR,
696 ("\nsbus: intr[%ld]%lx: %lx\nHunting for IRQ...\n",
697 (long)ipl, (long)vec, (u_long)intrlev[vec]));
698 if ((vec & INTMAP_OBIO) == 0) {
699 /* We're in an SBUS slot */
700 /* Register the map and clear intr registers */
701
702 int slot = INTSLOT(pri);
703
704 ih->ih_map = &(&sc->sc_sysio->sbus_slot0_int)[slot];
705 ih->ih_clr = &sc->sc_sysio->sbus0_clr_int[vec];
706 #ifdef DEBUG
707 if (sbus_debug & SDB_INTR) {
708 int64_t intrmap = *ih->ih_map;
709
710 printf("SBUS %lx IRQ as %llx in slot %d\n",
711 (long)vec, (long long)intrmap, slot);
712 printf("\tmap addr %p clr addr %p\n",
713 ih->ih_map, ih->ih_clr);
714 }
715 #endif
716 /* Enable the interrupt */
717 vec |= INTMAP_V;
718 /* Insert IGN */
719 vec |= sc->sc_ign;
720 bus_space_write_8(sc->sc_bustag,
721 (bus_space_handle_t)(u_long)ih->ih_map, 0, vec);
722 } else {
723 int64_t *intrptr = &sc->sc_sysio->scsi_int_map;
724 int64_t intrmap = 0;
725 int i;
726
727 /* Insert IGN */
728 vec |= sc->sc_ign;
729 for (i = 0; &intrptr[i] <=
730 (int64_t *)&sc->sc_sysio->reserved_int_map &&
731 INTVEC(intrmap = intrptr[i]) != INTVEC(vec); i++)
732 ;
733 if (INTVEC(intrmap) == INTVEC(vec)) {
734 DPRINTF(SDB_INTR,
735 ("OBIO %lx IRQ as %lx in slot %d\n",
736 vec, (long)intrmap, i));
737 /* Register the map and clear intr registers */
738 ih->ih_map = &intrptr[i];
739 intrptr = (int64_t *)&sc->sc_sysio->scsi_clr_int;
740 ih->ih_clr = &intrptr[i];
741 /* Enable the interrupt */
742 intrmap |= INTMAP_V;
743 bus_space_write_8(sc->sc_bustag,
744 (bus_space_handle_t)(u_long)ih->ih_map, 0,
745 (u_long)intrmap);
746 } else
747 panic("IRQ not found!");
748 }
749 }
750 #ifdef DEBUG
751 if (sbus_debug & SDB_INTR) { long i; for (i = 0; i < 400000000; i++); }
752 #endif
753
754 ih->ih_fun = handler;
755 ih->ih_arg = arg;
756 ih->ih_number = vec;
757 ih->ih_pil = (1<<ipl);
758 intr_establish(ipl, ih);
759 return (ih);
760 }
761
762 static bus_space_tag_t
763 sbus_alloc_bustag(sc)
764 struct sbus_softc *sc;
765 {
766 bus_space_tag_t sbt;
767
768 sbt = (bus_space_tag_t)
769 malloc(sizeof(struct sparc_bus_space_tag), M_DEVBUF, M_NOWAIT);
770 if (sbt == NULL)
771 return (NULL);
772
773 bzero(sbt, sizeof *sbt);
774 sbt->cookie = sc;
775 sbt->parent = sc->sc_bustag;
776 sbt->type = SBUS_BUS_SPACE;
777 sbt->sparc_bus_map = _sbus_bus_map;
778 sbt->sparc_bus_mmap = sbus_bus_mmap;
779 sbt->sparc_intr_establish = sbus_intr_establish;
780 return (sbt);
781 }
782
783
784 static bus_dma_tag_t
785 sbus_alloc_dmatag(sc)
786 struct sbus_softc *sc;
787 {
788 bus_dma_tag_t sdt, psdt = sc->sc_dmatag;
789
790 sdt = (bus_dma_tag_t)
791 malloc(sizeof(struct sparc_bus_dma_tag), M_DEVBUF, M_NOWAIT);
792 if (sdt == NULL)
793 /* Panic? */
794 return (psdt);
795
796 sdt->_cookie = sc;
797 sdt->_parent = psdt;
798 #define PCOPY(x) sdt->x = psdt->x
799 PCOPY(_dmamap_create);
800 PCOPY(_dmamap_destroy);
801 sdt->_dmamap_load = sbus_dmamap_load;
802 PCOPY(_dmamap_load_mbuf);
803 PCOPY(_dmamap_load_uio);
804 sdt->_dmamap_load_raw = sbus_dmamap_load_raw;
805 sdt->_dmamap_unload = sbus_dmamap_unload;
806 sdt->_dmamap_sync = sbus_dmamap_sync;
807 sdt->_dmamem_alloc = sbus_dmamem_alloc;
808 sdt->_dmamem_free = sbus_dmamem_free;
809 sdt->_dmamem_map = sbus_dmamem_map;
810 sdt->_dmamem_unmap = sbus_dmamem_unmap;
811 PCOPY(_dmamem_mmap);
812 #undef PCOPY
813 sc->sc_dmatag = sdt;
814 return (sdt);
815 }
816
817 int
818 sbus_dmamap_load(tag, map, buf, buflen, p, flags)
819 bus_dma_tag_t tag;
820 bus_dmamap_t map;
821 void *buf;
822 bus_size_t buflen;
823 struct proc *p;
824 int flags;
825 {
826 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
827
828 return (iommu_dvmamap_load(tag, &sc->sc_is, map, buf, buflen, p, flags));
829 }
830
831 int
832 sbus_dmamap_load_raw(tag, map, segs, nsegs, size, flags)
833 bus_dma_tag_t tag;
834 bus_dmamap_t map;
835 bus_dma_segment_t *segs;
836 int nsegs;
837 bus_size_t size;
838 int flags;
839 {
840 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
841
842 return (iommu_dvmamap_load_raw(tag, &sc->sc_is, map, segs, nsegs, flags, size));
843 }
844
845 void
846 sbus_dmamap_unload(tag, map)
847 bus_dma_tag_t tag;
848 bus_dmamap_t map;
849 {
850 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
851
852 iommu_dvmamap_unload(tag, &sc->sc_is, map);
853 }
854
855 void
856 sbus_dmamap_sync(tag, map, offset, len, ops)
857 bus_dma_tag_t tag;
858 bus_dmamap_t map;
859 bus_addr_t offset;
860 bus_size_t len;
861 int ops;
862 {
863 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
864
865 if (ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) {
866 /* Flush the CPU then the IOMMU */
867 bus_dmamap_sync(tag->_parent, map, offset, len, ops);
868 iommu_dvmamap_sync(tag, &sc->sc_is, map, offset, len, ops);
869 }
870 if (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) {
871 /* Flush the IOMMU then the CPU */
872 iommu_dvmamap_sync(tag, &sc->sc_is, map, offset, len, ops);
873 bus_dmamap_sync(tag->_parent, map, offset, len, ops);
874 }
875 }
876
877 int
878 sbus_dmamem_alloc(tag, size, alignment, boundary, segs, nsegs, rsegs, flags)
879 bus_dma_tag_t tag;
880 bus_size_t size;
881 bus_size_t alignment;
882 bus_size_t boundary;
883 bus_dma_segment_t *segs;
884 int nsegs;
885 int *rsegs;
886 int flags;
887 {
888 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
889
890 return (iommu_dvmamem_alloc(tag, &sc->sc_is, size, alignment, boundary,
891 segs, nsegs, rsegs, flags));
892 }
893
894 void
895 sbus_dmamem_free(tag, segs, nsegs)
896 bus_dma_tag_t tag;
897 bus_dma_segment_t *segs;
898 int nsegs;
899 {
900 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
901
902 iommu_dvmamem_free(tag, &sc->sc_is, segs, nsegs);
903 }
904
905 int
906 sbus_dmamem_map(tag, segs, nsegs, size, kvap, flags)
907 bus_dma_tag_t tag;
908 bus_dma_segment_t *segs;
909 int nsegs;
910 size_t size;
911 caddr_t *kvap;
912 int flags;
913 {
914 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
915
916 return (iommu_dvmamem_map(tag, &sc->sc_is, segs, nsegs, size, kvap, flags));
917 }
918
919 void
920 sbus_dmamem_unmap(tag, kva, size)
921 bus_dma_tag_t tag;
922 caddr_t kva;
923 size_t size;
924 {
925 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
926
927 iommu_dvmamem_unmap(tag, &sc->sc_is, kva, size);
928 }
929