home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1987, 1988 Regents of the University of California.
- * All rights reserved.
- *
- * 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 University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- * @(#)vba.c 7.6 (Berkeley) 12/16/90
- */
-
- /*
- * Tahoe VERSAbus adapator support routines.
- */
-
- #include "sys/param.h"
- #include "sys/buf.h"
- #include "sys/cmap.h"
- #include "sys/conf.h"
- #include "dk.h"
- #include "sys/map.h"
- #include "sys/systm.h"
- #include "sys/user.h"
- #include "sys/vmparam.h"
- #include "sys/vmmac.h"
- #include "sys/proc.h"
- #include "sys/syslog.h"
- #include "sys/malloc.h"
-
- #include "../include/mtpr.h"
- #include "../include/pte.h"
-
- #include "../vba/vbavar.h"
-
- /*
- * Allocate private page map and intermediate buffer
- * for a VERSAbus device, large enough for maximum transfer size.
- * Intermediate buffer
- * Make intermediate buffer uncacheable.
- */
- vbainit(vb, xsize, flags)
- register struct vb_buf *vb;
- int xsize, flags;
- {
- register struct pte *pte;
- register n;
-
- vb->vb_flags = flags;
- if (vbmapalloc((int)btoc(xsize) + 1, &vb->vb_map, &vb->vb_utl) == 0) {
- printf("vbmap exhausted\n");
- return (0);
- }
- n = roundup(xsize, NBPG);
- vb->vb_bufsize = n;
- if (vb->vb_rawbuf == 0)
- vb->vb_rawbuf = (caddr_t)malloc((u_long)n, M_DEVBUF, M_NOWAIT);
- if (vb->vb_rawbuf == 0) {
- printf("no memory for device buffer\n");
- return (0);
- }
- if ((int)vb->vb_rawbuf & PGOFSET)
- panic("vbinit pgoff");
- vb->vb_physbuf = (u_long)kvtophys(vb->vb_rawbuf);
- if (flags & VB_20BIT)
- vb->vb_maxphys = btoc(VB_MAXADDR20);
- else if (flags & VB_24BIT)
- vb->vb_maxphys = btoc(VB_MAXADDR24);
- else
- vb->vb_maxphys = btoc(VB_MAXADDR32);
- if (btoc(vb->vb_physbuf + n) > vb->vb_maxphys)
- panic("vbinit physbuf");
-
- /*
- * Make raw buffer pages uncacheable.
- */
- pte = kvtopte(vb->vb_rawbuf);
- for (n = btoc(n); n--; pte++)
- pte->pg_nc = 1;
- mtpr(TBIA, 0);
- return (1);
- }
-
- /*
- * Due to unknown hardware or software errors, some sites have problems
- * with strange crashes or corruption of text images when DMA is attempted
- * to kernel addresses spanning a page boundary, or to user addresses
- * (even if the buffer is physically contiguous). To avoid this behavior,
- * the following toggles inhibit such transfers when set.
- * vba_copyk: copy transfers to kernel address that span a page boundary
- * vba_copyu: copy transfers to user addresses
- */
- #ifndef VBA_TRICKY
- int vba_copyk = 1;
- int vba_copyu = 1;
- #else
- int vba_copyk = 0;
- int vba_copyu = 0;
- #endif
-
- /*
- * Check a transfer to see whether it can be done directly
- * to the destination buffer, or whether it must be copied.
- * On Tahoe, the lack of a bus I/O map forces data to be copied
- * to a physically-contiguous buffer whenever one of the following is true:
- * 1) The data length is not a multiple of sector size.
- * (The swapping code does this, unfortunately.)
- * 2) The buffer is not physically contiguous and the controller
- * does not support scatter-gather operations.
- * 3) The physical address for I/O is higher than addressible
- * by the device.
- * This routine is called by the start routine.
- * If copying is necessary, the intermediate buffer is mapped;
- * if the operation is a write, the data is copied into the buffer.
- * It returns the physical address of the first byte for DMA, to
- * be presented to the controller.
- */
- u_long
- vbasetup(bp, vb, sectsize)
- register struct buf *bp;
- register struct vb_buf *vb;
- int sectsize;
- {
- register struct pte *spte, *dpte;
- register int p, i;
- int npf, o, v;
-
- o = (int)bp->b_un.b_addr & PGOFSET;
- npf = btoc(bp->b_bcount + o);
- vb->vb_iskernel = (((int)bp->b_un.b_addr & KERNBASE) == KERNBASE);
- if (vb->vb_iskernel) {
- spte = kvtopte(bp->b_un.b_addr);
- if (vba_copyk && (o != 0 || npf > 1)) goto copy;
- } else {
- spte = vtopte((bp->b_flags&B_DIRTY) ? &proc[2] : bp->b_proc,
- btop(bp->b_un.b_addr));
- if (vba_copyu) goto copy;
- }
- if (bp->b_bcount % sectsize != 0 || (o & (sizeof(long) - 1)) != 0)
- goto copy;
- else if ((vb->vb_flags & VB_SCATTER) == 0 ||
- vb->vb_maxphys != btoc(VB_MAXADDR32)) {
- dpte = spte;
- p = (dpte++)->pg_pfnum;
- for (i = npf; --i > 0; dpte++) {
- if ((v = dpte->pg_pfnum) != p + CLSIZE &&
- (vb->vb_flags & VB_SCATTER) == 0)
- goto copy;
- if (p >= vb->vb_maxphys)
- goto copy;
- p = v;
- }
- if (p >= vb->vb_maxphys)
- goto copy;
- }
- vb->vb_copy = 0;
- if (vb->vb_iskernel)
- vbastat.k_raw++;
- else
- vbastat.u_raw++;
- return ((spte->pg_pfnum << PGSHIFT) + o);
-
- copy:
- vb->vb_copy = 1;
- if (bp->b_bcount > vb->vb_bufsize)
- panic("vba xfer too large");
- if (vb->vb_iskernel) {
- if ((bp->b_flags & B_READ) == 0)
- bcopy(bp->b_un.b_addr, vb->vb_rawbuf,
- (unsigned)bp->b_bcount);
- vbastat.k_copy++;
- } else {
- dpte = vb->vb_map;
- for (i = npf, p = (int)vb->vb_utl; i--; p += NBPG) {
- *(int *)dpte++ = (spte++)->pg_pfnum |
- PG_V | PG_KW | PG_N;
- mtpr(TBIS, p);
- }
- if ((bp->b_flags & B_READ) == 0)
- bcopy(vb->vb_utl + o, vb->vb_rawbuf,
- (unsigned)bp->b_bcount);
- vbastat.u_copy++;
- }
- return (vb->vb_physbuf);
- }
-
- /*
- * Called by the driver's interrupt routine, after DMA is completed.
- * If the operation was a read, copy data to final buffer if necessary
- * or invalidate data cache for cacheable direct buffers.
- * Similar to the vbastart routine, but in the reverse direction.
- */
- vbadone(bp, vb)
- register struct buf *bp;
- register struct vb_buf *vb;
- {
- register npf;
- register caddr_t v;
- int o;
-
- if (bp->b_flags & B_READ) {
- o = (int)bp->b_un.b_addr & PGOFSET;
- if (vb->vb_copy) {
- if (vb->vb_iskernel)
- bcopy(vb->vb_rawbuf, bp->b_un.b_addr,
- (unsigned)(bp->b_bcount - bp->b_resid));
- else {
- bcopy(vb->vb_rawbuf, vb->vb_utl + o,
- (unsigned)(bp->b_bcount - bp->b_resid));
- dkeyinval(bp->b_proc);
- }
- } else {
- if (vb->vb_iskernel) {
- npf = btoc(bp->b_bcount + o);
- for (v = bp->b_un.b_addr; npf--; v += NBPG)
- mtpr(P1DC, (int)v);
- } else
- dkeyinval(bp->b_proc);
- }
- }
- }
-
- /*
- * Set up a scatter-gather operation for SMD/E controller.
- * This code belongs half-way between {hd,vd}.c and this file.
- */
-
- #include "dk.h"
- #if NVD > 0
- #include "vdreg.h"
-
- vd_sgsetup(bp, vb, sg)
- register struct buf *bp;
- struct vb_buf *vb;
- struct trsg *sg;
- {
- register struct pte *spte;
- register struct addr_chain *adr;
- register int i;
- int o;
-
- vb->vb_iskernel = (((int)bp->b_un.b_addr & KERNBASE) == KERNBASE);
- vb->vb_copy = 0;
- if (vb->vb_iskernel) {
- spte = kvtopte(bp->b_un.b_addr);
- vbastat.k_sg++;
- } else {
- spte = vtopte((bp->b_flags&B_DIRTY) ? &proc[2] : bp->b_proc,
- btop(bp->b_un.b_addr));
- vbastat.u_sg++;
- }
-
- o = (int)bp->b_un.b_addr & PGOFSET;
- i = min(NBPG - o, bp->b_bcount);
- sg->start_addr.wcount = i >> 1;
- sg->start_addr.memadr = ((spte++)->pg_pfnum << PGSHIFT) + o;
- i = bp->b_bcount - i;
- if (i > VDMAXPAGES * NBPG)
- panic("vba xfer too large");
- i = i >> 1;
- for (adr = sg->addr_chain; i > 0; adr++, i -= NBPG / 2) {
- adr->nxt_addr = (spte++)->pg_pfnum << PGSHIFT;
- adr->nxt_len = imin(i, NBPG / 2);
- }
- adr->nxt_addr = 0;
- adr++->nxt_len = 0;
- return ((adr - sg->addr_chain) * sizeof(*adr) / sizeof(long));
- }
- #endif
-
- #include "hd.h"
- #if NHD > 0
- #include "hdreg.h"
-
- hd_sgsetup(bp, vb, sg)
- register struct buf *bp;
- struct vb_buf *vb;
- struct chain *sg;
- {
- register struct pte *spte;
- register struct addr_chain *adr;
- register int i, cnt;
- int o;
-
- if (bp->b_bcount > HDC_MAXBC ||
- bp->b_bcount % sizeof(long) - 1 ||
- (u_int)bp->b_un.b_addr % sizeof(long) - 1)
- return(0);
-
- vb->vb_iskernel = (((int)bp->b_un.b_addr & KERNBASE) == KERNBASE);
- vb->vb_copy = 0;
- if (vb->vb_iskernel) {
- spte = kvtopte(bp->b_un.b_addr);
- vbastat.k_sg++;
- } else {
- spte = vtopte((bp->b_flags&B_DIRTY) ? &proc[2] : bp->b_proc,
- btop(bp->b_un.b_addr));
- vbastat.u_sg++;
- }
-
- o = (int)bp->b_un.b_addr & PGOFSET;
- i = min(NBPG - o, bp->b_bcount);
- sg->wcount = i >> 2;
- sg->memadr = ((spte++)->pg_pfnum << PGSHIFT) + o;
- cnt = 0;
- for (i = (bp->b_bcount - i) >> 2; i > 0; i -= NBPG / sizeof(long)) {
- if (++cnt == HDC_MAXCHAIN)
- return(0);
- sg->wcount |= LWC_DATA_CHAIN;
- ++sg;
- sg->wcount = imin(i, NBPG / sizeof(long));
- sg->memadr = (spte++)->pg_pfnum << PGSHIFT;
- }
- return(1);
- }
- #endif
-