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