Annotation of sys/arch/mvme88k/dev/vme.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: vme.c,v 1.46 2007/03/22 18:52:38 miod Exp $ */
2: /*
3: * Copyright (c) 2004, Miodrag Vallat.
4: * Copyright (c) 1999 Steve Murphree, Jr.
5: * Copyright (c) 1995 Theo de Raadt
6: * All rights reserved.
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: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29: #include <sys/param.h>
30: #include <sys/conf.h>
31: #include <sys/ioctl.h>
32: #include <sys/proc.h>
33: #include <sys/uio.h>
34: #include <sys/systm.h>
35: #include <sys/kernel.h>
36: #include <sys/device.h>
37:
38: #include <machine/autoconf.h>
39: #include <machine/cpu.h>
40:
41: #include "pcctwo.h"
42: #include "syscon.h"
43:
44: #include <mvme88k/dev/vme.h>
45: #if NSYSCON > 0
46: #include <machine/mvme188.h>
47: #include <mvme88k/dev/sysconreg.h>
48: #endif
49:
50: int vmematch(struct device *, void *, void *);
51: void vmeattach(struct device *, struct device *, void *);
52:
53: void vme2chip_init(struct vmesoftc *);
54: void vmesyscon_init(struct vmesoftc *);
55: u_long vme2chip_map(u_long, int);
56: int vme2abort(void *);
57: int sysconabort(void *);
58: int vmeprint(void *, const char *);
59:
60: int vmebustype;
61: unsigned int vmevecbase;
62:
63: struct cfattach vme_ca = {
64: sizeof(struct vmesoftc), vmematch, vmeattach
65: };
66:
67: struct cfdriver vme_cd = {
68: NULL, "vme", DV_DULL
69: };
70:
71: /*
72: * bus_space routines for VME mappings
73: */
74:
75: int vme_map(bus_addr_t, bus_size_t, int, bus_space_handle_t *);
76: void vme_unmap(bus_space_handle_t, bus_size_t);
77: int vme_subregion(bus_space_handle_t, bus_size_t, bus_size_t,
78: bus_space_handle_t *);
79: void * vme_vaddr(bus_space_handle_t);
80:
81: const struct mvme88k_bus_space_tag vme_bustag = {
82: vme_map,
83: vme_unmap,
84: vme_subregion,
85: vme_vaddr
86: };
87:
88: /*
89: * VME space mapping functions
90: */
91:
92: int
93: vme_map(bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t *ret)
94: {
95: vaddr_t map;
96:
97: map = (vaddr_t)mapiodev((paddr_t)addr, size);
98: if (map == NULL)
99: return ENOMEM;
100:
101: *ret = (bus_space_handle_t)map;
102: return 0;
103: }
104:
105: void
106: vme_unmap(bus_space_handle_t handle, bus_size_t size)
107: {
108: unmapiodev((vaddr_t)handle, size);
109: }
110:
111: int
112: vme_subregion(bus_space_handle_t handle, bus_addr_t offset, bus_size_t size,
113: bus_space_handle_t *ret)
114: {
115: *ret = handle + offset;
116: return (0);
117: }
118:
119: void *
120: vme_vaddr(bus_space_handle_t handle)
121: {
122: return (void *)handle;
123: }
124:
125: /*
126: * Extra D16 access functions
127: *
128: * D16 cards will trigger bus errors on attempting to read or write more
129: * than 16 bits on the bus. Given how the m88k processor works, this means
130: * basically that all long (D32) accesses must be carefully taken care of.
131: *
132: * Since the kernels bcopy() and bzero() routines will use 32 bit accesses
133: * for performance, here are specific D16-compatible routines. They will
134: * also revert to D8 operations if neither of the operands is properly
135: * aligned.
136: */
137:
138: void d16_bcopy(const void *, void *, size_t);
139: void d16_bzero(void *, size_t);
140:
141: void
142: d16_bcopy(const void *src, void *dst, size_t len)
143: {
144: if ((vaddr_t)src & 1 || (vaddr_t)dst & 1)
145: bus_space_write_region_1(&vme_bustag, 0, (vaddr_t)dst,
146: (void *)src, len);
147: else {
148: bus_space_write_region_2(&vme_bustag, 0, (vaddr_t)dst,
149: (void *)src, len / 2);
150: if (len & 1)
151: bus_space_write_1(&vme_bustag, 0,
152: dst + len - 1, *(u_int8_t *)(src + len - 1));
153: }
154: }
155:
156: void
157: d16_bzero(void *dst, size_t len)
158: {
159: if ((vaddr_t)dst & 1)
160: bus_space_set_region_1(&vme_bustag, 0, (vaddr_t)dst, 0, len);
161: else {
162: bus_space_set_region_2(&vme_bustag, 0, (vaddr_t)dst, 0, len / 2);
163: if (len & 1)
164: bus_space_write_1(&vme_bustag, 0, dst + len - 1, 0);
165: }
166: }
167:
168: /*
169: * Configuration glue
170: */
171:
172: int
173: vmematch(parent, cf, args)
174: struct device *parent;
175: void *cf;
176: void *args;
177: {
178: #ifdef MVME187
179: if (brdtyp == BRD_8120)
180: return (0);
181: #endif
182: return (1);
183: }
184:
185: int
186: vmeprint(args, bus)
187: void *args;
188: const char *bus;
189: {
190: struct confargs *ca = args;
191:
192: printf(" addr 0x%x", ca->ca_paddr);
193: if (ca->ca_ipl > 0)
194: printf(" ipl %d", ca->ca_ipl);
195: if (ca->ca_vec > 0)
196: printf(" vec 0x%x", ca->ca_vec);
197: return (UNCONF);
198: }
199:
200: int
201: vmescan(parent, child, args, bustype)
202: struct device *parent;
203: void *child, *args;
204: int bustype;
205: {
206: struct cfdata *cf = child;
207: struct confargs oca, *ca = args;
208:
209: bzero(&oca, sizeof oca);
210: oca.ca_iot = &vme_bustag;
211: oca.ca_dmat = ca->ca_dmat;
212: oca.ca_bustype = bustype;
213: oca.ca_paddr = cf->cf_loc[0];
214: oca.ca_vec = cf->cf_loc[1];
215: oca.ca_ipl = cf->cf_loc[2];
216: if (oca.ca_ipl > 0 && oca.ca_vec < 0)
217: oca.ca_vec = vme_findvec(-1);
218: oca.ca_name = cf->cf_driver->cd_name;
219:
220: if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0)
221: return (0);
222:
223: config_attach(parent, cf, &oca, vmeprint);
224: return (1);
225: }
226:
227: void
228: vmeattach(parent, self, args)
229: struct device *parent, *self;
230: void *args;
231: {
232: struct vmesoftc *sc = (struct vmesoftc *)self;
233: struct confargs *ca = args;
234:
235: /*
236: * This is a waste if we are attached to SYSCON - but then obio
237: * mappings are free...
238: */
239: sc->sc_iot = ca->ca_iot;
240: if (bus_space_map(sc->sc_iot, ca->ca_paddr, PAGE_SIZE, 0,
241: &sc->sc_ioh) != 0) {
242: printf(": can't map registers!\n");
243: return;
244: }
245:
246: vmebustype = ca->ca_bustype;
247:
248: switch (ca->ca_bustype) {
249: #if NPCCTWO > 0
250: case BUS_PCCTWO:
251: {
252: u_int32_t vbr;
253:
254: /* Sanity check that the BUG is set up right */
255: vbr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_VBR);
256: vmevecbase = VME2_GET_VBR1(vbr) + 0x10;
257: if (vmevecbase >= 0x100) {
258: panic("Correct the VME Vector Base Registers "
259: "in the Bug ROM.\n"
260: "Suggested values are 0x60 for VME Vec0 and "
261: "0x70 for VME Vec1.");
262: }
263:
264: if ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_TCTL) &
265: VME2_TCTL_SCON) != 0)
266: printf(": system controller");
267: printf("\n");
268:
269: vme2chip_init(sc);
270: }
271: break;
272: #endif
273: #if NSYSCON > 0
274: case BUS_SYSCON:
275: {
276: u_int8_t sconc;
277:
278: vmevecbase = 0x60; /* Hard coded for MVME188 */
279: sconc = *(volatile u_int8_t *)MVME188_GLOBAL1;
280: if (ISSET(sconc, M188_SYSCON))
281: printf(": system controller");
282: printf("\n");
283:
284: vmesyscon_init(sc);
285: }
286: break;
287: #endif
288: }
289:
290: while (config_found(self, NULL, NULL))
291: ;
292: }
293:
294: /* find a VME vector based on what is in NVRAM settings. */
295: int
296: vme_findvec(int skip)
297: {
298: return intr_findvec(vmevecbase, 0xff, skip);
299: }
300:
301: /*
302: * make local addresses 1G-2G correspond to VME addresses 3G-4G,
303: * as D32
304: */
305:
306: #define VME2_D32STARTPHYS (1*1024*1024*1024UL)
307: #define VME2_D32ENDPHYS (2*1024*1024*1024UL)
308: #define VME2_D32STARTVME (3*1024*1024*1024UL)
309: #define VME2_D32BITSVME (3*1024*1024*1024UL)
310:
311: /*
312: * make local addresses 3G-3.75G correspond to VME addresses 3G-3.75G,
313: * as D16
314: */
315: #define VME2_D16STARTPHYS (3*1024*1024*1024UL)
316: #define VME2_D16ENDPHYS (3*1024*1024*1024UL + 768*1024*1024UL)
317: #define VME2_A32D16STARTPHYS (0xff000000UL)
318: #define VME2_A32D16ENDPHYS (0xff7fffffUL)
319:
320:
321: /*
322: * Returns a physical address mapping for a VME address & length.
323: * Note: on some hardware it is not possible to create certain
324: * mappings, ie. the MVME147 cannot do 32 bit accesses to VME bus
325: * addresses from 0 to physmem.
326: */
327: paddr_t
328: vmepmap(sc, vmeaddr, bustype)
329: struct device *sc;
330: off_t vmeaddr;
331: int bustype;
332: {
333: u_int32_t base = (u_int32_t)vmeaddr; /* wrap around 4GB */
334:
335: switch (vmebustype) {
336: #if NPCCTWO > 0 || NSYSCON > 0
337: case BUS_PCCTWO:
338: case BUS_SYSCON:
339: switch (bustype) {
340: case BUS_VMES: /* D16 VME Transfers */
341: #ifdef DEBUG
342: printf("base 0x%8llx/0x%8x\n",
343: vmeaddr, base);
344: #endif
345: base = vme2chip_map(base, 16);
346: #ifdef DEBUG
347: if (base == NULL) {
348: printf("%s: cannot map pa 0x%x\n",
349: sc->dv_xname, base);
350: }
351: #endif
352: break;
353: case BUS_VMEL: /* D32 VME Transfers */
354: #ifdef DEBUG
355: printf("base 0x%8llx/0x%8x\n",
356: vmeaddr, base);
357: #endif
358: base = vme2chip_map(base, 32);
359: #ifdef DEBUG
360: if (base == NULL) {
361: printf("%s: cannot map pa 0x%x\n",
362: sc->dv_xname, base);
363: }
364: #endif
365: break;
366: }
367: break;
368: #endif
369: default:
370: return NULL;
371: }
372: return (base);
373: }
374:
375: static vaddr_t vmemap(struct vmesoftc *, off_t);
376: static void vmeunmap(paddr_t);
377:
378: /* if successful, returns the va of a vme bus mapping */
379: static __inline__ vaddr_t
380: vmemap(struct vmesoftc *sc, off_t vmeaddr)
381: {
382: paddr_t pa;
383:
384: pa = vmepmap((struct device *)sc, vmeaddr, BUS_VMES);
385: if (pa == NULL)
386: return (NULL);
387: return mapiodev(pa, PAGE_SIZE);
388: }
389:
390: static __inline__ void
391: vmeunmap(vaddr_t va)
392: {
393: unmapiodev(va, PAGE_SIZE);
394: }
395:
396: int
397: vmerw(sc, uio, flags, bus)
398: struct device *sc;
399: struct uio *uio;
400: int flags;
401: int bus;
402: {
403: vaddr_t v;
404: int c;
405: struct iovec *iov;
406: paddr_t vme;
407: int error = 0;
408:
409: while (uio->uio_resid > 0 && error == 0) {
410: iov = uio->uio_iov;
411: if (iov->iov_len == 0) {
412: uio->uio_iov++;
413: uio->uio_iovcnt--;
414: if (uio->uio_iovcnt < 0)
415: panic("vmerw");
416: continue;
417: }
418:
419: v = uio->uio_offset;
420: c = min(iov->iov_len, MAXPHYS);
421: if ((v & PGOFSET) + c > PAGE_SIZE) /* max 1 page at a time */
422: c = PAGE_SIZE - (v & PGOFSET);
423: if (c == 0)
424: return 0;
425: vme = vmemap((struct vmesoftc *)sc, v & ~PGOFSET);
426: if (vme == NULL)
427: return EACCES;
428: error = uiomove((void *)vme + (v & PGOFSET), c, uio);
429: vmeunmap(vme);
430: }
431: return error;
432: }
433:
434: #ifdef MVME188
435: /*
436: * Currently registered VME interrupt vectors for a given IPL, if they
437: * are unique. Used to help the MVME188 interrupt handler when it's getting
438: * behind.
439: */
440: u_int vmevec_hints[8] = {
441: (u_int)-1, (u_int)-1, (u_int)-1, (u_int)-1,
442: (u_int)-1, (u_int)-1, (u_int)-1, (u_int)-1
443: };
444: #endif
445:
446: /*
447: * On the VMEbus, only one cpu may be configured to respond to any
448: * particular vme ipl. Therefore, it wouldn't make sense to globally
449: * enable all the interrupts all the time -- it would not be possible
450: * to put two cpu's and one vme card into a single cage. Rather, we
451: * enable each vme interrupt only when we are attaching a device that
452: * uses it. This makes it easier (though not trivial) to put two cpu
453: * cards in one VME cage, and both can have some limited access to vme
454: * interrupts (just can't share the same irq).
455: * Obviously no check is made to see if another cpu is using that
456: * interrupt. If you share you will lose.
457: */
458:
459: int
460: vmeintr_establish(int vec, struct intrhand *ih, const char *name)
461: {
462: struct vmesoftc *sc = (struct vmesoftc *) vme_cd.cd_devs[0];
463: int rc;
464:
465: #ifdef DIAGNOSTIC
466: if (ih->ih_ipl < 1 || ih->ih_ipl > 7)
467: return (EINVAL);
468: #endif
469:
470: switch (vmebustype) {
471: #if NPCCTWO > 0
472: case BUS_PCCTWO:
473: bus_space_write_4(sc->sc_iot, sc->sc_ioh, VME2_IRQEN,
474: bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_IRQEN) |
475: VME2_IRQ_VME(ih->ih_ipl));
476: break;
477: #endif
478: }
479:
480: if ((rc = intr_establish(vec, ih, name)) != 0)
481: return (rc);
482:
483: #ifdef MVME188
484: if (vmevec_hints[ih->ih_ipl] == (u_int)-1)
485: vmevec_hints[ih->ih_ipl] = vec;
486: else
487: vmevec_hints[ih->ih_ipl] = (u_int)-1;
488: #endif
489:
490: return (0);
491: }
492:
493: #if NPCCTWO > 0
494: void
495: vme2chip_init(sc)
496: struct vmesoftc *sc;
497: {
498: u_int32_t ctl, irqen, master, master4mod;
499:
500: /* turn off SYSFAIL LED */
501: bus_space_write_4(sc->sc_iot, sc->sc_ioh, VME2_TCTL,
502: bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_TCTL) &
503: ~VME2_TCTL_SYSFAIL);
504:
505: /*
506: * Display the VMEChip2 decoder status.
507: */
508: printf("%s: using BUG parameters\n", sc->sc_dev.dv_xname);
509: ctl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_GCSRCTL);
510: if (ctl & VME2_GCSRCTL_MDEN1) {
511: master = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_MASTER1);
512: printf("%s: 1phys 0x%08lx-0x%08lx to VME 0x%08lx-0x%08lx\n",
513: sc->sc_dev.dv_xname, master << 16, master & 0xffff0000,
514: master << 16, master & 0xffff0000);
515: }
516: if (ctl & VME2_GCSRCTL_MDEN2) {
517: master = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_MASTER2);
518: printf("%s: 2phys 0x%08lx-0x%08lx to VME 0x%08lx-0x%08lx\n",
519: sc->sc_dev.dv_xname, master << 16, master & 0xffff0000,
520: master << 16, master & 0xffff0000);
521: }
522: if (ctl & VME2_GCSRCTL_MDEN3) {
523: master = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_MASTER3);
524: printf("%s: 3phys 0x%08lx-0x%08lx to VME 0x%08lx-0x%08lx\n",
525: sc->sc_dev.dv_xname, master << 16, master & 0xffff0000,
526: master << 16, master & 0xffff0000);
527: }
528: if (ctl & VME2_GCSRCTL_MDEN4) {
529: master = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_MASTER4);
530: master4mod = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
531: VME2_MASTER4MOD);
532: printf("%s: 4phys 0x%08lx-0x%08lx to VME 0x%08lx-0x%08lx\n",
533: sc->sc_dev.dv_xname, master << 16, master & 0xffff0000,
534: (master << 16) + (master4mod << 16),
535: (master & 0xffff0000) + (master4mod & 0xffff0000));
536: }
537:
538: /*
539: * Map the VME irq levels to the cpu levels 1:1.
540: * This is rather inflexible, but much easier.
541: */
542: bus_space_write_4(sc->sc_iot, sc->sc_ioh, VME2_IRQL4,
543: (7 << VME2_IRQL4_VME7SHIFT) | (6 << VME2_IRQL4_VME6SHIFT) |
544: (5 << VME2_IRQL4_VME5SHIFT) | (4 << VME2_IRQL4_VME4SHIFT) |
545: (3 << VME2_IRQL4_VME3SHIFT) | (2 << VME2_IRQL4_VME2SHIFT) |
546: (1 << VME2_IRQL4_VME1SHIFT));
547: printf("%s: vme to cpu irq level 1:1\n",sc->sc_dev.dv_xname);
548:
549: /* Enable the reset switch */
550: bus_space_write_4(sc->sc_iot, sc->sc_ioh, VME2_TCTL, VME2_TCTL_RSWE |
551: bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_TCTL));
552: /* Set Watchdog timeout to about 1 minute */
553: bus_space_write_4(sc->sc_iot, sc->sc_ioh, VME2_TCR, VME2_TCR_64S |
554: bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_TCR));
555: /* Enable VMEChip2 Interrupts */
556: bus_space_write_4(sc->sc_iot, sc->sc_ioh, VME2_VBR, VME2_IOCTL1_MIEN |
557: bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_VBR));
558:
559: /*
560: * Map the Software VME irq levels to the cpu level 7.
561: */
562: bus_space_write_4(sc->sc_iot, sc->sc_ioh, VME2_IRQL3,
563: (7 << VME2_IRQL3_SW7SHIFT) | (7 << VME2_IRQL3_SW6SHIFT) |
564: (7 << VME2_IRQL3_SW5SHIFT) | (7 << VME2_IRQL3_SW4SHIFT) |
565: (7 << VME2_IRQL3_SW3SHIFT) | (7 << VME2_IRQL3_SW2SHIFT) |
566: (7 << VME2_IRQL3_SW1SHIFT));
567:
568: /*
569: * pseudo driver, abort interrupt handler
570: */
571: sc->sc_abih.ih_fn = vme2abort;
572: sc->sc_abih.ih_arg = 0;
573: sc->sc_abih.ih_wantframe = 1;
574: sc->sc_abih.ih_ipl = IPL_NMI;
575: intr_establish(110, &sc->sc_abih, sc->sc_dev.dv_xname);
576:
577: irqen = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_IRQEN);
578: irqen |= VME2_IRQ_AB;
579: /* bus_space_write_4(sc->sc_iot, sc->sc_ioh, VME2_IRQEN, irqen); */
580:
581: /*
582: * Enable ACFAIL interrupt, but disable Timer 1 interrupt - we
583: * prefer it without for delay().
584: */
585: irqen = (irqen | VME2_IRQ_ACF) & ~VME2_IRQ_TIC1;
586: bus_space_write_4(sc->sc_iot, sc->sc_ioh, VME2_IRQEN, irqen);
587: }
588: #endif /* NPCCTWO */
589:
590: #if NSYSCON > 0
591: void
592: vmesyscon_init(sc)
593: struct vmesoftc *sc;
594: {
595: u_int32_t ucsr;
596:
597: /*
598: * Force a reasonable timeout for VME data transfers.
599: * We can not disable this, this would cause autoconf to hang
600: * on the first missing device we'll probe.
601: */
602: ucsr = *(volatile u_int32_t*)MVME188_UCSR;
603: ucsr = (ucsr & ~VTOSELBITS) | VTO128US;
604: *(volatile u_int32_t *)MVME188_UCSR = ucsr;
605: }
606: #endif /* NSYSCON */
607:
608: /*
609: * A32 accesses on the MVME1[6789]x require setting up mappings in
610: * the VME2 chip.
611: * XXX VME address must be between 2G and 4G
612: * XXX We only support D32 at the moment..
613: * XXX smurph - This is bogus, get rid of it! Should check vme/syscon for offsets.
614: */
615: u_long
616: vme2chip_map(base, dwidth)
617: u_long base;
618: int dwidth;
619: {
620: /*
621: * Since we are checking range for one page only, no need to check
622: * for address wraparound.
623: */
624: switch (dwidth) {
625: case 16:
626: if (base < VME2_D16STARTPHYS ||
627: base + PAGE_SIZE > VME2_D16ENDPHYS)
628: return NULL;
629: break;
630: case 32:
631: if (base < VME2_D32STARTPHYS ||
632: base + PAGE_SIZE > VME2_D32ENDPHYS)
633: return NULL;
634: break;
635: default:
636: return NULL;
637: }
638: return base;
639: }
640:
641: #if NPCCTWO > 0
642: int
643: vme2abort(eframe)
644: void *eframe;
645: {
646: struct vmesoftc *sc = (struct vmesoftc *)vme_cd.cd_devs[0];
647:
648: if ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, VME2_IRQSTAT) &
649: VME2_IRQ_AB) == 0) {
650: printf("%s: abort irq not set\n", sc->sc_dev.dv_xname);
651: return (0);
652: }
653:
654: bus_space_write_4(sc->sc_iot, sc->sc_ioh, VME2_IRQCLR, VME2_IRQ_AB);
655: nmihand(eframe);
656: return (1);
657: }
658: #endif
CVSweb