1 /*-
2 * Copyright (c) 1998 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Paul Kranenburg.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the NetBSD
19 * Foundation, Inc. and its contributors.
20 * 4. Neither the name of The NetBSD Foundation nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36 /*
37 * Copyright (c) 1992, 1993
38 * The Regents of the University of California. All rights reserved.
39 *
40 * This software was developed by the Computer Systems Engineering group
41 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
42 * contributed to Berkeley.
43 *
44 * All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Lawrence Berkeley Laboratory.
48 *
49 * Redistribution and use in source and binary forms, with or without
50 * modification, are permitted provided that the following conditions
51 * are met:
52 * 1. Redistributions of source code must retain the above copyright
53 * notice, this list of conditions and the following disclaimer.
54 * 2. Redistributions in binary form must reproduce the above copyright
55 * notice, this list of conditions and the following disclaimer in the
56 * documentation and/or other materials provided with the distribution.
57 * 3. All advertising materials mentioning features or use of this software
58 * must display the following acknowledgement:
59 * This product includes software developed by the University of
60 * California, Berkeley and its contributors.
61 * 4. 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 /*
78 * Copyright (c) 1999 Eduardo Horvath
79 * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
80 * All rights reserved.
81 *
82 * Redistribution and use in source and binary forms, with or without
83 * modification, are permitted provided that the following conditions
84 * are met:
85 * 1. Redistributions of source code must retain the above copyright
86 * notice, this list of conditions and the following disclaimer.
87 *
88 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
89 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
90 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
91 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
92 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
93 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
94 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
95 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
96 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
97 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
98 * SUCH DAMAGE.
99 *
100 * from: @(#)sbus.c 8.1 (Berkeley) 6/11/93
101 * from: NetBSD: sbus.c,v 1.46 2001/10/07 20:30:41 eeh Exp
102 *
103 * $FreeBSD: releng/5.0/sys/sparc64/sbus/sbus.c 107477 2002-12-01 23:30:26Z tmm $
104 */
105
106 /*
107 * Sbus support.
108 */
109 #include <sys/param.h>
110 #include <sys/systm.h>
111 #include <sys/bus.h>
112 #include <sys/kernel.h>
113 #include <sys/malloc.h>
114 #include <sys/pcpu.h>
115 #include <sys/reboot.h>
116
117 #include <ofw/openfirm.h>
118
119 #include <machine/bus.h>
120 #include <machine/iommureg.h>
121 #include <machine/bus_common.h>
122 #include <machine/frame.h>
123 #include <machine/intr_machdep.h>
124 #include <machine/nexusvar.h>
125 #include <machine/ofw_upa.h>
126 #include <machine/resource.h>
127
128 #include <sys/rman.h>
129
130 #include <machine/iommuvar.h>
131
132 #include <sparc64/sbus/ofw_sbus.h>
133 #include <sparc64/sbus/sbusreg.h>
134 #include <sparc64/sbus/sbusvar.h>
135
136
137 #ifdef DEBUG
138 #define SDB_DVMA 0x1
139 #define SDB_INTR 0x2
140 int sbus_debug = 0;
141 #define DPRINTF(l, s) do { if (sbus_debug & l) printf s; } while (0)
142 #else
143 #define DPRINTF(l, s)
144 #endif
145
146 struct sbus_devinfo {
147 int sdi_burstsz;
148 char *sdi_compat;
149 char *sdi_name; /* PROM name */
150 phandle_t sdi_node; /* PROM node */
151 int sdi_slot;
152 char *sdi_type; /* PROM name */
153
154 struct resource_list sdi_rl;
155 };
156
157 /* Range descriptor, allocated for each sc_range. */
158 struct sbus_rd {
159 bus_addr_t rd_poffset;
160 bus_addr_t rd_pend;
161 int rd_slot;
162 bus_addr_t rd_coffset;
163 bus_addr_t rd_cend;
164 struct rman rd_rman;
165 bus_space_handle_t rd_bushandle;
166 struct resource *rd_res;
167 };
168
169 struct sbus_softc {
170 bus_space_tag_t sc_bustag;
171 bus_space_handle_t sc_bushandle;
172 bus_dma_tag_t sc_dmatag;
173 bus_dma_tag_t sc_cdmatag;
174 bus_space_tag_t sc_cbustag;
175 int sc_clockfreq; /* clock frequency (in Hz) */
176 struct upa_regs *sc_reg;
177 int sc_nreg;
178 int sc_nrange;
179 struct sbus_rd *sc_rd;
180 int sc_burst; /* burst transfer sizes supported */
181 int *sc_intr_compat;/* `intr' property to sbus compat */
182
183 struct resource *sc_sysio_res;
184 int sc_ign; /* Interrupt group number for this sysio */
185 struct iommu_state sc_is; /* IOMMU state, see iommureg.h */
186
187 struct resource *sc_ot_ires;
188 void *sc_ot_ihand;
189 struct resource *sc_pf_ires;
190 void *sc_pf_ihand;
191 };
192
193 struct sbus_clr {
194 struct sbus_softc *scl_sc;
195 bus_addr_t scl_clr; /* clear register */
196 driver_intr_t *scl_handler; /* handler to call */
197 void *scl_arg; /* argument for the handler */
198 void *scl_cookie; /* interrupt cookie of parent bus */
199 };
200
201 #define SYSIO_READ8(sc, off) \
202 bus_space_read_8((sc)->sc_bustag, (sc)->sc_bushandle, (off))
203 #define SYSIO_WRITE8(sc, off, v) \
204 bus_space_write_8((sc)->sc_bustag, (sc)->sc_bushandle, (off), (v))
205
206 static int sbus_probe(device_t dev);
207 static int sbus_print_child(device_t dev, device_t child);
208 static void sbus_probe_nomatch(device_t dev, device_t child);
209 static int sbus_read_ivar(device_t, device_t, int, u_long *);
210 static struct resource_list *sbus_get_resource_list(device_t dev,
211 device_t child);
212 static int sbus_setup_intr(device_t, device_t, struct resource *, int,
213 driver_intr_t *, void *, void **);
214 static int sbus_teardown_intr(device_t, device_t, struct resource *, void *);
215 static struct resource *sbus_alloc_resource(device_t, device_t, int, int *,
216 u_long, u_long, u_long, u_int);
217 static int sbus_activate_resource(device_t, device_t, int, int,
218 struct resource *);
219 static int sbus_deactivate_resource(device_t, device_t, int, int,
220 struct resource *);
221 static int sbus_release_resource(device_t, device_t, int, int,
222 struct resource *);
223
224 static struct sbus_devinfo * sbus_setup_dinfo(struct sbus_softc *sc,
225 phandle_t node, char *name);
226 static void sbus_destroy_dinfo(struct sbus_devinfo *dinfo);
227 static void sbus_intr_stub(void *);
228 static bus_space_tag_t sbus_alloc_bustag(struct sbus_softc *);
229 static void sbus_overtemp(void *);
230 static void sbus_pwrfail(void *);
231
232 /*
233 * DVMA routines
234 */
235 static int sbus_dmamap_create(bus_dma_tag_t, bus_dma_tag_t, int,
236 bus_dmamap_t *);
237 static int sbus_dmamap_destroy(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t);
238 static int sbus_dmamap_load(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t, void *,
239 bus_size_t, bus_dmamap_callback_t *, void *, int);
240 static void sbus_dmamap_unload(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t);
241 static void sbus_dmamap_sync(bus_dma_tag_t, bus_dma_tag_t, bus_dmamap_t,
242 bus_dmasync_op_t);
243 static int sbus_dmamem_alloc(bus_dma_tag_t, bus_dma_tag_t, void **, int,
244 bus_dmamap_t *);
245 static void sbus_dmamem_free(bus_dma_tag_t, bus_dma_tag_t, void *,
246 bus_dmamap_t);
247
248 static device_method_t sbus_methods[] = {
249 /* Device interface */
250 DEVMETHOD(device_probe, sbus_probe),
251 DEVMETHOD(device_attach, bus_generic_attach),
252
253 /* Bus interface */
254 DEVMETHOD(bus_print_child, sbus_print_child),
255 DEVMETHOD(bus_probe_nomatch, sbus_probe_nomatch),
256 DEVMETHOD(bus_read_ivar, sbus_read_ivar),
257 DEVMETHOD(bus_setup_intr, sbus_setup_intr),
258 DEVMETHOD(bus_teardown_intr, sbus_teardown_intr),
259 DEVMETHOD(bus_alloc_resource, sbus_alloc_resource),
260 DEVMETHOD(bus_activate_resource, sbus_activate_resource),
261 DEVMETHOD(bus_deactivate_resource, sbus_deactivate_resource),
262 DEVMETHOD(bus_release_resource, sbus_release_resource),
263 DEVMETHOD(bus_get_resource_list, sbus_get_resource_list),
264 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
265
266 { 0, 0 }
267 };
268
269 static driver_t sbus_driver = {
270 "sbus",
271 sbus_methods,
272 sizeof(struct sbus_softc),
273 };
274
275 static devclass_t sbus_devclass;
276
277 DRIVER_MODULE(sbus, nexus, sbus_driver, sbus_devclass, 0, 0);
278
279 #define OFW_SBUS_TYPE "sbus"
280 #define OFW_SBUS_NAME "sbus"
281
282 static int
283 sbus_probe(device_t dev)
284 {
285 struct sbus_softc *sc = device_get_softc(dev);
286 struct sbus_devinfo *sdi;
287 struct sbus_ranges *range;
288 struct resource *res;
289 device_t cdev;
290 bus_addr_t phys;
291 bus_size_t size;
292 char *name, *cname, *t;
293 phandle_t child, node = nexus_get_node(dev);
294 u_int64_t mr;
295 int intr, clock, rid, vec, i;
296
297 t = nexus_get_device_type(dev);
298 if (((t == NULL || strcmp(t, OFW_SBUS_TYPE) != 0)) &&
299 strcmp(nexus_get_name(dev), OFW_SBUS_NAME) != 0)
300 return (ENXIO);
301 device_set_desc(dev, "U2S UPA-SBus bridge");
302
303 if ((sc->sc_nreg = OF_getprop_alloc(node, "reg", sizeof(*sc->sc_reg),
304 (void **)&sc->sc_reg)) == -1) {
305 panic("sbus_probe: error getting reg property");
306 }
307 if (sc->sc_nreg < 1)
308 panic("sbus_probe: bogus properties");
309 phys = UPA_REG_PHYS(&sc->sc_reg[0]);
310 size = UPA_REG_SIZE(&sc->sc_reg[0]);
311 rid = 0;
312 sc->sc_sysio_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, phys,
313 phys + size - 1, size, RF_ACTIVE);
314 if (sc->sc_sysio_res == NULL ||
315 rman_get_start(sc->sc_sysio_res) != phys)
316 panic("sbus_probe: can't allocate device memory");
317 sc->sc_bustag = rman_get_bustag(sc->sc_sysio_res);
318 sc->sc_bushandle = rman_get_bushandle(sc->sc_sysio_res);
319
320 if (OF_getprop(node, "interrupts", &intr, sizeof(intr)) == -1)
321 panic("sbus_probe: cannot get IGN");
322 sc->sc_ign = intr & INTMAP_IGN_MASK; /* Find interrupt group no */
323 sc->sc_cbustag = sbus_alloc_bustag(sc);
324
325 /*
326 * Record clock frequency for synchronous SCSI.
327 * IS THIS THE CORRECT DEFAULT??
328 */
329 if (OF_getprop(node, "clock-frequency", &clock, sizeof(clock)) == -1)
330 clock = 25000000;
331 sc->sc_clockfreq = clock;
332 clock /= 1000;
333 device_printf(dev, "clock %d.%03d MHz\n", clock / 1000, clock % 1000);
334
335 sc->sc_dmatag = nexus_get_dmatag(dev);
336 if (bus_dma_tag_create(sc->sc_dmatag, 8, 1, 0, 0x3ffffffff, NULL, NULL,
337 0x3ffffffff, 0xff, 0xffffffff, 0, &sc->sc_cdmatag) != 0)
338 panic("bus_dma_tag_create failed");
339 /* Customize the tag */
340 sc->sc_cdmatag->cookie = sc;
341 sc->sc_cdmatag->dmamap_create = sbus_dmamap_create;
342 sc->sc_cdmatag->dmamap_destroy = sbus_dmamap_destroy;
343 sc->sc_cdmatag->dmamap_load = sbus_dmamap_load;
344 sc->sc_cdmatag->dmamap_unload = sbus_dmamap_unload;
345 sc->sc_cdmatag->dmamap_sync = sbus_dmamap_sync;
346 sc->sc_cdmatag->dmamem_alloc = sbus_dmamem_alloc;
347 sc->sc_cdmatag->dmamem_free = sbus_dmamem_free;
348 /* XXX: register as root dma tag (kluge). */
349 sparc64_root_dma_tag = sc->sc_cdmatag;
350
351 /*
352 * Collect address translations from the OBP.
353 */
354 if ((sc->sc_nrange = OF_getprop_alloc(node, "ranges",
355 sizeof(*range), (void **)&range)) == -1) {
356 panic("%s: error getting ranges property",
357 device_get_name(dev));
358 }
359 sc->sc_rd = (struct sbus_rd *)malloc(sizeof(*sc->sc_rd) * sc->sc_nrange,
360 M_DEVBUF, M_NOWAIT);
361 if (sc->sc_rd == NULL)
362 panic("sbus_probe: could not allocate rmans");
363 /*
364 * Preallocate all space that the SBus bridge decodes, so that nothing
365 * else gets in the way; set up rmans etc.
366 */
367 for (i = 0; i < sc->sc_nrange; i++) {
368 phys = range[i].poffset | ((bus_addr_t)range[i].pspace << 32);
369 size = range[i].size;
370 sc->sc_rd[i].rd_slot = range[i].cspace;
371 sc->sc_rd[i].rd_coffset = range[i].coffset;
372 sc->sc_rd[i].rd_cend = sc->sc_rd[i].rd_coffset + size;
373 rid = 0;
374 if ((res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, phys,
375 phys + size - 1, size, RF_ACTIVE)) == NULL)
376 panic("sbus_probe: could not allocate decoded range");
377 sc->sc_rd[i].rd_bushandle = rman_get_bushandle(res);
378 sc->sc_rd[i].rd_rman.rm_type = RMAN_ARRAY;
379 sc->sc_rd[i].rd_rman.rm_descr = "SBus Device Memory";
380 if (rman_init(&sc->sc_rd[i].rd_rman) != 0 ||
381 rman_manage_region(&sc->sc_rd[i].rd_rman, 0, size) != 0)
382 panic("psycho_probe: failed to set up memory rman");
383 sc->sc_rd[i].rd_poffset = phys;
384 sc->sc_rd[i].rd_pend = phys + size;
385 sc->sc_rd[i].rd_res = res;
386 }
387 free(range, M_OFWPROP);
388
389 /*
390 * Get the SBus burst transfer size if burst transfers are supported.
391 * XXX: is the default correct?
392 */
393 if (OF_getprop(node, "burst-sizes", &sc->sc_burst,
394 sizeof(sc->sc_burst)) == -1 || sc->sc_burst == 0)
395 sc->sc_burst = SBUS_BURST_DEF;
396
397 /* initalise the IOMMU */
398
399 /* punch in our copies */
400 sc->sc_is.is_bustag = sc->sc_bustag;
401 sc->sc_is.is_bushandle = sc->sc_bushandle;
402 sc->sc_is.is_iommu = SBR_IOMMU;
403 sc->sc_is.is_dtag = SBR_IOMMU_TLB_TAG_DIAG;
404 sc->sc_is.is_ddram = SBR_IOMMU_TLB_DATA_DIAG;
405 sc->sc_is.is_dqueue = SBR_IOMMU_QUEUE_DIAG;
406 sc->sc_is.is_dva = SBR_IOMMU_SVADIAG;
407 sc->sc_is.is_dtcmp = 0;
408 sc->sc_is.is_sb[0] = SBR_STRBUF;
409 sc->sc_is.is_sb[1] = NULL;
410
411 /* give us a nice name.. */
412 name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
413 if (name == 0)
414 panic("sbus_probe: couldn't malloc iommu name");
415 snprintf(name, 32, "%s dvma", device_get_name(dev));
416
417 /*
418 * Note: the SBus IOMMU ignores the high bits of an address, so a NULL
419 * DMA pointer will be translated by the first page of the IOTSB.
420 * To detect bugs we'll allocate and ignore the first entry.
421 */
422 iommu_init(name, &sc->sc_is, 0, -1, 1);
423
424 /* Enable the over-temperature and power-fail intrrupts. */
425 rid = 0;
426 mr = SYSIO_READ8(sc, SBR_THERM_INT_MAP);
427 vec = INTVEC(mr);
428 if ((sc->sc_ot_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, vec,
429 vec, 1, RF_ACTIVE)) == NULL)
430 panic("sbus_probe: failed to get temperature interrupt");
431 bus_setup_intr(dev, sc->sc_ot_ires, INTR_TYPE_MISC | INTR_FAST,
432 sbus_overtemp, sc, &sc->sc_ot_ihand);
433 SYSIO_WRITE8(sc, SBR_THERM_INT_MAP, INTMAP_ENABLE(mr, PCPU_GET(mid)));
434 rid = 0;
435 mr = SYSIO_READ8(sc, SBR_POWER_INT_MAP);
436 vec = INTVEC(mr);
437 if ((sc->sc_pf_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, vec,
438 vec, 1, RF_ACTIVE)) == NULL)
439 panic("sbus_probe: failed to get power fail interrupt");
440 bus_setup_intr(dev, sc->sc_pf_ires, INTR_TYPE_MISC | INTR_FAST,
441 sbus_pwrfail, sc, &sc->sc_pf_ihand);
442 SYSIO_WRITE8(sc, SBR_POWER_INT_MAP, INTMAP_ENABLE(mr, PCPU_GET(mid)));
443
444 /* Initialize the counter-timer. */
445 sparc64_counter_init(sc->sc_bustag, sc->sc_bushandle, SBR_TC0);
446
447 /*
448 * Loop through ROM children, fixing any relative addresses
449 * and then configuring each device.
450 * `specials' is an array of device names that are treated
451 * specially:
452 */
453 for (child = OF_child(node); child != 0; child = OF_peer(child)) {
454 if ((OF_getprop_alloc(child, "name", 1, (void **)&cname)) == -1)
455 continue;
456
457 if ((sdi = sbus_setup_dinfo(sc, child, cname)) == NULL) {
458 device_printf(dev, "<%s>: incomplete\n", cname);
459 free(cname, M_OFWPROP);
460 continue;
461 }
462 if ((cdev = device_add_child(dev, NULL, -1)) == NULL)
463 panic("sbus_probe: device_add_child failed");
464 device_set_ivars(cdev, sdi);
465 }
466 return (0);
467 }
468
469 static struct sbus_devinfo *
470 sbus_setup_dinfo(struct sbus_softc *sc, phandle_t node, char *name)
471 {
472 struct sbus_devinfo *sdi;
473 struct sbus_regs *reg;
474 u_int32_t base, iv, *intr;
475 int i, nreg, nintr, slot, rslot;
476
477 sdi = malloc(sizeof(*sdi), M_DEVBUF, M_ZERO | M_WAITOK);
478 if (sdi == NULL)
479 return (NULL);
480 resource_list_init(&sdi->sdi_rl);
481 sdi->sdi_name = name;
482 sdi->sdi_node = node;
483 OF_getprop_alloc(node, "compat", 1, (void **)&sdi->sdi_compat);
484 OF_getprop_alloc(node, "device_type", 1, (void **)&sdi->sdi_type);
485 slot = -1;
486 nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®);
487 if (nreg == -1) {
488 if (sdi->sdi_type == NULL ||
489 strcmp(sdi->sdi_type, "hierarchical") != 0) {
490 sbus_destroy_dinfo(sdi);
491 return (NULL);
492 }
493 } else {
494 for (i = 0; i < nreg; i++) {
495 base = reg[i].sbr_offset;
496 if (SBUS_ABS(base)) {
497 rslot = SBUS_ABS_TO_SLOT(base);
498 base = SBUS_ABS_TO_OFFSET(base);
499 } else
500 rslot = reg[i].sbr_slot;
501 if (slot != -1 && slot != rslot)
502 panic("sbus_setup_dinfo: multiple slots");
503 slot = rslot;
504
505 resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, i,
506 base, base + reg[i].sbr_size, reg[i].sbr_size);
507 }
508 free(reg, M_OFWPROP);
509 }
510 sdi->sdi_slot = slot;
511
512 /*
513 * The `interrupts' property contains the Sbus interrupt level.
514 */
515 nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr);
516 if (nintr != -1) {
517 for (i = 0; i < nintr; i++) {
518 iv = intr[i];
519 /*
520 * Sbus card devices need the slot number encoded into
521 * the vector as this is generally not done.
522 */
523 if ((iv & INTMAP_OBIO_MASK) == 0)
524 iv |= slot << 3;
525 /* Set the ign as appropriate. */
526 iv |= sc->sc_ign;
527 resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ, i,
528 iv, iv, 1);
529 }
530 free(intr, M_OFWPROP);
531 }
532 if (OF_getprop(node, "burst-sizes", &sdi->sdi_burstsz,
533 sizeof(sdi->sdi_burstsz)) == -1)
534 sdi->sdi_burstsz = sc->sc_burst;
535 else
536 sdi->sdi_burstsz &= sc->sc_burst;
537
538 return (sdi);
539 }
540
541 /* Free everything except sdi_name, which is handled separately. */
542 static void
543 sbus_destroy_dinfo(struct sbus_devinfo *dinfo)
544 {
545
546 resource_list_free(&dinfo->sdi_rl);
547 if (dinfo->sdi_compat != NULL)
548 free(dinfo->sdi_compat, M_OFWPROP);
549 if (dinfo->sdi_type != NULL)
550 free(dinfo->sdi_type, M_OFWPROP);
551 free(dinfo, M_DEVBUF);
552 }
553
554 static int
555 sbus_print_child(device_t dev, device_t child)
556 {
557 struct sbus_devinfo *dinfo;
558 struct resource_list *rl;
559 int rv;
560
561 dinfo = device_get_ivars(child);
562 rl = &dinfo->sdi_rl;
563 rv = bus_print_child_header(dev, child);
564 rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
565 rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
566 rv += bus_print_child_footer(dev, child);
567 return (rv);
568 }
569
570 static void
571 sbus_probe_nomatch(device_t dev, device_t child)
572 {
573 char *name;
574 char *type;
575
576 if (BUS_READ_IVAR(dev, child, SBUS_IVAR_NAME,
577 (uintptr_t *)&name) != 0 ||
578 BUS_READ_IVAR(dev, child, SBUS_IVAR_DEVICE_TYPE,
579 (uintptr_t *)&type) != 0)
580 return;
581
582 if (type == NULL)
583 type = "(unknown)";
584 device_printf(dev, "<%s>, type %s (no driver attached)\n",
585 name, type);
586 }
587
588 static int
589 sbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
590 {
591 struct sbus_softc *sc = device_get_softc(dev);
592 struct sbus_devinfo *dinfo;
593
594 if ((dinfo = device_get_ivars(child)) == NULL)
595 return (ENOENT);
596 switch (which) {
597 case SBUS_IVAR_BURSTSZ:
598 *result = dinfo->sdi_burstsz;
599 break;
600 case SBUS_IVAR_CLOCKFREQ:
601 *result = sc->sc_clockfreq;
602 break;
603 case SBUS_IVAR_COMPAT:
604 *result = (uintptr_t)dinfo->sdi_compat;
605 break;
606 case SBUS_IVAR_NAME:
607 *result = (uintptr_t)dinfo->sdi_name;
608 break;
609 case SBUS_IVAR_NODE:
610 *result = dinfo->sdi_node;
611 break;
612 case SBUS_IVAR_SLOT:
613 *result = dinfo->sdi_slot;
614 break;
615 case SBUS_IVAR_DEVICE_TYPE:
616 *result = (uintptr_t)dinfo->sdi_type;
617 break;
618 default:
619 return (ENOENT);
620 }
621 return 0;
622 }
623
624 static struct resource_list *
625 sbus_get_resource_list(device_t dev, device_t child)
626 {
627 struct sbus_devinfo *sdi;
628
629 sdi = device_get_ivars(child);
630 return (&sdi->sdi_rl);
631 }
632
633 /* Write to the correct clr register, and call the actual handler. */
634 static void
635 sbus_intr_stub(void *arg)
636 {
637 struct sbus_clr *scl;
638
639 scl = (struct sbus_clr *)arg;
640 scl->scl_handler(scl->scl_arg);
641 SYSIO_WRITE8(scl->scl_sc, scl->scl_clr, 0);
642 }
643
644 static int
645 sbus_setup_intr(device_t dev, device_t child,
646 struct resource *ires, int flags, driver_intr_t *intr, void *arg,
647 void **cookiep)
648 {
649 struct sbus_softc *sc;
650 struct sbus_clr *scl;
651 bus_addr_t intrmapptr, intrclrptr, intrptr;
652 u_int64_t intrmap;
653 u_int32_t inr, slot;
654 int error, i;
655 long vec = rman_get_start(ires);
656
657 sc = (struct sbus_softc *)device_get_softc(dev);
658 scl = (struct sbus_clr *)malloc(sizeof(*scl), M_DEVBUF, M_NOWAIT);
659 if (scl == NULL)
660 return (NULL);
661 intrptr = intrmapptr = intrclrptr = 0;
662 intrmap = 0;
663 inr = INTVEC(vec);
664 if ((inr & INTMAP_OBIO_MASK) == 0) {
665 /*
666 * We're in an SBUS slot, register the map and clear
667 * intr registers.
668 */
669 slot = INTSLOT(vec);
670 intrmapptr = SBR_SLOT0_INT_MAP + slot * 8;
671 intrclrptr = SBR_SLOT0_INT_CLR +
672 (slot * 8 * 8) + (INTPRI(vec) * 8);
673 /* Enable the interrupt, insert IGN. */
674 intrmap = inr | sc->sc_ign;
675 } else {
676 intrptr = SBR_SCSI_INT_MAP;
677 /* Insert IGN */
678 inr |= sc->sc_ign;
679 for (i = 0; intrptr <= SBR_RESERVED_INT_MAP &&
680 INTVEC(intrmap = SYSIO_READ8(sc, intrptr)) !=
681 INTVEC(inr); intrptr += 8, i++)
682 ;
683 if (INTVEC(intrmap) == INTVEC(inr)) {
684 /* Register the map and clear intr registers */
685 intrmapptr = intrptr;
686 intrclrptr = SBR_SCSI_INT_CLR + i * 8;
687 /* Enable the interrupt */
688 } else
689 panic("sbus_setup_intr: IRQ not found!");
690 }
691
692 scl->scl_sc = sc;
693 scl->scl_arg = arg;
694 scl->scl_handler = intr;
695 scl->scl_clr = intrclrptr;
696 /* Disable the interrupt while we fiddle with it */
697 SYSIO_WRITE8(sc, intrmapptr, intrmap);
698 error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
699 sbus_intr_stub, scl, cookiep);
700 if (error != 0) {
701 free(scl, M_DEVBUF);
702 return (error);
703 }
704 scl->scl_cookie = *cookiep;
705 *cookiep = scl;
706
707 /*
708 * Clear the interrupt, it might have been triggered before it was
709 * set up.
710 */
711 SYSIO_WRITE8(sc, intrclrptr, 0);
712 /*
713 * Enable the interrupt and program the target module now we have the
714 * handler installed.
715 */
716 SYSIO_WRITE8(sc, intrmapptr, INTMAP_ENABLE(intrmap, PCPU_GET(mid)));
717 return (error);
718 }
719
720 static int
721 sbus_teardown_intr(device_t dev, device_t child,
722 struct resource *vec, void *cookie)
723 {
724 struct sbus_clr *scl;
725 int error;
726
727 scl = (struct sbus_clr *)cookie;
728 error = BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec,
729 scl->scl_cookie);
730 /*
731 * Don't disable the interrupt for now, so that stray interupts get
732 * detected...
733 */
734 if (error != 0)
735 free(scl, M_DEVBUF);
736 return (error);
737 }
738
739 static struct resource *
740 sbus_alloc_resource(device_t bus, device_t child, int type, int *rid,
741 u_long start, u_long end, u_long count, u_int flags)
742 {
743 struct sbus_softc *sc;
744 struct sbus_devinfo *sdi;
745 struct rman *rm;
746 struct resource *rv;
747 struct resource_list *rl;
748 struct resource_list_entry *rle;
749 bus_space_handle_t bh;
750 bus_addr_t toffs;
751 bus_size_t tend;
752 int i;
753 int isdefault = (start == 0UL && end == ~0UL);
754 int needactivate = flags & RF_ACTIVE;
755
756 sc = (struct sbus_softc *)device_get_softc(bus);
757 sdi = device_get_ivars(child);
758 rl = &sdi->sdi_rl;
759 rle = resource_list_find(rl, type, *rid);
760 if (rle == NULL)
761 return (NULL);
762 if (rle->res != NULL)
763 panic("sbus_alloc_resource: resource entry is busy");
764 if (isdefault) {
765 start = rle->start;
766 count = ulmax(count, rle->count);
767 end = ulmax(rle->end, start + count - 1);
768 }
769 switch (type) {
770 case SYS_RES_IRQ:
771 rv = bus_alloc_resource(bus, type, rid, start, end,
772 count, flags);
773 if (rv == NULL)
774 return (NULL);
775 break;
776 case SYS_RES_MEMORY:
777 rm = NULL;
778 bh = toffs = tend = 0;
779 for (i = 0; i < sc->sc_nrange; i++) {
780 if (sc->sc_rd[i].rd_slot != sdi->sdi_slot ||
781 start < sc->sc_rd[i].rd_coffset ||
782 start > sc->sc_rd[i].rd_cend)
783 continue;
784 /* Disallow cross-range allocations. */
785 if (end > sc->sc_rd[i].rd_cend)
786 return (NULL);
787 /* We've found the connection to the parent bus */
788 toffs = start - sc->sc_rd[i].rd_coffset;
789 tend = end - sc->sc_rd[i].rd_coffset;
790 rm = &sc->sc_rd[i].rd_rman;
791 bh = sc->sc_rd[i].rd_bushandle;
792 }
793 if (toffs == NULL)
794 return (NULL);
795 flags &= ~RF_ACTIVE;
796 rv = rman_reserve_resource(rm, toffs, tend, count, flags,
797 child);
798 if (rv == NULL)
799 return (NULL);
800 rman_set_bustag(rv, sc->sc_cbustag);
801 rman_set_bushandle(rv, bh + rman_get_start(rv));
802 if (needactivate) {
803 if (bus_activate_resource(child, type, *rid, rv)) {
804 rman_release_resource(rv);
805 return (NULL);
806 }
807 }
808 break;
809 default:
810 return (NULL);
811 }
812 rle->res = rv;
813 return (rv);
814 }
815
816 static int
817 sbus_activate_resource(device_t bus, device_t child, int type, int rid,
818 struct resource *r)
819 {
820
821 if (type == SYS_RES_IRQ)
822 return (bus_activate_resource(bus, type, rid, r));
823 return (rman_activate_resource(r));
824 }
825
826 static int
827 sbus_deactivate_resource(device_t bus, device_t child, int type, int rid,
828 struct resource *r)
829 {
830
831 if (type == SYS_RES_IRQ)
832 return (bus_deactivate_resource(bus, type, rid, r));
833 return (rman_deactivate_resource(r));
834 }
835
836 static int
837 sbus_release_resource(device_t bus, device_t child, int type, int rid,
838 struct resource *r)
839 {
840 int error;
841
842 if (type == SYS_RES_IRQ)
843 return (bus_release_resource(bus, type, rid, r));
844 if (rman_get_flags(r) & RF_ACTIVE) {
845 error = bus_deactivate_resource(child, type, rid, r);
846 if (error)
847 return error;
848 }
849 return (rman_release_resource(r));
850 }
851
852 /*
853 * Handle an overtemp situation.
854 *
855 * SPARCs have temperature sensors which generate interrupts
856 * if the machine's temperature exceeds a certain threshold.
857 * This handles the interrupt and powers off the machine.
858 * The same needs to be done to PCI controller drivers.
859 */
860 static void
861 sbus_overtemp(void *arg)
862 {
863
864 printf("DANGER: OVER TEMPERATURE detected\nShutting down NOW.\n");
865 shutdown_nice(RB_POWEROFF);
866 }
867
868 /* Try to shut down in time in case of power failure. */
869 static void
870 sbus_pwrfail(void *arg)
871 {
872
873 printf("Power failure detected\nShutting down NOW.\n");
874 shutdown_nice(0);
875 }
876
877 static bus_space_tag_t
878 sbus_alloc_bustag(struct sbus_softc *sc)
879 {
880 bus_space_tag_t sbt;
881
882 sbt = (bus_space_tag_t)malloc(sizeof(struct bus_space_tag), M_DEVBUF,
883 M_NOWAIT | M_ZERO);
884 if (sbt == NULL)
885 panic("sbus_alloc_bustag: out of memory");
886
887 bzero(sbt, sizeof *sbt);
888 sbt->cookie = sc;
889 sbt->parent = sc->sc_bustag;
890 sbt->type = SBUS_BUS_SPACE;
891 return (sbt);
892 }
893
894 static int
895 sbus_dmamap_create(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, int flags,
896 bus_dmamap_t *mapp)
897 {
898 struct sbus_softc *sc = (struct sbus_softc *)pdmat->cookie;
899
900 return (iommu_dvmamap_create(pdmat, ddmat, &sc->sc_is, flags, mapp));
901
902 }
903
904 static int
905 sbus_dmamap_destroy(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, bus_dmamap_t map)
906 {
907 struct sbus_softc *sc = (struct sbus_softc *)pdmat->cookie;
908
909 return (iommu_dvmamap_destroy(pdmat, ddmat, &sc->sc_is, map));
910 }
911
912 static int
913 sbus_dmamap_load(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, bus_dmamap_t map,
914 void *buf, bus_size_t buflen, bus_dmamap_callback_t *callback,
915 void *callback_arg, int flags)
916 {
917 struct sbus_softc *sc = (struct sbus_softc *)pdmat->cookie;
918
919 return (iommu_dvmamap_load(pdmat, ddmat, &sc->sc_is, map, buf, buflen,
920 callback, callback_arg, flags));
921 }
922
923 static void
924 sbus_dmamap_unload(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, bus_dmamap_t map)
925 {
926 struct sbus_softc *sc = (struct sbus_softc *)pdmat->cookie;
927
928 iommu_dvmamap_unload(pdmat, ddmat, &sc->sc_is, map);
929 }
930
931 static void
932 sbus_dmamap_sync(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, bus_dmamap_t map,
933 bus_dmasync_op_t op)
934 {
935 struct sbus_softc *sc = (struct sbus_softc *)pdmat->cookie;
936
937 iommu_dvmamap_sync(pdmat, ddmat, &sc->sc_is, map, op);
938 }
939
940 static int
941 sbus_dmamem_alloc(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, void **vaddr,
942 int flags, bus_dmamap_t *mapp)
943 {
944 struct sbus_softc *sc = (struct sbus_softc *)pdmat->cookie;
945
946 return (iommu_dvmamem_alloc(pdmat, ddmat, &sc->sc_is, vaddr, flags,
947 mapp));
948 }
949
950 static void
951 sbus_dmamem_free(bus_dma_tag_t pdmat, bus_dma_tag_t ddmat, void *vaddr,
952 bus_dmamap_t map)
953 {
954 struct sbus_softc *sc = (struct sbus_softc *)pdmat->cookie;
955
956 iommu_dvmamem_free(pdmat, ddmat, &sc->sc_is, vaddr, map);
957 }
Cache object: 9a205b4aa50b0795b444af282013fe53
|