|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1987, 1988 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that the above copyright notice and this paragraph are ! 7: * duplicated in all such forms and that any documentation, ! 8: * advertising materials, and other materials related to such ! 9: * distribution and use acknowledge that the software was developed ! 10: * by the University of California, Berkeley. The name of the ! 11: * University may not be used to endorse or promote products derived ! 12: * from this software without specific prior written permission. ! 13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 16: * ! 17: * @(#)vba.c 7.4 (Berkeley) 5/5/89 ! 18: */ ! 19: ! 20: /* ! 21: * Tahoe VERSAbus adapator support routines. ! 22: */ ! 23: ! 24: #include "param.h" ! 25: #include "buf.h" ! 26: #include "cmap.h" ! 27: #include "conf.h" ! 28: #include "dk.h" ! 29: #include "map.h" ! 30: #include "systm.h" ! 31: #include "dir.h" ! 32: #include "user.h" ! 33: #include "vmparam.h" ! 34: #include "vmmac.h" ! 35: #include "proc.h" ! 36: #include "syslog.h" ! 37: #include "malloc.h" ! 38: ! 39: #include "../tahoe/mtpr.h" ! 40: #include "../tahoe/pte.h" ! 41: ! 42: #include "../tahoevba/vbavar.h" ! 43: ! 44: /* ! 45: * Allocate private page map and intermediate buffer ! 46: * for a VERSAbus device, large enough for maximum transfer size. ! 47: * Intermediate buffer ! 48: * Make intermediate buffer uncacheable. ! 49: */ ! 50: vbainit(vb, xsize, flags) ! 51: register struct vb_buf *vb; ! 52: int xsize, flags; ! 53: { ! 54: register struct pte *pte; ! 55: register n; ! 56: ! 57: vb->vb_flags = flags; ! 58: if (vbmapalloc((int)btoc(xsize) + 1, &vb->vb_map, &vb->vb_utl) == 0) { ! 59: printf("vbmap exhausted\n"); ! 60: return (0); ! 61: } ! 62: n = roundup(xsize, NBPG); ! 63: vb->vb_bufsize = n; ! 64: if (vb->vb_rawbuf == 0) ! 65: vb->vb_rawbuf = (caddr_t)malloc((u_long)n, M_DEVBUF, M_NOWAIT); ! 66: if (vb->vb_rawbuf == 0) { ! 67: printf("no memory for device buffer\n"); ! 68: return (0); ! 69: } ! 70: if ((int)vb->vb_rawbuf & PGOFSET) ! 71: panic("vbinit pgoff"); ! 72: vb->vb_physbuf = (u_long)kvtophys(vb->vb_rawbuf); ! 73: if (flags & VB_20BIT) ! 74: vb->vb_maxphys = btoc(VB_MAXADDR20); ! 75: else if (flags & VB_24BIT) ! 76: vb->vb_maxphys = btoc(VB_MAXADDR24); ! 77: else ! 78: vb->vb_maxphys = btoc(VB_MAXADDR32); ! 79: if (btoc(vb->vb_physbuf + n) > vb->vb_maxphys) ! 80: panic("vbinit physbuf"); ! 81: ! 82: /* ! 83: * Make raw buffer pages uncacheable. ! 84: */ ! 85: pte = kvtopte(vb->vb_rawbuf); ! 86: for (n = btoc(n); n--; pte++) ! 87: pte->pg_nc = 1; ! 88: mtpr(TBIA, 0); ! 89: return (1); ! 90: } ! 91: ! 92: /* ! 93: * Due to unknown hardware or software errors, some sites have problems ! 94: * with strange crashes or corruption of text images when DMA is attempted ! 95: * to kernel addresses spanning a page boundary, or to user addresses ! 96: * (even if the buffer is physically contiguous). To avoid this behavior, ! 97: * the following toggles inhibit such transfers when set. ! 98: * vba_copyk: copy transfers to kernel address that span a page boundary ! 99: * vba_copyu: copy transfers to user addresses ! 100: */ ! 101: #ifndef VBA_TRICKY ! 102: int vba_copyk = 1; ! 103: int vba_copyu = 1; ! 104: #else ! 105: int vba_copyk = 0; ! 106: int vba_copyu = 0; ! 107: #endif ! 108: ! 109: /* ! 110: * Check a transfer to see whether it can be done directly ! 111: * to the destination buffer, or whether it must be copied. ! 112: * On Tahoe, the lack of a bus I/O map forces data to be copied ! 113: * to a physically-contiguous buffer whenever one of the following is true: ! 114: * 1) The data length is not a multiple of sector size. ! 115: * (The swapping code does this, unfortunately.) ! 116: * 2) The buffer is not physically contiguous and the controller ! 117: * does not support scatter-gather operations. ! 118: * 3) The physical address for I/O is higher than addressible ! 119: * by the device. ! 120: * This routine is called by the start routine. ! 121: * If copying is necessary, the intermediate buffer is mapped; ! 122: * if the operation is a write, the data is copied into the buffer. ! 123: * It returns the physical address of the first byte for DMA, to ! 124: * be presented to the controller. ! 125: */ ! 126: u_long ! 127: vbasetup(bp, vb, sectsize) ! 128: register struct buf *bp; ! 129: register struct vb_buf *vb; ! 130: int sectsize; ! 131: { ! 132: register struct pte *spte, *dpte; ! 133: register int p, i; ! 134: int npf, o, v; ! 135: ! 136: o = (int)bp->b_un.b_addr & PGOFSET; ! 137: npf = btoc(bp->b_bcount + o); ! 138: vb->vb_iskernel = (((int)bp->b_un.b_addr & KERNBASE) == KERNBASE); ! 139: if (vb->vb_iskernel) { ! 140: spte = kvtopte(bp->b_un.b_addr); ! 141: if (vba_copyk && (o != 0 || npf > 1)) goto copy; ! 142: } else { ! 143: spte = vtopte((bp->b_flags&B_DIRTY) ? &proc[2] : bp->b_proc, ! 144: btop(bp->b_un.b_addr)); ! 145: if (vba_copyu) goto copy; ! 146: } ! 147: if (bp->b_bcount % sectsize != 0 || (o & (sizeof(long) - 1)) != 0) ! 148: goto copy; ! 149: else if ((vb->vb_flags & VB_SCATTER) == 0 || ! 150: vb->vb_maxphys != btoc(VB_MAXADDR32)) { ! 151: dpte = spte; ! 152: p = (dpte++)->pg_pfnum; ! 153: for (i = npf; --i > 0; dpte++) { ! 154: if ((v = dpte->pg_pfnum) != p + CLSIZE && ! 155: (vb->vb_flags & VB_SCATTER) == 0) ! 156: goto copy; ! 157: if (p >= vb->vb_maxphys) ! 158: goto copy; ! 159: p = v; ! 160: } ! 161: if (p >= vb->vb_maxphys) ! 162: goto copy; ! 163: } ! 164: vb->vb_copy = 0; ! 165: if (vb->vb_iskernel) ! 166: vbastat.k_raw++; ! 167: else ! 168: vbastat.u_raw++; ! 169: return ((spte->pg_pfnum << PGSHIFT) + o); ! 170: ! 171: copy: ! 172: vb->vb_copy = 1; ! 173: if (bp->b_bcount > vb->vb_bufsize) ! 174: panic("vba xfer too large"); ! 175: if (vb->vb_iskernel) { ! 176: if ((bp->b_flags & B_READ) == 0) ! 177: bcopy(bp->b_un.b_addr, vb->vb_rawbuf, ! 178: (unsigned)bp->b_bcount); ! 179: vbastat.k_copy++; ! 180: } else { ! 181: dpte = vb->vb_map; ! 182: for (i = npf, p = (int)vb->vb_utl; i--; p += NBPG) { ! 183: *(int *)dpte++ = (spte++)->pg_pfnum | ! 184: PG_V | PG_KW | PG_N; ! 185: mtpr(TBIS, p); ! 186: } ! 187: if ((bp->b_flags & B_READ) == 0) ! 188: bcopy(vb->vb_utl + o, vb->vb_rawbuf, ! 189: (unsigned)bp->b_bcount); ! 190: vbastat.u_copy++; ! 191: } ! 192: return (vb->vb_physbuf); ! 193: } ! 194: ! 195: /* ! 196: * Called by the driver's interrupt routine, after DMA is completed. ! 197: * If the operation was a read, copy data to final buffer if necessary ! 198: * or invalidate data cache for cacheable direct buffers. ! 199: * Similar to the vbastart routine, but in the reverse direction. ! 200: */ ! 201: vbadone(bp, vb) ! 202: register struct buf *bp; ! 203: register struct vb_buf *vb; ! 204: { ! 205: register npf; ! 206: register caddr_t v; ! 207: int o; ! 208: ! 209: if (bp->b_flags & B_READ) { ! 210: o = (int)bp->b_un.b_addr & PGOFSET; ! 211: if (vb->vb_copy) { ! 212: if (vb->vb_iskernel) ! 213: bcopy(vb->vb_rawbuf, bp->b_un.b_addr, ! 214: (unsigned)(bp->b_bcount - bp->b_resid)); ! 215: else { ! 216: bcopy(vb->vb_rawbuf, vb->vb_utl + o, ! 217: (unsigned)(bp->b_bcount - bp->b_resid)); ! 218: dkeyinval(bp->b_proc); ! 219: } ! 220: } else { ! 221: if (vb->vb_iskernel) { ! 222: npf = btoc(bp->b_bcount + o); ! 223: for (v = bp->b_un.b_addr; npf--; v += NBPG) ! 224: mtpr(P1DC, (int)v); ! 225: } else ! 226: dkeyinval(bp->b_proc); ! 227: } ! 228: } ! 229: } ! 230: ! 231: /* ! 232: * Set up a scatter-gather operation for SMD/E controller. ! 233: * This code belongs half-way between {hd,vd}.c and this file. ! 234: */ ! 235: ! 236: #include "dk.h" ! 237: #if NVD > 0 ! 238: #include "vdreg.h" ! 239: ! 240: vd_sgsetup(bp, vb, sg) ! 241: register struct buf *bp; ! 242: struct vb_buf *vb; ! 243: struct trsg *sg; ! 244: { ! 245: register struct pte *spte; ! 246: register struct addr_chain *adr; ! 247: register int i; ! 248: int o; ! 249: ! 250: vb->vb_iskernel = (((int)bp->b_un.b_addr & KERNBASE) == KERNBASE); ! 251: vb->vb_copy = 0; ! 252: if (vb->vb_iskernel) { ! 253: spte = kvtopte(bp->b_un.b_addr); ! 254: vbastat.k_sg++; ! 255: } else { ! 256: spte = vtopte((bp->b_flags&B_DIRTY) ? &proc[2] : bp->b_proc, ! 257: btop(bp->b_un.b_addr)); ! 258: vbastat.u_sg++; ! 259: } ! 260: ! 261: o = (int)bp->b_un.b_addr & PGOFSET; ! 262: i = min(NBPG - o, bp->b_bcount); ! 263: sg->start_addr.wcount = i >> 1; ! 264: sg->start_addr.memadr = ((spte++)->pg_pfnum << PGSHIFT) + o; ! 265: i = bp->b_bcount - i; ! 266: if (i > VDMAXPAGES * NBPG) ! 267: panic("vba xfer too large"); ! 268: i = i >> 1; ! 269: for (adr = sg->addr_chain; i > 0; adr++, i -= NBPG / 2) { ! 270: adr->nxt_addr = (spte++)->pg_pfnum << PGSHIFT; ! 271: adr->nxt_len = imin(i, NBPG / 2); ! 272: } ! 273: adr->nxt_addr = 0; ! 274: adr++->nxt_len = 0; ! 275: return ((adr - sg->addr_chain) * sizeof(*adr) / sizeof(long)); ! 276: } ! 277: #endif ! 278: ! 279: #include "hd.h" ! 280: #if NHD > 0 ! 281: #include "hdreg.h" ! 282: ! 283: hd_sgsetup(bp, vb, sg) ! 284: register struct buf *bp; ! 285: struct vb_buf *vb; ! 286: struct chain *sg; ! 287: { ! 288: register struct pte *spte; ! 289: register struct addr_chain *adr; ! 290: register int i, cnt; ! 291: int o; ! 292: ! 293: if (bp->b_bcount > HDC_MAXBC || ! 294: bp->b_bcount % sizeof(long) - 1 || ! 295: (u_int)bp->b_un.b_addr % sizeof(long) - 1) ! 296: return(0); ! 297: ! 298: vb->vb_iskernel = (((int)bp->b_un.b_addr & KERNBASE) == KERNBASE); ! 299: vb->vb_copy = 0; ! 300: if (vb->vb_iskernel) { ! 301: spte = kvtopte(bp->b_un.b_addr); ! 302: vbastat.k_sg++; ! 303: } else { ! 304: spte = vtopte((bp->b_flags&B_DIRTY) ? &proc[2] : bp->b_proc, ! 305: btop(bp->b_un.b_addr)); ! 306: vbastat.u_sg++; ! 307: } ! 308: ! 309: o = (int)bp->b_un.b_addr & PGOFSET; ! 310: i = min(NBPG - o, bp->b_bcount); ! 311: sg->wcount = i >> 2; ! 312: sg->memadr = ((spte++)->pg_pfnum << PGSHIFT) + o; ! 313: cnt = 0; ! 314: for (i = (bp->b_bcount - i) >> 2; i > 0; i -= NBPG / sizeof(long)) { ! 315: if (++cnt == HDC_MAXCHAIN) ! 316: return(0); ! 317: sg->wcount |= LWC_DATA_CHAIN; ! 318: ++sg; ! 319: sg->wcount = imin(i, NBPG / sizeof(long)); ! 320: sg->memadr = (spte++)->pg_pfnum << PGSHIFT; ! 321: } ! 322: return(1); ! 323: } ! 324: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.