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