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