1 /* vba.c 1.7 87/04/06 */ 2 3 /* 4 * Tahoe VERSAbus adapator support routines. 5 */ 6 7 #include "../tahoe/mtpr.h" 8 #include "../tahoe/pte.h" 9 10 #include "param.h" 11 #include "buf.h" 12 #include "cmap.h" 13 #include "conf.h" 14 #include "dir.h" 15 #include "dk.h" 16 #include "map.h" 17 #include "systm.h" 18 #include "user.h" 19 #include "vmparam.h" 20 #include "vmmac.h" 21 #include "proc.h" 22 #include "syslog.h" 23 24 #include "../tahoevba/vbavar.h" 25 26 #define kvtopte(v) (&Sysmap[btop((int)(v) &~ KERNBASE)]) 27 28 /* 29 * Allocate private page map and intermediate buffer 30 * for a VERSAbus device, large enough for maximum transfer size. 31 * Intermediate buffer 32 * Make intermediate buffer uncacheable. 33 */ 34 vbainit(vb, xsize, flags) 35 register struct vb_buf *vb; 36 int xsize, flags; 37 { 38 register struct pte *pte; 39 register n; 40 41 vb->vb_flags = flags; 42 vbmapalloc(btoc(xsize) + 1, &vb->vb_map, &vb->vb_utl); 43 n = roundup(xsize, NBPG); 44 vb->vb_bufsize = n; 45 if (vb->vb_rawbuf == 0) 46 vb->vb_rawbuf = calloc(n); 47 if ((int)vb->vb_rawbuf & PGOFSET) 48 panic("vbinit pgoff"); 49 vb->vb_physbuf = vtoph((struct proc *)0, vb->vb_rawbuf); 50 if (flags & VB_20BIT) 51 vb->vb_maxphys = btoc(VB_MAXADDR20); 52 else if (flags & VB_24BIT) 53 vb->vb_maxphys = btoc(VB_MAXADDR24); 54 else 55 vb->vb_maxphys = btoc(VB_MAXADDR32); 56 if (btoc(vb->vb_physbuf + n) > vb->vb_maxphys) 57 panic("vbinit physbuf"); 58 59 /* 60 * Make raw buffer pages uncacheable. 61 */ 62 pte = kvtopte(vb->vb_rawbuf); 63 for (n = btoc(n); n--; pte++) 64 pte->pg_nc = 1; 65 mtpr(TBIA, 0); 66 } 67 68 /* 69 * Check a transfer to see whether it can be done directly 70 * to the destination buffer, or whether it must be copied. 71 * On Tahoe, the lack of a bus I/O map forces data to be copied 72 * to a physically-contiguous buffer whenever one of the following is true: 73 * 1) The data length is not a multiple of sector size. 74 * (The swapping code does this, unfortunately.) 75 * 2) The buffer is not physically contiguous and the controller 76 * does not support scatter-gather operations. 77 * 3) The physical address for I/O is higher than addressible 78 * by the device. 79 * This routine is called by the start routine. 80 * If copying is necessary, the intermediate buffer is mapped; 81 * if the operation is a write, the data is copied into the buffer. 82 * It returns the physical address of the first byte for DMA, to 83 * be presented to the controller. 84 */ 85 u_long 86 vbasetup(bp, vb, sectsize) 87 register struct buf *bp; 88 register struct vb_buf *vb; 89 int sectsize; 90 { 91 register struct pte *spte, *dpte; 92 register int p, i; 93 int npf, o, v; 94 95 o = (int)bp->b_un.b_addr & PGOFSET; 96 npf = btoc(bp->b_bcount + o); 97 vb->vb_iskernel = (((int)bp->b_un.b_addr & KERNBASE) == KERNBASE); 98 if (vb->vb_iskernel) 99 spte = kvtopte(bp->b_un.b_addr); 100 else 101 spte = vtopte((bp->b_flags&B_DIRTY) ? &proc[2] : bp->b_proc, 102 btop(bp->b_un.b_addr)); 103 if (bp->b_bcount % sectsize) 104 goto copy; 105 else if ((vb->vb_flags & VB_SCATTER) == 0 || 106 vb->vb_maxphys != VB_MAXADDR32) { 107 dpte = spte; 108 p = (dpte++)->pg_pfnum; 109 for (i = npf; --i > 0; dpte++) { 110 if ((v = dpte->pg_pfnum) != p + CLSIZE && 111 (vb->vb_flags & VB_SCATTER) == 0) 112 goto copy; 113 if (p >= vb->vb_maxphys) 114 goto copy; 115 p = v; 116 } 117 if (p >= vb->vb_maxphys) 118 goto copy; 119 } 120 vb->vb_copy = 0; 121 if (vb->vb_iskernel) 122 vbastat.k_raw++; 123 else 124 vbastat.u_raw++; 125 return ((spte->pg_pfnum << PGSHIFT) + o); 126 127 copy: 128 vb->vb_copy = 1; 129 if (bp->b_bcount > vb->vb_bufsize) 130 panic("vba xfer too large"); 131 if (vb->vb_iskernel) { 132 if ((bp->b_flags & B_READ) == 0) 133 bcopy(bp->b_un.b_addr, vb->vb_rawbuf, 134 (unsigned)bp->b_bcount); 135 vbastat.k_copy++; 136 } else { 137 dpte = vb->vb_map; 138 for (i = npf, p = (int)vb->vb_utl; i--; p += NBPG) { 139 *(int *)dpte++ = (spte++)->pg_pfnum | 140 PG_V | PG_KW | PG_N; 141 mtpr(TBIS, p); 142 } 143 if ((bp->b_flags & B_READ) == 0) 144 bcopy(vb->vb_utl + o, vb->vb_rawbuf, 145 (unsigned)bp->b_bcount); 146 vbastat.u_copy++; 147 } 148 return (vb->vb_physbuf); 149 } 150 151 /* 152 * Called by the driver's interrupt routine, after DMA is completed. 153 * If the operation was a read, copy data to final buffer if necessary 154 * or invalidate data cache for cacheable direct buffers. 155 * Similar to the vbastart routine, but in the reverse direction. 156 */ 157 vbadone(bp, vb) 158 register struct buf *bp; 159 register struct vb_buf *vb; 160 { 161 register npf; 162 register caddr_t v; 163 int o; 164 165 if (bp->b_flags & B_READ) { 166 o = (int)bp->b_un.b_addr & PGOFSET; 167 if (vb->vb_copy) { 168 if (vb->vb_iskernel) 169 bcopy(vb->vb_rawbuf, bp->b_un.b_addr, 170 (unsigned)(bp->b_bcount - bp->b_resid)); 171 else { 172 bcopy(vb->vb_rawbuf, vb->vb_utl + o, 173 (unsigned)(bp->b_bcount - bp->b_resid)); 174 dkeyinval(bp->b_proc); 175 } 176 } else { 177 if (vb->vb_iskernel) { 178 npf = btoc(bp->b_bcount + o); 179 for (v = bp->b_un.b_addr; npf--; v += NBPG) 180 mtpr(P1DC, (int)v); 181 } else 182 dkeyinval(bp->b_proc); 183 } 184 } 185 } 186 187 /* 188 * Set up a scatter-gather operation for SMD/E controller. 189 * This code belongs half-way between vd.c and this file. 190 */ 191 #include "vdreg.h" 192 193 vba_sgsetup(bp, vb, sg) 194 register struct buf *bp; 195 struct vb_buf *vb; 196 struct trsg *sg; 197 { 198 register struct pte *spte; 199 register struct addr_chain *adr; 200 register int npf, i; 201 int o; 202 203 o = (int)bp->b_un.b_addr & PGOFSET; 204 npf = btoc(bp->b_bcount + o); 205 vb->vb_iskernel = (((int)bp->b_un.b_addr & KERNBASE) == KERNBASE); 206 vb->vb_copy = 0; 207 if (vb->vb_iskernel) { 208 spte = kvtopte(bp->b_un.b_addr); 209 vbastat.k_sg++; 210 } else { 211 spte = vtopte((bp->b_flags&B_DIRTY) ? &proc[2] : bp->b_proc, 212 btop(bp->b_un.b_addr)); 213 vbastat.u_sg++; 214 } 215 216 i = min(NBPG - o, bp->b_bcount); 217 sg->start_addr.wcount = (i + 1) >> 1; 218 sg->start_addr.memadr = ((spte++)->pg_pfnum << PGSHIFT) + o; 219 i = bp->b_bcount - i; 220 if (i > VDMAXPAGES * NBPG) 221 panic("vba xfer too large"); 222 i = (i + 1) >> 1; 223 for (adr = sg->addr_chain; i > 0; adr++, i -= NBPG / 2) { 224 adr->nxt_addr = (spte++)->pg_pfnum << PGSHIFT; 225 adr->nxt_len = min(i, NBPG / 2); 226 } 227 adr->nxt_addr = 0; 228 adr++->nxt_len = 0; 229 return ((adr - sg->addr_chain) * sizeof(*adr) / sizeof(long)); 230 } 231