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