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