/* $NetBSD: bus_subr.c,v 1.7 1997/05/30 07:02:14 jeremy Exp $ */ /*- * Copyright (c) 1996 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Adam Glass and Gordon W. Ross. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * bus_xxx support functions */ #include #include #include #include #include #include #include #include #include #include #include #include /* * bus_scan: * This function is passed to config_search() by the attach function * for each of the "bus" drivers (obctl, obio, obmem, vmes, vmel). * The purpose of this function is to copy the "locators" into our * confargs structure, so child drivers may use the confargs both * as match parameters and as temporary storage for the defaulted * locator values determined in the child_match and preserved for * the child_attach function. If the bus attach functions just * used config_found, then we would not have an opportunity to * setup the confargs for each child match and attach call. */ int bus_scan(parent, cf, aux) struct device *parent; struct cfdata *cf; void *aux; { struct confargs *ca = aux; cfmatch_t mf; #ifdef DIAGNOSTIC if (cf->cf_fstate == FSTATE_STAR) panic("bus_scan: FSTATE_STAR"); #endif /* * Copy the locators into our confargs. * Our parent set ca->ca_bustype already. */ ca->ca_paddr = cf->cf_paddr; ca->ca_intpri = cf->cf_intpri; ca->ca_intvec = cf->cf_intvec; /* * Note that this allows the match function to save * defaulted locators in the confargs that will be * preserved for the related attach call. * XXX - This is a hack... */ mf = cf->cf_attach->ca_match; if ((*mf)(parent, cf, ca) > 0) { config_attach(parent, cf, ca, bus_print); } return (0); } /* * bus_print: * Just print out the final (non-default) locators. * The parent name is non-NULL when there was no match * found by config_found(). */ int bus_print(args, name) void *args; const char *name; { struct confargs *ca = args; if (name) printf("%s:", name); if (ca->ca_paddr != -1) printf(" addr 0x%x", ca->ca_paddr); if (ca->ca_intpri != -1) printf(" ipl %d", ca->ca_intpri); if (ca->ca_intvec != -1) printf(" vect 0x%x", ca->ca_intvec); return(UNCONF); } /****************************************************************/ /* support functions */ label_t *nofault; /* These are defined in pmap.c */ extern vm_offset_t tmp_vpages[]; extern int tmp_vpages_inuse; static const int bustype_to_patype[4] = { 0, /* OBMEM */ 0, /* OBIO */ PMAP_VME16, /* VMED16 */ PMAP_VME32, /* VMED32 */ }; /* * Read addr with size len (1,2,4) into val. * If this generates a bus error, return -1 * * Create a temporary mapping, * Try the access using peek_* * Clean up temp. mapping */ int bus_peek(bustype, paddr, sz) int bustype, paddr, sz; { int offset, rtn, s; vm_offset_t va_page; caddr_t va; /* XXX - Must fix for VME support... */ if (bustype != OBIO && bustype != OBMEM) return -1; offset = paddr & ~(MMU_PAGE_MASK); paddr = _trunc_page(paddr); paddr |= bustype_to_patype[bustype]; paddr |= PMAP_NC; s = splimp(); if (tmp_vpages_inuse) panic("bus_peek: temporary vpages are in use."); tmp_vpages_inuse++; va_page = tmp_vpages[1]; va = (caddr_t) va_page + offset; pmap_enter(pmap_kernel(), va_page, paddr, (VM_PROT_READ|VM_PROT_WRITE), TRUE); switch (sz) { case 1: rtn = peek_byte(va); break; case 2: rtn = peek_word(va); break; case 4: rtn = peek_long(va); break; default: printf(" bus_peek: invalid size=%d\n", sz); rtn = -1; } pmap_remove(pmap_kernel(), va_page, va_page + NBPG); --tmp_vpages_inuse; splx(s); return (rtn); } void * bus_mapin(bustype, paddr, sz) int bustype, paddr, sz; { int off, pa, pmt; vm_offset_t va, retval; if (bustype & ~3) return (NULL); off = paddr & PGOFSET; pa = paddr - off; sz += off; sz = round_page(sz); pmt = PMAP_NC; /* non-cached */ /* Get some kernel virtual address space. */ va = kmem_alloc_wait(kernel_map, sz); if (va == 0) panic("bus_mapin"); retval = va + off; /* Map it to the specified bus. */ #if 0 /* This has a problem with wrap-around... (on the sun3x? -j) */ pmap_map((int)va, pa | pmt, pa + sz, VM_PROT_ALL); #else do { pmap_enter(pmap_kernel(), va, pa | pmt, VM_PROT_ALL, FALSE); va += NBPG; pa += NBPG; } while ((sz -= NBPG) > 0); #endif return ((void*)retval); } /* from hp300: badbaddr() */ int peek_byte(addr) register caddr_t addr; { label_t faultbuf; register int x; nofault = &faultbuf; if (setjmp(&faultbuf)) { nofault = NULL; return(-1); } x = *(volatile u_char *)addr; nofault = NULL; return(x); } int peek_word(addr) register caddr_t addr; { label_t faultbuf; register int x; nofault = &faultbuf; if (setjmp(&faultbuf)) { nofault = NULL; return(-1); } x = *(volatile u_short *)addr; nofault = NULL; return(x); } int peek_long(addr) register caddr_t addr; { label_t faultbuf; register int x; nofault = &faultbuf; if (setjmp(&faultbuf)) { nofault = NULL; return(-1); } x = *(volatile int *)addr; nofault = NULL; return(x); }