1 /* $NetBSD: sbus.c,v 1.73 2009/09/17 16:28:12 tsutsui Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 1992, 1993
34 * The Regents of the University of California. All rights reserved.
36 * This software was developed by the Computer Systems Engineering group
37 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
38 * contributed to Berkeley.
40 * All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Lawrence Berkeley Laboratory.
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
48 * 1. Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright
51 * notice, this list of conditions and the following disclaimer in the
52 * documentation and/or other materials provided with the distribution.
53 * 3. Neither the name of the University nor the names of its contributors
54 * may be used to endorse or promote products derived from this software
55 * without specific prior written permission.
57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * @(#)sbus.c 8.1 (Berkeley) 6/11/93
76 #include <sys/cdefs.h>
77 __KERNEL_RCSID(0, "$NetBSD: sbus.c,v 1.73 2009/09/17 16:28:12 tsutsui Exp $");
79 #include <sys/param.h>
80 #include <sys/malloc.h>
81 #include <sys/kernel.h>
82 #include <sys/systm.h>
83 #include <sys/device.h>
85 #include <uvm/uvm_extern.h>
87 #include <machine/autoconf.h>
88 #include <machine/bus.h>
89 #include <sparc/dev/sbusreg.h>
90 #include <dev/sbus/sbusvar.h>
91 #include <dev/sbus/xboxvar.h>
93 #include <sparc/sparc/iommuvar.h>
97 static int sbus_get_intr(struct sbus_softc
*, int,
98 struct openprom_intr
**, int *);
99 static void *sbus_intr_establish(
101 int, /* Sbus interrupt level */
102 int, /* `device class' priority */
103 int (*)(void *), /* handler */
104 void *, /* handler arg */
105 void (*)(void)); /* fast handler */
108 /* autoconfiguration driver */
109 int sbus_match_mainbus(device_t
, struct cfdata
*, void *);
110 int sbus_match_iommu(device_t
, struct cfdata
*, void *);
111 int sbus_match_xbox(device_t
, struct cfdata
*, void *);
112 void sbus_attach_mainbus(device_t
, device_t
, void *);
113 void sbus_attach_iommu(device_t
, device_t
, void *);
114 void sbus_attach_xbox(device_t
, device_t
, void *);
116 static int sbus_error(void);
117 int (*sbuserr_handler
)(void);
119 CFATTACH_DECL_NEW(sbus_mainbus
, sizeof(struct sbus_softc
),
120 sbus_match_mainbus
, sbus_attach_mainbus
, NULL
, NULL
);
122 CFATTACH_DECL_NEW(sbus_iommu
, sizeof(struct sbus_softc
),
123 sbus_match_iommu
, sbus_attach_iommu
, NULL
, NULL
);
125 CFATTACH_DECL_NEW(sbus_xbox
, sizeof(struct sbus_softc
),
126 sbus_match_xbox
, sbus_attach_xbox
, NULL
, NULL
);
128 extern struct cfdriver sbus_cd
;
130 static int sbus_mainbus_attached
;
132 /* The "primary" Sbus */
133 struct sbus_softc
*sbus_sc
;
135 /* If the PROM does not provide the `ranges' property, we make up our own */
136 struct openprom_range sbus_translations
[] = {
137 /* Assume a maximum of 4 Sbus slots, all mapped to on-board io space */
138 { 0, 0, PMAP_OBIO
, SBUS_ADDR(0,0), 1 << 25 },
139 { 1, 0, PMAP_OBIO
, SBUS_ADDR(1,0), 1 << 25 },
140 { 2, 0, PMAP_OBIO
, SBUS_ADDR(2,0), 1 << 25 },
141 { 3, 0, PMAP_OBIO
, SBUS_ADDR(3,0), 1 << 25 }
145 * Child devices receive the Sbus interrupt level in their attach
146 * arguments. We translate these to CPU IPLs using the following
147 * tables. Note: obio bus interrupt levels are identical to the
150 * The second set of tables is used when the Sbus interrupt level
151 * cannot be had from the PROM as an `interrupt' property. We then
152 * fall back on the `intr' property which contains the CPU IPL.
155 /* Translate Sbus interrupt level to processor IPL */
156 static int intr_sbus2ipl_4c
[] = {
157 0, 1, 2, 3, 5, 7, 8, 9
159 static int intr_sbus2ipl_4m
[] = {
160 0, 2, 3, 5, 7, 9, 11, 13
164 * This value is or'ed into the attach args' interrupt level cookie
165 * if the interrupt level comes from an `intr' property, i.e. it is
166 * not an Sbus interrupt level.
168 #define SBUS_INTR_COMPAT 0x80000000
172 * Print the location of some sbus-attached device (called just
173 * before attaching that device). If `sbus' is not NULL, the
174 * device was found but not configured; print the sbus as well.
175 * Return UNCONF (config_find ignores this if the device was configured).
178 sbus_print(void *args
, const char *busname
)
180 struct sbus_attach_args
*sa
= args
;
184 aprint_normal("%s at %s", sa
->sa_name
, busname
);
185 aprint_normal(" slot %d offset 0x%x", sa
->sa_slot
, sa
->sa_offset
);
186 for (i
= 0; i
< sa
->sa_nintr
; i
++) {
187 uint32_t level
= sa
->sa_intr
[i
].oi_pri
;
188 struct sbus_softc
*sc
=
189 (struct sbus_softc
*) sa
->sa_bustag
->cookie
;
191 aprint_normal(" level %d", level
& ~SBUS_INTR_COMPAT
);
192 if ((level
& SBUS_INTR_COMPAT
) == 0) {
193 int ipl
= sc
->sc_intr2ipl
[level
];
195 aprint_normal(" (ipl %d)", ipl
);
202 sbus_match_mainbus(device_t parent
, struct cfdata
*cf
, void *aux
)
204 struct mainbus_attach_args
*ma
= aux
;
206 if (CPU_ISSUN4
|| sbus_mainbus_attached
)
209 return (strcmp(cf
->cf_name
, ma
->ma_name
) == 0);
213 sbus_match_iommu(device_t parent
, struct cfdata
*cf
, void *aux
)
215 struct iommu_attach_args
*ia
= aux
;
220 return (strcmp(cf
->cf_name
, ia
->iom_name
) == 0);
224 sbus_match_xbox(device_t parent
, struct cfdata
*cf
, void *aux
)
226 struct xbox_attach_args
*xa
= aux
;
231 return (strcmp(cf
->cf_name
, xa
->xa_name
) == 0);
238 sbus_attach_mainbus(device_t parent
, device_t self
, void *aux
)
240 struct sbus_softc
*sc
= device_private(self
);
241 struct mainbus_attach_args
*ma
= aux
;
242 int node
= ma
->ma_node
;
244 sbus_mainbus_attached
= 1;
247 sc
->sc_bustag
= ma
->ma_bustag
;
248 sc
->sc_dmatag
= ma
->ma_dmatag
;
250 #if 0 /* sbus at mainbus (sun4c): `reg' prop is not control space */
251 if (ma
->ma_size
== 0)
252 printf("%s: no Sbus registers", device_xname(self
));
254 if (bus_space_map(ma
->ma_bustag
,
257 BUS_SPACE_MAP_LINEAR
,
259 panic("%s: can't map sbusbusreg", device_xname(self
));
263 /* Setup interrupt translation tables */
264 sc
->sc_intr2ipl
= CPU_ISSUN4C
269 * Record clock frequency for synchronous SCSI.
270 * IS THIS THE CORRECT DEFAULT??
272 sc
->sc_clockfreq
= prom_getpropint(node
, "clock-frequency", 25*1000*1000);
273 printf(": clock = %s MHz\n", clockfreq(sc
->sc_clockfreq
));
276 sbus_attach_common(sc
, "sbus", node
, NULL
);
281 sbus_attach_iommu(device_t parent
, device_t self
, void *aux
)
283 struct sbus_softc
*sc
= device_private(self
);
284 struct iommu_attach_args
*ia
= aux
;
285 int node
= ia
->iom_node
;
288 sc
->sc_bustag
= ia
->iom_bustag
;
289 sc
->sc_dmatag
= ia
->iom_dmatag
;
291 if (ia
->iom_nreg
== 0)
292 panic("%s: no Sbus registers", device_xname(self
));
294 if (bus_space_map(ia
->iom_bustag
,
295 BUS_ADDR(ia
->iom_reg
[0].oa_space
,
296 ia
->iom_reg
[0].oa_base
),
297 (bus_size_t
)ia
->iom_reg
[0].oa_size
,
298 BUS_SPACE_MAP_LINEAR
,
300 panic("%s: can't map sbusbusreg", device_xname(self
));
303 /* Setup interrupt translation tables */
304 sc
->sc_intr2ipl
= CPU_ISSUN4C
? intr_sbus2ipl_4c
: intr_sbus2ipl_4m
;
307 * Record clock frequency for synchronous SCSI.
308 * IS THIS THE CORRECT DEFAULT??
310 sc
->sc_clockfreq
= prom_getpropint(node
, "clock-frequency", 25*1000*1000);
311 printf(": clock = %s MHz\n", clockfreq(sc
->sc_clockfreq
));
314 sbuserr_handler
= sbus_error
;
315 sbus_attach_common(sc
, "sbus", node
, NULL
);
319 sbus_attach_xbox(device_t parent
, device_t self
, void *aux
)
321 struct sbus_softc
*sc
= device_private(self
);
322 struct xbox_attach_args
*xa
= aux
;
323 int node
= xa
->xa_node
;
325 sc
->sc_bustag
= xa
->xa_bustag
;
326 sc
->sc_dmatag
= xa
->xa_dmatag
;
328 /* Setup interrupt translation tables */
329 sc
->sc_intr2ipl
= CPU_ISSUN4C
? intr_sbus2ipl_4c
: intr_sbus2ipl_4m
;
332 * Record clock frequency for synchronous SCSI.
333 * IS THIS THE CORRECT DEFAULT??
335 sc
->sc_clockfreq
= prom_getpropint(node
, "clock-frequency", 25*1000*1000);
336 printf(": clock = %s MHz\n", clockfreq(sc
->sc_clockfreq
));
338 sbus_attach_common(sc
, "sbus", node
, NULL
);
342 sbus_attach_common(struct sbus_softc
*sc
, const char *busname
, int busnode
,
343 const char * const *specials
)
345 int node0
, node
, error
;
347 const char *const *ssp
;
349 struct sbus_attach_args sa
;
351 if ((sbt
= bus_space_tag_alloc(sc
->sc_bustag
, sc
)) == NULL
) {
352 printf("%s: attach: out of memory\n",
353 device_xname(sc
->sc_dev
));
356 sbt
->sparc_intr_establish
= sbus_intr_establish
;
359 * Get the SBus burst transfer size if burst transfers are supported
361 sc
->sc_burst
= prom_getpropint(busnode
, "burst-sizes", 0);
366 * Some models (e.g. SS20) erroneously report 64-bit
367 * burst capability. We mask it out here for all SUN4Ms,
368 * since probably no member of that class supports
369 * 64-bit Sbus bursts.
371 sc
->sc_burst
&= ~SBUS_BURST_64
;
375 * Collect address translations from the OBP.
377 error
= prom_getprop(busnode
, "ranges", sizeof(struct rom_range
),
378 &sbt
->nranges
, &sbt
->ranges
);
383 /* Fall back to our own `range' construction */
384 sbt
->ranges
= sbus_translations
;
386 sizeof(sbus_translations
)/sizeof(sbus_translations
[0]);
389 panic("%s: error getting ranges property",
390 device_xname(sc
->sc_dev
));
394 * Loop through ROM children, fixing any relative addresses
395 * and then configuring each device.
396 * `specials' is an array of device names that are treated
399 node0
= firstchild(busnode
);
400 for (ssp
= specials
; ssp
!= NULL
&& *(sp
= *ssp
) != 0; ssp
++) {
401 if ((node
= findnode(node0
, sp
)) == 0) {
402 panic("could not find %s amongst %s devices",
406 if (sbus_setup_attach_args(sc
, sbt
, sc
->sc_dmatag
,
408 panic("sbus_attach: %s: incomplete", sp
);
410 (void) config_found(sc
->sc_dev
, (void *)&sa
, sbus_print
);
411 sbus_destroy_attach_args(&sa
);
414 for (node
= node0
; node
; node
= nextsibling(node
)) {
415 char *name
= prom_getpropstring(node
, "name");
416 for (ssp
= specials
, sp
= NULL
;
417 ssp
!= NULL
&& (sp
= *ssp
) != NULL
;
419 if (strcmp(name
, sp
) == 0)
423 /* Already configured as an "early" device */
426 if (sbus_setup_attach_args(sc
, sbt
, sc
->sc_dmatag
,
428 printf("sbus_attach: %s: incomplete\n", name
);
431 (void) config_found(sc
->sc_dev
, (void *)&sa
, sbus_print
);
432 sbus_destroy_attach_args(&sa
);
437 sbus_setup_attach_args(struct sbus_softc
*sc
,
438 bus_space_tag_t bustag
, bus_dma_tag_t dmatag
, int node
,
439 struct sbus_attach_args
*sa
)
443 memset(sa
, 0, sizeof(struct sbus_attach_args
));
444 error
= prom_getprop(node
, "name", 1, &n
, &sa
->sa_name
);
447 sa
->sa_name
[n
] = '\0';
449 sa
->sa_bustag
= bustag
;
450 sa
->sa_dmatag
= dmatag
;
452 sa
->sa_frequency
= sc
->sc_clockfreq
;
454 error
= prom_getprop(node
, "reg", sizeof(struct openprom_addr
),
455 &sa
->sa_nreg
, &sa
->sa_reg
);
458 if (error
!= ENOENT
||
459 !node_has_property(node
, "device_type") ||
460 strcmp(prom_getpropstringA(node
, "device_type", buf
, sizeof buf
),
461 "hierarchical") != 0)
464 for (n
= 0; n
< sa
->sa_nreg
; n
++) {
465 /* Convert to relative addressing, if necessary */
466 uint32_t base
= sa
->sa_reg
[n
].oa_base
;
467 if (SBUS_ABS(base
)) {
468 sa
->sa_reg
[n
].oa_space
= SBUS_ABS_TO_SLOT(base
);
469 sa
->sa_reg
[n
].oa_base
= SBUS_ABS_TO_OFFSET(base
);
473 if ((error
= sbus_get_intr(sc
, node
, &sa
->sa_intr
, &sa
->sa_nintr
)) != 0)
476 error
= prom_getprop(node
, "address", sizeof(uint32_t),
477 &sa
->sa_npromvaddrs
, &sa
->sa_promvaddrs
);
478 if (error
!= 0 && error
!= ENOENT
)
485 sbus_destroy_attach_args(struct sbus_attach_args
*sa
)
488 if (sa
->sa_name
!= NULL
)
489 free(sa
->sa_name
, M_DEVBUF
);
491 if (sa
->sa_nreg
!= 0)
492 free(sa
->sa_reg
, M_DEVBUF
);
495 free(sa
->sa_intr
, M_DEVBUF
);
497 if (sa
->sa_promvaddrs
)
498 free(sa
->sa_promvaddrs
, M_DEVBUF
);
500 memset(sa
, 0, sizeof(struct sbus_attach_args
));/*DEBUG*/
504 sbus_bus_addr(bus_space_tag_t t
, u_int btype
, u_int offset
)
507 /* XXX: sbus_bus_addr should be g/c'ed */
508 return (BUS_ADDR(btype
, offset
));
513 * Get interrupt attributes for an Sbus device.
516 sbus_get_intr(struct sbus_softc
*sc
, int node
,
517 struct openprom_intr
**ipp
, int *np
)
520 uint32_t *ipl
= NULL
;
523 * The `interrupts' property contains the Sbus interrupt level.
525 if (prom_getprop(node
, "interrupts", sizeof(int), np
,
527 /* Change format to an `struct openprom_intr' array */
528 struct openprom_intr
*ip
;
529 ip
= malloc(*np
* sizeof(struct openprom_intr
), M_DEVBUF
,
535 for (n
= 0; n
< *np
; n
++) {
536 ip
[n
].oi_pri
= ipl
[n
];
545 * Fall back on `intr' property.
548 error
= prom_getprop(node
, "intr", sizeof(struct openprom_intr
),
552 for (n
= *np
; n
-- > 0;) {
553 (*ipp
)[n
].oi_pri
&= 0xf;
554 (*ipp
)[n
].oi_pri
|= SBUS_INTR_COMPAT
;
567 * Install an interrupt handler for an Sbus device.
570 sbus_intr_establish(bus_space_tag_t t
, int pri
, int level
,
571 int (*handler
)(void *), void *arg
,
572 void (*fastvec
)(void))
574 struct sbus_softc
*sc
= t
->cookie
;
578 ih
= (struct intrhand
*)
579 malloc(sizeof(struct intrhand
), M_DEVBUF
, M_NOWAIT
);
584 * Translate Sbus interrupt priority to CPU interrupt level
586 if ((pri
& SBUS_INTR_COMPAT
) != 0)
587 pil
= pri
& ~SBUS_INTR_COMPAT
;
589 pil
= sc
->sc_intr2ipl
[pri
];
591 ih
->ih_fun
= handler
;
593 intr_establish(pil
, level
, ih
, fastvec
, false);
600 struct sbus_softc
*sc
= sbus_sc
;
601 bus_space_handle_t bh
= sc
->sc_bh
;
604 static int straytime
, nstray
;
607 afsr
= bus_space_read_4(sc
->sc_bustag
, bh
, SBUS_AFSR_REG
);
608 afva
= bus_space_read_4(sc
->sc_bustag
, bh
, SBUS_AFAR_REG
);
609 snprintb(bits
, sizeof(bits
), SBUS_AFSR_BITS
, afsr
);
610 printf("sbus error:\n\tAFSR %s\n", bits
);
611 printf("\taddress: 0x%x%x\n", afsr
& SBUS_AFSR_PAH
, afva
);
613 /* For now, do the same dance as on stray interrupts */
614 timesince
= time_uptime
- straytime
;
615 if (timesince
<= 10) {
617 panic("too many SBus errors");
619 straytime
= time_uptime
;
623 /* Unlock registers and clear interrupt */
624 bus_space_write_4(sc
->sc_bustag
, bh
, SBUS_AFSR_REG
, afsr
);