1 /* $NetBSD: sbus.c,v 1.84 2009/05/17 01:28:27 tsutsui Exp $ */
4 * Copyright (c) 1999-2002 Eduardo Horvath
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: sbus.c,v 1.84 2009/05/17 01:28:27 tsutsui Exp $");
41 #include <sys/param.h>
42 #include <sys/extent.h>
43 #include <sys/malloc.h>
44 #include <sys/systm.h>
45 #include <sys/device.h>
46 #include <sys/reboot.h>
48 #include <machine/bus.h>
49 #include <machine/openfirm.h>
51 #include <sparc64/dev/iommureg.h>
52 #include <sparc64/dev/iommuvar.h>
53 #include <sparc64/dev/sbusreg.h>
54 #include <dev/sbus/sbusvar.h>
56 #include <uvm/uvm_extern.h>
58 #include <machine/autoconf.h>
59 #include <machine/cpu.h>
60 #include <machine/sparc64.h>
66 #define DPRINTF(l, s) do { if (sbus_debug & l) printf s; } while (0)
73 static bus_dma_tag_t
sbus_alloc_dmatag(struct sbus_softc
*);
74 static int sbus_get_intr(struct sbus_softc
*, int, struct openprom_intr
**,
76 static int sbus_overtemp(void *);
77 static int _sbus_bus_map(
79 bus_addr_t
, /*offset*/
82 vaddr_t
, /* XXX unused -- compat w/sparc */
83 bus_space_handle_t
*);
84 static void *sbus_intr_establish(
86 int, /*`device class' priority*/
87 int, /*Sbus interrupt level*/
88 int (*)(void *), /*handler*/
89 void *, /*handler arg*/
90 void (*)(void)); /*optional fast trap*/
93 /* autoconfiguration driver */
94 int sbus_match(device_t
, cfdata_t
, void *);
95 void sbus_attach(device_t
, device_t
, void *);
98 CFATTACH_DECL_NEW(sbus
, sizeof(struct sbus_softc
),
99 sbus_match
, sbus_attach
, NULL
, NULL
);
101 extern struct cfdriver sbus_cd
;
106 static int sbus_dmamap_create(bus_dma_tag_t
, bus_size_t
, int, bus_size_t
,
107 bus_size_t
, int, bus_dmamap_t
*);
110 * Child devices receive the Sbus interrupt level in their attach
111 * arguments. We translate these to CPU IPLs using the following
112 * tables. Note: obio bus interrupt levels are identical to the
115 * The second set of tables is used when the Sbus interrupt level
116 * cannot be had from the PROM as an `interrupt' property. We then
117 * fall back on the `intr' property which contains the CPU IPL.
121 * This value is or'ed into the attach args' interrupt level cookie
122 * if the interrupt level comes from an `intr' property, i.e. it is
123 * not an Sbus interrupt level.
125 #define SBUS_INTR_COMPAT 0x80000000
129 * Print the location of some sbus-attached device (called just
130 * before attaching that device). If `sbus' is not NULL, the
131 * device was found but not configured; print the sbus as well.
132 * Return UNCONF (config_find ignores this if the device was configured).
135 sbus_print(void *args
, const char *busname
)
137 struct sbus_attach_args
*sa
= args
;
141 aprint_normal("%s at %s", sa
->sa_name
, busname
);
142 aprint_normal(" slot %ld offset 0x%lx", (long)sa
->sa_slot
,
143 (u_long
)sa
->sa_offset
);
144 for (i
= 0; i
< sa
->sa_nintr
; i
++) {
145 struct openprom_intr
*sbi
= &sa
->sa_intr
[i
];
147 aprint_normal(" vector %lx ipl %ld",
149 (long)INTLEV(sbi
->oi_pri
));
155 sbus_match(device_t parent
, cfdata_t cf
, void *aux
)
157 struct mainbus_attach_args
*ma
= aux
;
159 return (strcmp(cf
->cf_name
, ma
->ma_name
) == 0);
166 sbus_attach(device_t parent
, device_t self
, void *aux
)
168 struct sbus_softc
*sc
= device_private(self
);
169 struct mainbus_attach_args
*ma
= aux
;
173 int node
= ma
->ma_node
;
176 struct sbus_attach_args sa
;
179 sc
->sc_bustag
= ma
->ma_bustag
;
180 sc
->sc_dmatag
= ma
->ma_dmatag
;
181 sc
->sc_ign
= ma
->ma_interrupts
[0] & INTMAP_IGN
;
183 /* XXXX Use sysio PROM mappings for interrupt vector regs. */
184 sparc_promaddr_to_handle(sc
->sc_bustag
, ma
->ma_address
[0], &sc
->sc_bh
);
185 sc
->sc_sysio
= (struct sysioreg
*)bus_space_vaddr(sc
->sc_bustag
,
190 * 32-bit kernels use virtual addresses for bus space operations
191 * so we may as well use the prom VA.
193 * 64-bit kernels use physical addresses for bus space operations
194 * so mapping this in again will reduce TLB thrashing.
196 if (bus_space_map(sc
->sc_bustag
, ma
->ma_reg
[0].ur_paddr
,
197 ma
->ma_reg
[0].ur_len
, 0, &sc
->sc_bh
) != 0) {
198 aprint_error_dev(self
, "cannot map registers\n");
204 * Record clock frequency for synchronous SCSI.
205 * IS THIS THE CORRECT DEFAULT??
207 sc
->sc_clockfreq
= prom_getpropint(node
, "clock-frequency",
209 printf(": clock = %s MHz\n", clockfreq(sc
->sc_clockfreq
));
211 sbt
= bus_space_tag_alloc(sc
->sc_bustag
, sc
);
212 sbt
->type
= SBUS_BUS_SPACE
;
213 sbt
->sparc_bus_map
= _sbus_bus_map
;
214 sbt
->sparc_intr_establish
= sbus_intr_establish
;
216 sc
->sc_dmatag
= sbus_alloc_dmatag(sc
);
219 * Get the SBus burst transfer size if burst transfers are supported
221 sc
->sc_burst
= prom_getpropint(node
, "burst-sizes", 0);
224 * Collect address translations from the OBP.
226 error
= prom_getprop(node
, "ranges", sizeof(struct openprom_range
),
227 &sbt
->nranges
, &sbt
->ranges
);
229 panic("%s: error getting ranges property", device_xname(self
));
231 /* initialize the IOMMU */
233 /* punch in our copies */
234 sc
->sc_is
.is_bustag
= sc
->sc_bustag
;
235 bus_space_subregion(sc
->sc_bustag
, sc
->sc_bh
,
236 (vaddr_t
)&((struct sysioreg
*)NULL
)->sys_iommu
,
237 sizeof (struct iommureg
), &sc
->sc_is
.is_iommu
);
239 /* initialize our strbuf_ctl */
240 sc
->sc_is
.is_sb
[0] = &sc
->sc_sb
;
241 sc
->sc_sb
.sb_is
= &sc
->sc_is
;
242 bus_space_subregion(sc
->sc_bustag
, sc
->sc_bh
,
243 (vaddr_t
)&((struct sysioreg
*)NULL
)->sys_strbuf
,
244 sizeof (struct iommu_strbuf
), &sc
->sc_sb
.sb_sb
);
245 /* Point sb_flush to our flush buffer. */
246 sc
->sc_sb
.sb_flush
= &sc
->sc_flush
;
248 /* give us a nice name.. */
249 name
= (char *)malloc(32, M_DEVBUF
, M_NOWAIT
);
251 panic("couldn't malloc iommu name");
252 snprintf(name
, 32, "%s dvma", device_xname(self
));
254 iommu_init(name
, &sc
->sc_is
, 0, -1);
256 /* Enable the over temp intr */
257 ih
= (struct intrhand
*)
258 malloc(sizeof(struct intrhand
), M_DEVBUF
, M_NOWAIT
);
259 ih
->ih_map
= &sc
->sc_sysio
->therm_int_map
;
260 ih
->ih_clr
= NULL
; /* &sc->sc_sysio->therm_clr_int; */
261 ih
->ih_fun
= sbus_overtemp
;
263 ih
->ih_pil
= (1<<ipl
);
264 ih
->ih_number
= INTVEC(*(ih
->ih_map
));
265 intr_establish(ipl
, true, ih
);
266 *(ih
->ih_map
) |= INTMAP_V
|(CPU_UPAID
<< INTMAP_TID_SHIFT
);
269 * Note: the stupid SBUS IOMMU ignores the high bits of an address, so a
270 * NULL DMA pointer will be translated by the first page of the IOTSB.
271 * To avoid bugs we'll alloc and ignore the first entry in the IOTSB.
276 if (extent_alloc_subregion(sc
->sc_is
.is_dvmamap
,
277 sc
->sc_is
.is_dvmabase
, sc
->sc_is
.is_dvmabase
+ PAGE_SIZE
,
278 PAGE_SIZE
, PAGE_SIZE
, 0, EX_NOWAIT
|EX_BOUNDZERO
,
279 (u_long
*)&dummy
) != 0)
280 panic("sbus iommu: can't toss first dvma page");
284 * Loop through ROM children, fixing any relative addresses
285 * and then configuring each device.
286 * `specials' is an array of device names that are treated
289 node0
= OF_child(node
);
290 for (node
= node0
; node
; node
= OF_peer(node
)) {
291 char *name1
= prom_getpropstring(node
, "name");
293 if (sbus_setup_attach_args(sc
, sbt
, sc
->sc_dmatag
,
295 printf("sbus_attach: %s: incomplete\n", name1
);
298 (void) config_found(self
, &sa
, sbus_print
);
299 sbus_destroy_attach_args(&sa
);
304 sbus_setup_attach_args(struct sbus_softc
*sc
, bus_space_tag_t bustag
,
305 bus_dma_tag_t dmatag
, int node
, struct sbus_attach_args
*sa
)
307 /*struct openprom_addr sbusreg;*/
312 memset(sa
, 0, sizeof(struct sbus_attach_args
));
314 error
= prom_getprop(node
, "name", 1, &n
, &sa
->sa_name
);
317 sa
->sa_name
[n
] = '\0';
319 sa
->sa_bustag
= bustag
;
320 sa
->sa_dmatag
= dmatag
;
322 sa
->sa_frequency
= sc
->sc_clockfreq
;
324 error
= prom_getprop(node
, "reg", sizeof(struct openprom_addr
),
325 &sa
->sa_nreg
, &sa
->sa_reg
);
328 if (error
!= ENOENT
||
329 !node_has_property(node
, "device_type") ||
330 strcmp(prom_getpropstringA(node
, "device_type", buf
, sizeof buf
),
331 "hierarchical") != 0)
334 for (n
= 0; n
< sa
->sa_nreg
; n
++) {
335 /* Convert to relative addressing, if necessary */
336 uint32_t base
= sa
->sa_reg
[n
].oa_base
;
337 if (SBUS_ABS(base
)) {
338 sa
->sa_reg
[n
].oa_space
= SBUS_ABS_TO_SLOT(base
);
339 sa
->sa_reg
[n
].oa_base
= SBUS_ABS_TO_OFFSET(base
);
343 if ((error
= sbus_get_intr(sc
, node
, &sa
->sa_intr
, &sa
->sa_nintr
,
347 error
= prom_getprop(node
, "address", sizeof(uint32_t),
348 &sa
->sa_npromvaddrs
, &sa
->sa_promvaddrs
);
349 if (error
!= 0 && error
!= ENOENT
)
356 sbus_destroy_attach_args(struct sbus_attach_args
*sa
)
358 if (sa
->sa_name
!= NULL
)
359 free(sa
->sa_name
, M_DEVBUF
);
361 if (sa
->sa_nreg
!= 0)
362 free(sa
->sa_reg
, M_DEVBUF
);
365 free(sa
->sa_intr
, M_DEVBUF
);
367 if (sa
->sa_promvaddrs
)
368 free((void *)sa
->sa_promvaddrs
, M_DEVBUF
);
370 memset(sa
, 0, sizeof(struct sbus_attach_args
)); /*DEBUG*/
375 _sbus_bus_map(bus_space_tag_t t
, bus_addr_t addr
, bus_size_t size
, int flags
,
376 vaddr_t v
, bus_space_handle_t
*hp
)
380 if (t
->ranges
!= NULL
) {
381 if ((error
= bus_space_translate_address_generic(
382 t
->ranges
, t
->nranges
, &addr
)) != 0)
386 return (bus_space_map(t
->parent
, addr
, size
, flags
, hp
));
391 sbus_bus_addr(bus_space_tag_t t
, u_int btype
, u_int offset
)
394 struct openprom_range
*rp
;
397 for (i
= 0; i
< t
->nranges
; i
++) {
399 if (rp
->or_child_space
!= slot
)
402 return BUS_ADDR(rp
->or_parent_space
,
403 rp
->or_parent_base
+ offset
);
411 * Handle an overtemp situation.
413 * SPARCs have temperature sensors which generate interrupts
414 * if the machine's temperature exceeds a certain threshold.
415 * This handles the interrupt and powers off the machine.
416 * The same needs to be done to PCI controller drivers.
419 sbus_overtemp(void *arg
)
421 /* Should try a clean shutdown first */
422 printf("DANGER: OVER TEMPERATURE detected\nShutting down...\n");
424 cpu_reboot(RB_POWERDOWN
|RB_HALT
, NULL
);
428 * Get interrupt attributes for an Sbus device.
431 sbus_get_intr(struct sbus_softc
*sc
, int node
, struct openprom_intr
**ipp
,
439 * The `interrupts' property contains the Sbus interrupt level.
442 if (prom_getprop(node
, "interrupts", sizeof(int), np
, &ipl
) == 0) {
443 struct openprom_intr
*ip
;
446 /* Default to interrupt level 2 -- otherwise unused */
447 pri
= INTLEVENCODE(2);
449 /* Change format to an `struct sbus_intr' array */
450 ip
= malloc(*np
* sizeof(struct openprom_intr
), M_DEVBUF
,
456 * Now things get ugly. We need to take this value which is
457 * the interrupt vector number and encode the IPL into it
458 * somehow. Luckily, the interrupt vector has lots of free
459 * space and we can easily stuff the IPL in there for a while.
461 prom_getpropstringA(node
, "device_type", buf
, sizeof buf
);
463 prom_getpropstringA(node
, "name", buf
, sizeof buf
);
465 for (i
= 0; intrmap
[i
].in_class
; i
++)
466 if (strcmp(intrmap
[i
].in_class
, buf
) == 0) {
467 pri
= INTLEVENCODE(intrmap
[i
].in_lev
);
472 * Sbus card devices need the slot number encoded into
473 * the vector as this is generally not done.
475 if ((ipl
[0] & INTMAP_OBIO
) == 0)
478 for (n
= 0; n
< *np
; n
++) {
480 * We encode vector and priority into sbi_pri so we
481 * can pass them as a unit. This will go away if
482 * sbus_establish ever takes an sbus_intr instead
483 * of an integer level.
484 * Stuff the real vector in sbi_vec.
487 ip
[n
].oi_pri
= pri
|ipl
[n
];
488 ip
[n
].oi_vec
= ipl
[n
];
499 * Install an interrupt handler for an Sbus device.
502 sbus_intr_establish(bus_space_tag_t t
, int pri
, int level
,
503 int (*handler
)(void *), void *arg
, void (*fastvec
)(void))
505 struct sbus_softc
*sc
= t
->cookie
;
510 ih
= (struct intrhand
*)
511 malloc(sizeof(struct intrhand
), M_DEVBUF
, M_NOWAIT
);
515 if ((vec
& SBUS_INTR_COMPAT
) != 0)
516 ipl
= vec
& ~SBUS_INTR_COMPAT
;
518 /* Decode and remove IPL */
522 ("\nsbus: intr[%ld]%lx: %lx\nHunting for IRQ...\n",
523 (long)ipl
, (long)vec
, (u_long
)intrlev
[vec
]));
524 if ((vec
& INTMAP_OBIO
) == 0) {
525 /* We're in an SBUS slot */
526 /* Register the map and clear intr registers */
528 int slot
= INTSLOT(pri
);
530 ih
->ih_map
= &(&sc
->sc_sysio
->sbus_slot0_int
)[slot
];
531 ih
->ih_clr
= &sc
->sc_sysio
->sbus0_clr_int
[vec
];
533 if (sbus_debug
& SDB_INTR
) {
534 int64_t imap
= *ih
->ih_map
;
536 printf("SBUS %lx IRQ as %llx in slot %d\n",
537 (long)vec
, (long long)imap
, slot
);
538 printf("\tmap addr %p clr addr %p\n",
539 ih
->ih_map
, ih
->ih_clr
);
542 /* Enable the interrupt */
543 vec
|= INTMAP_V
| sc
->sc_ign
|
544 (CPU_UPAID
<< INTMAP_TID_SHIFT
);
547 int64_t *intrptr
= &sc
->sc_sysio
->scsi_int_map
;
553 for (i
= 0; &intrptr
[i
] <=
554 (int64_t *)&sc
->sc_sysio
->reserved_int_map
&&
555 INTVEC(imap
= intrptr
[i
]) != INTVEC(vec
); i
++)
557 if (INTVEC(imap
) == INTVEC(vec
)) {
559 ("OBIO %lx IRQ as %lx in slot %d\n",
560 vec
, (long)imap
, i
));
561 /* Register the map and clear intr registers */
562 ih
->ih_map
= &intrptr
[i
];
563 intrptr
= (int64_t *)&sc
->sc_sysio
->scsi_clr_int
;
564 ih
->ih_clr
= &intrptr
[i
];
565 /* Enable the interrupt */
567 |(CPU_UPAID
<< INTMAP_TID_SHIFT
);
569 *(ih
->ih_map
) = imap
;
571 panic("IRQ not found!");
575 if (sbus_debug
& SDB_INTR
) { long i
; for (i
= 0; i
< 400000000; i
++); }
578 ih
->ih_fun
= handler
;
581 ih
->ih_pil
= (1<<ipl
);
582 intr_establish(ipl
, level
!= IPL_VM
, ih
);
587 sbus_alloc_dmatag(struct sbus_softc
*sc
)
589 bus_dma_tag_t sdt
, psdt
= sc
->sc_dmatag
;
591 sdt
= (bus_dma_tag_t
)
592 malloc(sizeof(struct sparc_bus_dma_tag
), M_DEVBUF
, M_NOWAIT
);
599 #define PCOPY(x) sdt->x = psdt->x
600 sdt
->_dmamap_create
= sbus_dmamap_create
;
601 PCOPY(_dmamap_destroy
);
602 sdt
->_dmamap_load
= iommu_dvmamap_load
;
603 PCOPY(_dmamap_load_mbuf
);
604 PCOPY(_dmamap_load_uio
);
605 sdt
->_dmamap_load_raw
= iommu_dvmamap_load_raw
;
606 sdt
->_dmamap_unload
= iommu_dvmamap_unload
;
607 sdt
->_dmamap_sync
= iommu_dvmamap_sync
;
608 sdt
->_dmamem_alloc
= iommu_dvmamem_alloc
;
609 sdt
->_dmamem_free
= iommu_dvmamem_free
;
610 sdt
->_dmamem_map
= iommu_dvmamem_map
;
611 sdt
->_dmamem_unmap
= iommu_dvmamem_unmap
;
619 sbus_dmamap_create(bus_dma_tag_t t
, bus_size_t size
, int nsegments
,
620 bus_size_t maxsegsz
, bus_size_t boundary
, int flags
,
623 struct sbus_softc
*sc
= t
->_cookie
;
626 error
= bus_dmamap_create(t
->_parent
, size
, nsegments
, maxsegsz
,
627 boundary
, flags
, dmamp
);
629 (*dmamp
)->_dm_cookie
= &sc
->sc_sb
;