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