1 /* if_uba.c 4.14 82/10/10 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/mbuf.h" 6 #include "../h/map.h" 7 #include "../h/pte.h" 8 #include "../h/buf.h" 9 #include "../h/cmap.h" 10 #include "../h/vmmac.h" 11 #include "../h/socket.h" 12 13 #include "../net/if.h" 14 15 #include "../vax/mtpr.h" 16 #include "../vaxif/if_uba.h" 17 #include "../vaxuba/ubareg.h" 18 #include "../vaxuba/ubavar.h" 19 20 /* 21 * Routines supporting UNIBUS network interfaces. 22 * 23 * TODO: 24 * Support interfaces using only one BDP statically. 25 */ 26 27 /* 28 * Init UNIBUS for interface on uban whose headers of size hlen are to 29 * end on a page boundary. We allocate a UNIBUS map register for the page 30 * with the header, and nmr more UNIBUS map registers for i/o on the adapter, 31 * doing this twice: once for reading and once for writing. We also 32 * allocate page frames in the mbuffer pool for these pages. 33 */ 34 if_ubainit(ifu, uban, hlen, nmr) 35 register struct ifuba *ifu; 36 int uban, hlen, nmr; 37 { 38 register caddr_t cp; 39 int i, ncl; 40 41 ncl = clrnd(nmr + CLSIZE) / CLSIZE; 42 if (ifu->ifu_r.ifrw_addr) 43 cp = ifu->ifu_r.ifrw_addr - (CLBYTES - hlen); 44 else { 45 cp = m_clalloc(2 * ncl, MPG_SPACE); 46 if (cp == 0) 47 return (0); 48 ifu->ifu_r.ifrw_addr = cp + CLBYTES - hlen; 49 ifu->ifu_w.ifrw_addr = ifu->ifu_r.ifrw_addr + ncl * CLBYTES; 50 ifu->ifu_hlen = hlen; 51 ifu->ifu_uban = uban; 52 ifu->ifu_uba = uba_hd[uban].uh_uba; 53 } 54 if (if_ubaalloc(ifu, &ifu->ifu_r, nmr) == 0) 55 goto bad; 56 if (if_ubaalloc(ifu, &ifu->ifu_w, nmr) == 0) 57 goto bad2; 58 for (i = 0; i < nmr; i++) 59 ifu->ifu_wmap[i] = ifu->ifu_w.ifrw_mr[i]; 60 ifu->ifu_xswapd = 0; 61 return (1); 62 bad2: 63 ubarelse(ifu->ifu_uban, &ifu->ifu_r.ifrw_info); 64 bad: 65 m_pgfree(cp, 2 * ncl); 66 ifu->ifu_r.ifrw_addr = 0; 67 return (0); 68 } 69 70 /* 71 * Setup either a ifrw structure by allocating UNIBUS map registers, 72 * possibly a buffered data path, and initializing the fields of 73 * the ifrw structure to minimize run-time overhead. 74 */ 75 static 76 if_ubaalloc(ifu, ifrw, nmr) 77 struct ifuba *ifu; 78 register struct ifrw *ifrw; 79 int nmr; 80 { 81 register int info; 82 83 info = 84 uballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->ifu_hlen, 85 ifu->ifu_flags); 86 if (info == 0) 87 return (0); 88 ifrw->ifrw_info = info; 89 ifrw->ifrw_bdp = UBAI_BDP(info); 90 ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT); 91 ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1]; 92 return (1); 93 } 94 95 /* 96 * Pull read data off a interface. 97 * Len is length of data, with local net header stripped. 98 * Off is non-zero if a trailer protocol was used, and 99 * gives the offset of the trailer information. 100 * We copy the trailer information and then all the normal 101 * data into mbufs. When full cluster sized units are present 102 * on the interface on cluster boundaries we can get them more 103 * easily by remapping, and take advantage of this here. 104 */ 105 struct mbuf * 106 if_rubaget(ifu, totlen, off0) 107 register struct ifuba *ifu; 108 int totlen, off0; 109 { 110 struct mbuf *top, **mp, *m; 111 int off = off0, len; 112 register caddr_t cp = ifu->ifu_r.ifrw_addr + ifu->ifu_hlen; 113 114 115 top = 0; 116 mp = ⊤ 117 while (totlen > 0) { 118 MGET(m, 0); 119 if (m == 0) 120 goto bad; 121 if (off) { 122 len = totlen - off; 123 cp = ifu->ifu_r.ifrw_addr + ifu->ifu_hlen + off; 124 } else 125 len = totlen; 126 if (len >= CLBYTES) { 127 struct mbuf *p; 128 struct pte *cpte, *ppte; 129 int x, *ip, i; 130 131 MCLGET(p, 1); 132 if (p == 0) 133 goto nopage; 134 len = m->m_len = CLBYTES; 135 m->m_off = (int)p - (int)m; 136 if (!claligned(cp)) 137 goto copy; 138 139 /* 140 * Switch pages mapped to UNIBUS with new page p, 141 * as quick form of copy. Remap UNIBUS and invalidate. 142 */ 143 cpte = &Mbmap[mtocl(cp)*CLSIZE]; 144 ppte = &Mbmap[mtocl(p)*CLSIZE]; 145 x = btop(cp - ifu->ifu_r.ifrw_addr); 146 ip = (int *)&ifu->ifu_r.ifrw_mr[x]; 147 for (i = 0; i < CLSIZE; i++) { 148 struct pte t; 149 t = *ppte; *ppte++ = *cpte; *cpte = t; 150 *ip++ = 151 cpte++->pg_pfnum|ifu->ifu_r.ifrw_proto; 152 mtpr(TBIS, cp); 153 cp += NBPG; 154 mtpr(TBIS, (caddr_t)p); 155 p += NBPG / sizeof (*p); 156 } 157 goto nocopy; 158 } 159 nopage: 160 m->m_len = MIN(MLEN, len); 161 m->m_off = MMINOFF; 162 copy: 163 bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len); 164 cp += m->m_len; 165 nocopy: 166 *mp = m; 167 mp = &m->m_next; 168 if (off) { 169 /* sort of an ALGOL-W style for statement... */ 170 off += m->m_len; 171 if (off == totlen) { 172 cp = ifu->ifu_r.ifrw_addr + ifu->ifu_hlen; 173 off = 0; 174 totlen = off0; 175 } 176 } else 177 totlen -= m->m_len; 178 } 179 return (top); 180 bad: 181 m_freem(top); 182 return (0); 183 } 184 185 /* 186 * Map a chain of mbufs onto a network interface 187 * in preparation for an i/o operation. 188 * The argument chain of mbufs includes the local network 189 * header which is copied to be in the mapped, aligned 190 * i/o space. 191 */ 192 if_wubaput(ifu, m) 193 register struct ifuba *ifu; 194 register struct mbuf *m; 195 { 196 register struct mbuf *mp; 197 register caddr_t cp, dp; 198 register int i; 199 int xswapd = 0; 200 int x, cc; 201 202 cp = ifu->ifu_w.ifrw_addr; 203 while (m) { 204 dp = mtod(m, char *); 205 if (claligned(cp) && claligned(dp) && m->m_len == CLBYTES) { 206 struct pte *pte; int *ip; 207 pte = &Mbmap[mtocl(dp)*CLSIZE]; 208 x = btop(cp - ifu->ifu_w.ifrw_addr); 209 ip = (int *)&ifu->ifu_w.ifrw_mr[x]; 210 for (i = 0; i < CLSIZE; i++) 211 *ip++ = 212 ifu->ifu_w.ifrw_proto | pte++->pg_pfnum; 213 xswapd |= 1 << (x>>(CLSHIFT-PGSHIFT)); 214 mp = m->m_next; 215 m->m_next = ifu->ifu_xtofree; 216 ifu->ifu_xtofree = m; 217 cp += m->m_len; 218 } else { 219 bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len); 220 cp += m->m_len; 221 MFREE(m, mp); 222 } 223 m = mp; 224 } 225 226 /* 227 * Xswapd is the set of clusters we just mapped out. Ifu->ifu_xswapd 228 * is the set of clusters mapped out from before. We compute 229 * the number of clusters involved in this operation in x. 230 * Clusters mapped out before and involved in this operation 231 * should be unmapped so original pages will be accessed by the device. 232 */ 233 cc = cp - ifu->ifu_w.ifrw_addr; 234 x = ((cc - ifu->ifu_hlen) + CLBYTES - 1) >> CLSHIFT; 235 ifu->ifu_xswapd &= ~xswapd; 236 xswapd &= ~ifu->ifu_xswapd; 237 while (i = ffs(ifu->ifu_xswapd)) { 238 i--; 239 if (i >= x) 240 break; 241 ifu->ifu_xswapd &= ~(1<<i); 242 i *= CLSIZE; 243 for (x = 0; x < CLSIZE; x++) { 244 ifu->ifu_w.ifrw_mr[i] = ifu->ifu_wmap[i]; 245 i++; 246 } 247 } 248 ifu->ifu_xswapd |= xswapd; 249 return (cc); 250 } 251