sbus.c revision 1.79 1 /* $NetBSD: sbus.c,v 1.79 2008/04/05 13:40:05 cegger Exp $ */
2
3 /*
4 * Copyright (c) 1999-2002 Eduardo Horvath
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
17 *
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
28 * SUCH DAMAGE.
29 */
30
31
32 /*
33 * Sbus stuff.
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: sbus.c,v 1.79 2008/04/05 13:40:05 cegger Exp $");
38
39 #include "opt_ddb.h"
40
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>
47
48 #include <machine/bus.h>
49 #include <machine/openfirm.h>
50
51 #include <sparc64/sparc64/cache.h>
52 #include <sparc64/dev/iommureg.h>
53 #include <sparc64/dev/iommuvar.h>
54 #include <sparc64/dev/sbusreg.h>
55 #include <dev/sbus/sbusvar.h>
56
57 #include <uvm/uvm_extern.h>
58
59 #include <machine/autoconf.h>
60 #include <machine/cpu.h>
61 #include <machine/sparc64.h>
62
63 #ifdef DEBUG
64 #define SDB_DVMA 0x1
65 #define SDB_INTR 0x2
66 int sbus_debug = 0;
67 #define DPRINTF(l, s) do { if (sbus_debug & l) printf s; } while (0)
68 #else
69 #define DPRINTF(l, s)
70 #endif
71
72 void sbusreset(int);
73
74 static bus_dma_tag_t sbus_alloc_dmatag(struct sbus_softc *);
75 static int sbus_get_intr(struct sbus_softc *, int, struct openprom_intr **,
76 int *, int);
77 static int sbus_overtemp(void *);
78 static int _sbus_bus_map(
79 bus_space_tag_t,
80 bus_addr_t, /*offset*/
81 bus_size_t, /*size*/
82 int, /*flags*/
83 vaddr_t, /* XXX unused -- compat w/sparc */
84 bus_space_handle_t *);
85 static void *sbus_intr_establish(
86 bus_space_tag_t,
87 int, /*`device class' priority*/
88 int, /*Sbus interrupt level*/
89 int (*)(void *), /*handler*/
90 void *, /*handler arg*/
91 void (*)(void)); /*optional fast trap*/
92
93
94 /* autoconfiguration driver */
95 int sbus_match(struct device *, struct cfdata *, void *);
96 void sbus_attach(struct device *, struct device *, void *);
97
98
99 CFATTACH_DECL(sbus, sizeof(struct sbus_softc),
100 sbus_match, sbus_attach, NULL, NULL);
101
102 extern struct cfdriver sbus_cd;
103
104 /*
105 * DVMA routines
106 */
107 int sbus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t,
108 struct proc *, int);
109 void sbus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
110 int sbus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, bus_dma_segment_t *,
111 int, bus_size_t, int);
112 void sbus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, bus_size_t,
113 int);
114 int sbus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size,
115 bus_size_t alignment, bus_size_t boundary,
116 bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags);
117 void sbus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs);
118 int sbus_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs,
119 size_t size, void **kvap, int flags);
120 void sbus_dmamem_unmap(bus_dma_tag_t tag, void *kva, size_t size);
121
122 /*
123 * Child devices receive the Sbus interrupt level in their attach
124 * arguments. We translate these to CPU IPLs using the following
125 * tables. Note: obio bus interrupt levels are identical to the
126 * processor IPL.
127 *
128 * The second set of tables is used when the Sbus interrupt level
129 * cannot be had from the PROM as an `interrupt' property. We then
130 * fall back on the `intr' property which contains the CPU IPL.
131 */
132
133 /*
134 * This value is or'ed into the attach args' interrupt level cookie
135 * if the interrupt level comes from an `intr' property, i.e. it is
136 * not an Sbus interrupt level.
137 */
138 #define SBUS_INTR_COMPAT 0x80000000
139
140
141 /*
142 * Print the location of some sbus-attached device (called just
143 * before attaching that device). If `sbus' is not NULL, the
144 * device was found but not configured; print the sbus as well.
145 * Return UNCONF (config_find ignores this if the device was configured).
146 */
147 int
148 sbus_print(void *args, const char *busname)
149 {
150 struct sbus_attach_args *sa = args;
151 int i;
152
153 if (busname)
154 aprint_normal("%s at %s", sa->sa_name, busname);
155 aprint_normal(" slot %ld offset 0x%lx", (long)sa->sa_slot,
156 (u_long)sa->sa_offset);
157 for (i = 0; i < sa->sa_nintr; i++) {
158 struct openprom_intr *sbi = &sa->sa_intr[i];
159
160 aprint_normal(" vector %lx ipl %ld",
161 (u_long)sbi->oi_vec,
162 (long)INTLEV(sbi->oi_pri));
163 }
164 return (UNCONF);
165 }
166
167 int
168 sbus_match(struct device *parent, struct cfdata *cf, void *aux)
169 {
170 struct mainbus_attach_args *ma = aux;
171
172 return (strcmp(cf->cf_name, ma->ma_name) == 0);
173 }
174
175 /*
176 * Attach an Sbus.
177 */
178 void
179 sbus_attach(struct device *parent, struct device *self, void *aux)
180 {
181 struct sbus_softc *sc = (struct sbus_softc *)self;
182 struct mainbus_attach_args *ma = aux;
183 struct intrhand *ih;
184 int ipl;
185 char *name;
186 int node = ma->ma_node;
187 int node0, error;
188 bus_space_tag_t sbt;
189 struct sbus_attach_args sa;
190
191 sc->sc_bustag = ma->ma_bustag;
192 sc->sc_dmatag = ma->ma_dmatag;
193 sc->sc_ign = ma->ma_interrupts[0] & INTMAP_IGN;
194
195 /* XXXX Use sysio PROM mappings for interrupt vector regs. */
196 sparc_promaddr_to_handle(sc->sc_bustag, ma->ma_address[0], &sc->sc_bh);
197 sc->sc_sysio = (struct sysioreg *)bus_space_vaddr(sc->sc_bustag,
198 sc->sc_bh);
199
200 #ifdef _LP64
201 /*
202 * 32-bit kernels use virtual addresses for bus space operations
203 * so we may as well use the prom VA.
204 *
205 * 64-bit kernels use physical addresses for bus space operations
206 * so mapping this in again will reduce TLB thrashing.
207 */
208 if (bus_space_map(sc->sc_bustag, ma->ma_reg[0].ur_paddr,
209 ma->ma_reg[0].ur_len, 0, &sc->sc_bh) != 0) {
210 aprint_error_dev(self, "cannot map registers\n");
211 return;
212 }
213 #endif
214
215 /*
216 * Record clock frequency for synchronous SCSI.
217 * IS THIS THE CORRECT DEFAULT??
218 */
219 sc->sc_clockfreq = prom_getpropint(node, "clock-frequency",
220 25*1000*1000);
221 printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq));
222
223 sbt = bus_space_tag_alloc(sc->sc_bustag, sc);
224 sbt->type = SBUS_BUS_SPACE;
225 sbt->sparc_bus_map = _sbus_bus_map;
226 sbt->sparc_intr_establish = sbus_intr_establish;
227
228 sc->sc_dmatag = sbus_alloc_dmatag(sc);
229
230 /*
231 * Get the SBus burst transfer size if burst transfers are supported
232 */
233 sc->sc_burst = prom_getpropint(node, "burst-sizes", 0);
234
235 /*
236 * Collect address translations from the OBP.
237 */
238 error = prom_getprop(node, "ranges", sizeof(struct openprom_range),
239 &sbt->nranges, &sbt->ranges);
240 if (error)
241 panic("%s: error getting ranges property", device_xname(&sc->sc_dev));
242
243 /* initialize the IOMMU */
244
245 /* punch in our copies */
246 sc->sc_is.is_bustag = sc->sc_bustag;
247 bus_space_subregion(sc->sc_bustag, sc->sc_bh,
248 (vaddr_t)&((struct sysioreg *)NULL)->sys_iommu,
249 sizeof (struct iommureg), &sc->sc_is.is_iommu);
250
251 /* initialize our strbuf_ctl */
252 sc->sc_is.is_sb[0] = &sc->sc_sb;
253 sc->sc_sb.sb_is = &sc->sc_is;
254 bus_space_subregion(sc->sc_bustag, sc->sc_bh,
255 (vaddr_t)&((struct sysioreg *)NULL)->sys_strbuf,
256 sizeof (struct iommu_strbuf), &sc->sc_sb.sb_sb);
257 /* Point sb_flush to our flush buffer. */
258 sc->sc_sb.sb_flush = &sc->sc_flush;
259
260 /* give us a nice name.. */
261 name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
262 if (name == 0)
263 panic("couldn't malloc iommu name");
264 snprintf(name, 32, "%s dvma", device_xname(&sc->sc_dev));
265
266 iommu_init(name, &sc->sc_is, 0, -1);
267
268 /* Enable the over temp intr */
269 ih = (struct intrhand *)
270 malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT);
271 ih->ih_map = &sc->sc_sysio->therm_int_map;
272 ih->ih_clr = NULL; /* &sc->sc_sysio->therm_clr_int; */
273 ih->ih_fun = sbus_overtemp;
274 ipl = 1;
275 ih->ih_pil = (1<<ipl);
276 ih->ih_number = INTVEC(*(ih->ih_map));
277 intr_establish(ipl, ih);
278 *(ih->ih_map) |= INTMAP_V|(CPU_UPAID << INTMAP_TID_SHIFT);
279
280 /*
281 * Note: the stupid SBUS IOMMU ignores the high bits of an address, so a
282 * NULL DMA pointer will be translated by the first page of the IOTSB.
283 * To avoid bugs we'll alloc and ignore the first entry in the IOTSB.
284 */
285 {
286 u_long dummy;
287
288 if (extent_alloc_subregion(sc->sc_is.is_dvmamap,
289 sc->sc_is.is_dvmabase, sc->sc_is.is_dvmabase + PAGE_SIZE,
290 PAGE_SIZE, PAGE_SIZE, 0, EX_NOWAIT|EX_BOUNDZERO,
291 (u_long *)&dummy) != 0)
292 panic("sbus iommu: can't toss first dvma page");
293 }
294
295 /*
296 * Loop through ROM children, fixing any relative addresses
297 * and then configuring each device.
298 * `specials' is an array of device names that are treated
299 * specially:
300 */
301 node0 = OF_child(node);
302 for (node = node0; node; node = OF_peer(node)) {
303 char *name1 = prom_getpropstring(node, "name");
304
305 if (sbus_setup_attach_args(sc, sbt, sc->sc_dmatag,
306 node, &sa) != 0) {
307 printf("sbus_attach: %s: incomplete\n", name1);
308 continue;
309 }
310 (void) config_found(&sc->sc_dev, (void *)&sa, sbus_print);
311 sbus_destroy_attach_args(&sa);
312 }
313 }
314
315 int
316 sbus_setup_attach_args(struct sbus_softc *sc, bus_space_tag_t bustag,
317 bus_dma_tag_t dmatag, int node, struct sbus_attach_args *sa)
318 {
319 /*struct openprom_addr sbusreg;*/
320 /*int base;*/
321 int error;
322 int n;
323
324 memset(sa, 0, sizeof(struct sbus_attach_args));
325 n = 0;
326 error = prom_getprop(node, "name", 1, &n, &sa->sa_name);
327 if (error != 0)
328 return (error);
329 sa->sa_name[n] = '\0';
330
331 sa->sa_bustag = bustag;
332 sa->sa_dmatag = dmatag;
333 sa->sa_node = node;
334 sa->sa_frequency = sc->sc_clockfreq;
335
336 error = prom_getprop(node, "reg", sizeof(struct openprom_addr),
337 &sa->sa_nreg, &sa->sa_reg);
338 if (error != 0) {
339 char buf[32];
340 if (error != ENOENT ||
341 !node_has_property(node, "device_type") ||
342 strcmp(prom_getpropstringA(node, "device_type", buf, sizeof buf),
343 "hierarchical") != 0)
344 return (error);
345 }
346 for (n = 0; n < sa->sa_nreg; n++) {
347 /* Convert to relative addressing, if necessary */
348 uint32_t base = sa->sa_reg[n].oa_base;
349 if (SBUS_ABS(base)) {
350 sa->sa_reg[n].oa_space = SBUS_ABS_TO_SLOT(base);
351 sa->sa_reg[n].oa_base = SBUS_ABS_TO_OFFSET(base);
352 }
353 }
354
355 if ((error = sbus_get_intr(sc, node, &sa->sa_intr, &sa->sa_nintr,
356 sa->sa_slot)) != 0)
357 return (error);
358
359 error = prom_getprop(node, "address", sizeof(uint32_t),
360 &sa->sa_npromvaddrs, &sa->sa_promvaddrs);
361 if (error != 0 && error != ENOENT)
362 return (error);
363
364 return (0);
365 }
366
367 void
368 sbus_destroy_attach_args(struct sbus_attach_args *sa)
369 {
370 if (sa->sa_name != NULL)
371 free(sa->sa_name, M_DEVBUF);
372
373 if (sa->sa_nreg != 0)
374 free(sa->sa_reg, M_DEVBUF);
375
376 if (sa->sa_intr)
377 free(sa->sa_intr, M_DEVBUF);
378
379 if (sa->sa_promvaddrs)
380 free((void *)sa->sa_promvaddrs, M_DEVBUF);
381
382 memset(sa, 0, sizeof(struct sbus_attach_args)); /*DEBUG*/
383 }
384
385
386 int
387 _sbus_bus_map(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, int flags,
388 vaddr_t v, bus_space_handle_t *hp)
389 {
390 int error;
391
392 if (t->ranges != NULL) {
393 if ((error = bus_space_translate_address_generic(
394 t->ranges, t->nranges, &addr)) != 0)
395 return (error);
396 }
397
398 return (bus_space_map(t->parent, addr, size, flags, hp));
399 }
400
401
402 bus_addr_t
403 sbus_bus_addr(bus_space_tag_t t, u_int btype, u_int offset)
404 {
405 int slot = btype;
406 struct openprom_range *rp;
407 int i;
408
409 for (i = 0; i < t->nranges; i++) {
410 rp = &t->ranges[i];
411 if (rp->or_child_space != slot)
412 continue;
413
414 return BUS_ADDR(rp->or_parent_space,
415 rp->or_parent_base + offset);
416 }
417
418 return (0);
419 }
420
421
422 /*
423 * Each attached device calls sbus_establish after it initializes
424 * its sbusdev portion.
425 */
426 void
427 sbus_establish(register struct sbusdev *sd, register struct device *dev)
428 {
429 register struct sbus_softc *sc;
430 register struct device *curdev;
431
432 /*
433 * We have to look for the sbus by name, since it is not necessarily
434 * our immediate parent (i.e. sun4m /iommu/sbus/espdma/esp)
435 * We don't just use the device structure of the above-attached
436 * sbus, since we might (in the future) support multiple sbus's.
437 */
438 for (curdev = device_parent(dev); ; curdev = device_parent(curdev)) {
439 if (!curdev || !device_xname(curdev))
440 panic("sbus_establish: can't find sbus parent for %s",
441 device_xname(sd->sd_dev)
442 ? device_xname(sd->sd_dev)
443 : "<unknown>" );
444
445 if (strncmp(device_xname(curdev), "sbus", 4) == 0)
446 break;
447 }
448 sc = (struct sbus_softc *) curdev;
449
450 sd->sd_dev = dev;
451 sd->sd_bchain = sc->sc_sbdev;
452 sc->sc_sbdev = sd;
453 }
454
455 /*
456 * Reset the given sbus.
457 */
458 void
459 sbusreset(int sbus)
460 {
461 register struct sbusdev *sd;
462 struct sbus_softc *sc = sbus_cd.cd_devs[sbus];
463 struct device *dev;
464
465 printf("reset %s:", device_xname(&sc->sc_dev));
466 for (sd = sc->sc_sbdev; sd != NULL; sd = sd->sd_bchain) {
467 if (sd->sd_reset) {
468 dev = sd->sd_dev;
469 (*sd->sd_reset)(dev);
470 printf(" %s", device_xname(dev));
471 }
472 }
473 /* Reload iommu regs */
474 iommu_reset(&sc->sc_is);
475 }
476
477 /*
478 * Handle an overtemp situation.
479 *
480 * SPARCs have temperature sensors which generate interrupts
481 * if the machine's temperature exceeds a certain threshold.
482 * This handles the interrupt and powers off the machine.
483 * The same needs to be done to PCI controller drivers.
484 */
485 int
486 sbus_overtemp(void *arg)
487 {
488 /* Should try a clean shutdown first */
489 printf("DANGER: OVER TEMPERATURE detected\nShutting down...\n");
490 delay(20);
491 cpu_reboot(RB_POWERDOWN|RB_HALT, NULL);
492 }
493
494 /*
495 * Get interrupt attributes for an Sbus device.
496 */
497 int
498 sbus_get_intr(struct sbus_softc *sc, int node, struct openprom_intr **ipp,
499 int *np, int slot)
500 {
501 int *ipl;
502 int n, i;
503 char buf[32];
504
505 /*
506 * The `interrupts' property contains the Sbus interrupt level.
507 */
508 ipl = NULL;
509 if (prom_getprop(node, "interrupts", sizeof(int), np, &ipl) == 0) {
510 struct openprom_intr *ip;
511 int pri;
512
513 /* Default to interrupt level 2 -- otherwise unused */
514 pri = INTLEVENCODE(2);
515
516 /* Change format to an `struct sbus_intr' array */
517 ip = malloc(*np * sizeof(struct openprom_intr), M_DEVBUF,
518 M_NOWAIT);
519 if (ip == NULL)
520 return (ENOMEM);
521
522 /*
523 * Now things get ugly. We need to take this value which is
524 * the interrupt vector number and encode the IPL into it
525 * somehow. Luckily, the interrupt vector has lots of free
526 * space and we can easily stuff the IPL in there for a while.
527 */
528 prom_getpropstringA(node, "device_type", buf, sizeof buf);
529 if (buf[0] == '\0')
530 prom_getpropstringA(node, "name", buf, sizeof buf);
531
532 for (i = 0; intrmap[i].in_class; i++)
533 if (strcmp(intrmap[i].in_class, buf) == 0) {
534 pri = INTLEVENCODE(intrmap[i].in_lev);
535 break;
536 }
537
538 /*
539 * Sbus card devices need the slot number encoded into
540 * the vector as this is generally not done.
541 */
542 if ((ipl[0] & INTMAP_OBIO) == 0)
543 pri |= slot << 3;
544
545 for (n = 0; n < *np; n++) {
546 /*
547 * We encode vector and priority into sbi_pri so we
548 * can pass them as a unit. This will go away if
549 * sbus_establish ever takes an sbus_intr instead
550 * of an integer level.
551 * Stuff the real vector in sbi_vec.
552 */
553
554 ip[n].oi_pri = pri|ipl[n];
555 ip[n].oi_vec = ipl[n];
556 }
557 free(ipl, M_DEVBUF);
558 *ipp = ip;
559 }
560
561 return (0);
562 }
563
564
565 /*
566 * Install an interrupt handler for an Sbus device.
567 */
568 void *
569 sbus_intr_establish(bus_space_tag_t t, int pri, int level,
570 int (*handler)(void *), void *arg, void (*fastvec)(void))
571 {
572 struct sbus_softc *sc = t->cookie;
573 struct intrhand *ih;
574 int ipl;
575 long vec = pri;
576
577 ih = (struct intrhand *)
578 malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT);
579 if (ih == NULL)
580 return (NULL);
581
582 if ((vec & SBUS_INTR_COMPAT) != 0)
583 ipl = vec & ~SBUS_INTR_COMPAT;
584 else {
585 /* Decode and remove IPL */
586 ipl = INTLEV(vec);
587 vec = INTVEC(vec);
588 DPRINTF(SDB_INTR,
589 ("\nsbus: intr[%ld]%lx: %lx\nHunting for IRQ...\n",
590 (long)ipl, (long)vec, (u_long)intrlev[vec]));
591 if ((vec & INTMAP_OBIO) == 0) {
592 /* We're in an SBUS slot */
593 /* Register the map and clear intr registers */
594
595 int slot = INTSLOT(pri);
596
597 ih->ih_map = &(&sc->sc_sysio->sbus_slot0_int)[slot];
598 ih->ih_clr = &sc->sc_sysio->sbus0_clr_int[vec];
599 #ifdef DEBUG
600 if (sbus_debug & SDB_INTR) {
601 int64_t imap = *ih->ih_map;
602
603 printf("SBUS %lx IRQ as %llx in slot %d\n",
604 (long)vec, (long long)imap, slot);
605 printf("\tmap addr %p clr addr %p\n",
606 ih->ih_map, ih->ih_clr);
607 }
608 #endif
609 /* Enable the interrupt */
610 vec |= INTMAP_V | sc->sc_ign |
611 (CPU_UPAID << INTMAP_TID_SHIFT);
612 *(ih->ih_map) = vec;
613 } else {
614 int64_t *intrptr = &sc->sc_sysio->scsi_int_map;
615 int64_t imap = 0;
616 int i;
617
618 /* Insert IGN */
619 vec |= sc->sc_ign;
620 for (i = 0; &intrptr[i] <=
621 (int64_t *)&sc->sc_sysio->reserved_int_map &&
622 INTVEC(imap = intrptr[i]) != INTVEC(vec); i++)
623 ;
624 if (INTVEC(imap) == INTVEC(vec)) {
625 DPRINTF(SDB_INTR,
626 ("OBIO %lx IRQ as %lx in slot %d\n",
627 vec, (long)imap, i));
628 /* Register the map and clear intr registers */
629 ih->ih_map = &intrptr[i];
630 intrptr = (int64_t *)&sc->sc_sysio->scsi_clr_int;
631 ih->ih_clr = &intrptr[i];
632 /* Enable the interrupt */
633 imap |= INTMAP_V
634 |(CPU_UPAID << INTMAP_TID_SHIFT);
635 /* XXXX */
636 *(ih->ih_map) = imap;
637 } else
638 panic("IRQ not found!");
639 }
640 }
641 #ifdef DEBUG
642 if (sbus_debug & SDB_INTR) { long i; for (i = 0; i < 400000000; i++); }
643 #endif
644
645 ih->ih_fun = handler;
646 ih->ih_arg = arg;
647 ih->ih_number = vec;
648 ih->ih_pil = (1<<ipl);
649 intr_establish(ipl, ih);
650 return (ih);
651 }
652
653 static bus_dma_tag_t
654 sbus_alloc_dmatag(struct sbus_softc *sc)
655 {
656 bus_dma_tag_t sdt, psdt = sc->sc_dmatag;
657
658 sdt = (bus_dma_tag_t)
659 malloc(sizeof(struct sparc_bus_dma_tag), M_DEVBUF, M_NOWAIT);
660 if (sdt == NULL)
661 /* Panic? */
662 return (psdt);
663
664 sdt->_cookie = sc;
665 sdt->_parent = psdt;
666 #define PCOPY(x) sdt->x = psdt->x
667 PCOPY(_dmamap_create);
668 PCOPY(_dmamap_destroy);
669 sdt->_dmamap_load = sbus_dmamap_load;
670 PCOPY(_dmamap_load_mbuf);
671 PCOPY(_dmamap_load_uio);
672 sdt->_dmamap_load_raw = sbus_dmamap_load_raw;
673 sdt->_dmamap_unload = sbus_dmamap_unload;
674 sdt->_dmamap_sync = sbus_dmamap_sync;
675 sdt->_dmamem_alloc = sbus_dmamem_alloc;
676 sdt->_dmamem_free = sbus_dmamem_free;
677 sdt->_dmamem_map = sbus_dmamem_map;
678 sdt->_dmamem_unmap = sbus_dmamem_unmap;
679 PCOPY(_dmamem_mmap);
680 #undef PCOPY
681 sc->sc_dmatag = sdt;
682 return (sdt);
683 }
684
685 int
686 sbus_dmamap_load(bus_dma_tag_t tag, bus_dmamap_t map, void *buf,
687 bus_size_t buflen, struct proc *p, int flags)
688 {
689 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
690
691 return (iommu_dvmamap_load(tag, &sc->sc_sb, map, buf, buflen, p, flags));
692 }
693
694 int
695 sbus_dmamap_load_raw(bus_dma_tag_t tag, bus_dmamap_t map,
696 bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
697 {
698 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
699
700 return (iommu_dvmamap_load_raw(tag, &sc->sc_sb, map, segs, nsegs, flags, size));
701 }
702
703 void
704 sbus_dmamap_unload(bus_dma_tag_t tag, bus_dmamap_t map)
705 {
706 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
707
708 iommu_dvmamap_unload(tag, &sc->sc_sb, map);
709 }
710
711 void
712 sbus_dmamap_sync(bus_dma_tag_t tag, bus_dmamap_t map, bus_addr_t offset,
713 bus_size_t len, int ops)
714 {
715 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
716
717 if (ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) {
718 /* Flush the CPU then the IOMMU */
719 bus_dmamap_sync(tag->_parent, map, offset, len, ops);
720 iommu_dvmamap_sync(tag, &sc->sc_sb, map, offset, len, ops);
721 }
722 if (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) {
723 /* Flush the IOMMU then the CPU */
724 iommu_dvmamap_sync(tag, &sc->sc_sb, map, offset, len, ops);
725 bus_dmamap_sync(tag->_parent, map, offset, len, ops);
726 }
727 }
728
729 int
730 sbus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size, bus_size_t alignment,
731 bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
732 int flags)
733 {
734 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
735
736 return (iommu_dvmamem_alloc(tag, &sc->sc_sb, size, alignment, boundary,
737 segs, nsegs, rsegs, flags));
738 }
739
740 void
741 sbus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs)
742 {
743 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
744
745 iommu_dvmamem_free(tag, &sc->sc_sb, segs, nsegs);
746 }
747
748 int
749 sbus_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs,
750 size_t size, void **kvap, int flags)
751 {
752 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
753
754 return (iommu_dvmamem_map(tag, &sc->sc_sb, segs, nsegs, size, kvap, flags));
755 }
756
757 void
758 sbus_dmamem_unmap(bus_dma_tag_t tag, void *kva, size_t size)
759 {
760 struct sbus_softc *sc = (struct sbus_softc *)tag->_cookie;
761
762 iommu_dvmamem_unmap(tag, &sc->sc_sb, kva, size);
763 }
764