BSD 4_3_Net_2 release
[unix-history] / usr / src / sys / vax / if / if_uba.c
CommitLineData
da7c5cc6 1/*
5ec5a918 2 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
5f9369d6 3 * All rights reserved.
da7c5cc6 4 *
af359dea
C
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
5f9369d6 20 *
af359dea
C
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)if_uba.c 7.16 (Berkeley) 12/16/90
da7c5cc6 34 */
961945a8 35
b28b3a13
KB
36#include "sys/param.h"
37#include "sys/systm.h"
38#include "sys/malloc.h"
39#include "sys/mbuf.h"
40#include "sys/map.h"
41#include "sys/buf.h"
42#include "sys/cmap.h"
43#include "sys/vmmac.h"
44#include "sys/socket.h"
45#include "sys/syslog.h"
eaa60542 46
b28b3a13 47#include "net/if.h"
eaa60542 48
b28b3a13
KB
49#include "../include/pte.h"
50#include "../include/mtpr.h"
a6e960e7 51#include "if_uba.h"
b28b3a13
KB
52#include "../uba/ubareg.h"
53#include "../uba/ubavar.h"
0468e5fa
BJ
54
55/*
56 * Routines supporting UNIBUS network interfaces.
57 *
58 * TODO:
59 * Support interfaces using only one BDP statically.
60 */
61
62/*
63 * Init UNIBUS for interface on uban whose headers of size hlen are to
64 * end on a page boundary. We allocate a UNIBUS map register for the page
65 * with the header, and nmr more UNIBUS map registers for i/o on the adapter,
822a4f2c 66 * doing this once for each read and once for each write buffer. We also
0468e5fa
BJ
67 * allocate page frames in the mbuffer pool for these pages.
68 */
822a4f2c
MK
69if_ubaminit(ifu, uban, hlen, nmr, ifr, nr, ifw, nw)
70 register struct ifubinfo *ifu;
71 int uban, hlen, nmr, nr, nw;
72 register struct ifrw *ifr;
73 register struct ifxmt *ifw;
0468e5fa 74{
822a4f2c
MK
75 register caddr_t p;
76 caddr_t cp;
8e313c90 77 int i, nclbytes, off;
0468e5fa 78
e6822062 79 if (hlen)
5ec5a918 80 off = MCLBYTES - hlen;
e6822062
MK
81 else
82 off = 0;
5ec5a918 83 nclbytes = roundup(nmr * NBPG, MCLBYTES);
e6822062 84 if (hlen)
5ec5a918 85 nclbytes += MCLBYTES;
822a4f2c
MK
86 if (ifr[0].ifrw_addr)
87 cp = ifr[0].ifrw_addr - off;
176c481f 88 else {
ca67e7b4
C
89 cp = (caddr_t)malloc((u_long)((nr + nw) * nclbytes), M_DEVBUF,
90 M_NOWAIT);
176c481f
BJ
91 if (cp == 0)
92 return (0);
822a4f2c
MK
93 p = cp;
94 for (i = 0; i < nr; i++) {
95 ifr[i].ifrw_addr = p + off;
8e313c90 96 p += nclbytes;
822a4f2c
MK
97 }
98 for (i = 0; i < nw; i++) {
99 ifw[i].ifw_base = p;
100 ifw[i].ifw_addr = p + off;
8e313c90 101 p += nclbytes;
822a4f2c
MK
102 }
103 ifu->iff_hlen = hlen;
104 ifu->iff_uban = uban;
105 ifu->iff_uba = uba_hd[uban].uh_uba;
ca67e7b4 106 ifu->iff_ubamr = uba_hd[uban].uh_mr;
822a4f2c
MK
107 }
108 for (i = 0; i < nr; i++)
109 if (if_ubaalloc(ifu, &ifr[i], nmr) == 0) {
110 nr = i;
111 nw = 0;
112 goto bad;
113 }
114 for (i = 0; i < nw; i++)
115 if (if_ubaalloc(ifu, &ifw[i].ifrw, nmr) == 0) {
116 nw = i;
117 goto bad;
118 }
119 while (--nw >= 0) {
120 for (i = 0; i < nmr; i++)
121 ifw[nw].ifw_wmap[i] = ifw[nw].ifw_mr[i];
122 ifw[nw].ifw_xswapd = 0;
3ab9cb88 123 ifw[nw].ifw_flags = IFRW_W;
92441f6e 124 ifw[nw].ifw_nmr = nmr;
176c481f 125 }
0468e5fa 126 return (1);
0468e5fa 127bad:
822a4f2c 128 while (--nw >= 0)
2f6055c3 129 ubarelse(ifu->iff_uban, &ifw[nw].ifw_info);
822a4f2c 130 while (--nr >= 0)
2f6055c3 131 ubarelse(ifu->iff_uban, &ifr[nr].ifrw_info);
8e313c90 132 free(cp, M_DEVBUF);
822a4f2c 133 ifr[0].ifrw_addr = 0;
0468e5fa
BJ
134 return (0);
135}
136
137/*
822a4f2c 138 * Setup an ifrw structure by allocating UNIBUS map registers,
d6391cba
SL
139 * possibly a buffered data path, and initializing the fields of
140 * the ifrw structure to minimize run-time overhead.
0468e5fa
BJ
141 */
142static
b454c3ea 143if_ubaalloc(ifu, ifrw, nmr)
822a4f2c 144 struct ifubinfo *ifu;
0468e5fa 145 register struct ifrw *ifrw;
b454c3ea 146 int nmr;
0468e5fa
BJ
147{
148 register int info;
149
150 info =
822a4f2c
MK
151 uballoc(ifu->iff_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->iff_hlen,
152 ifu->iff_flags);
0468e5fa 153 if (info == 0)
8a13b737 154 return (0);
0468e5fa
BJ
155 ifrw->ifrw_info = info;
156 ifrw->ifrw_bdp = UBAI_BDP(info);
97da2a42 157 ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT);
ca67e7b4 158 ifrw->ifrw_mr = &ifu->iff_ubamr[UBAI_MR(info) + (ifu->iff_hlen? 1 : 0)];
8a13b737 159 return (1);
0468e5fa
BJ
160}
161
162/*
f1b2fa5b 163 * Pull read data off a interface.
193bee4c 164 * Totlen is length of data, with local net header stripped.
f1b2fa5b
BJ
165 * Off is non-zero if a trailer protocol was used, and
166 * gives the offset of the trailer information.
193bee4c 167 * We copy the header from the trailer and then all the normal
f1b2fa5b
BJ
168 * data into mbufs. When full cluster sized units are present
169 * on the interface on cluster boundaries we can get them more
170 * easily by remapping, and take advantage of this here.
193bee4c 171 * Save a pointer to the interface structure and the total length,
25506232 172 * so that protocols can determine where incoming packets arrived.
3ab9cb88
MK
173 * Note: we may be called to receive from a transmit buffer by some
174 * devices. In that case, we must force normal mapping of the buffer,
175 * so that the correct data will appear (only unibus maps are
176 * changed when remapping the transmit buffers).
0468e5fa
BJ
177 */
178struct mbuf *
193bee4c 179if_ubaget(ifu, ifr, totlen, off, ifp)
822a4f2c
MK
180 struct ifubinfo *ifu;
181 register struct ifrw *ifr;
193bee4c
MK
182 register int totlen;
183 int off;
25506232 184 struct ifnet *ifp;
0468e5fa 185{
822a4f2c
MK
186 struct mbuf *top, **mp;
187 register struct mbuf *m;
2fdf5fa3 188 register caddr_t cp = ifr->ifrw_addr + ifu->iff_hlen, pp;
193bee4c
MK
189 register int len;
190 caddr_t epkt = cp + totlen;
0468e5fa 191
f1b2fa5b
BJ
192 top = 0;
193 mp = &top;
193bee4c
MK
194 /*
195 * Skip the trailer header (type and trailer length).
196 */
197 if (off) {
198 off += 2 * sizeof(u_short);
199 totlen -= 2 * sizeof(u_short);
200 cp += off;
201 }
202 MGETHDR(m, M_DONTWAIT, MT_DATA);
203 if (m == 0)
204 return ((struct mbuf *)NULL);
205 m->m_pkthdr.rcvif = ifp;
206 m->m_pkthdr.len = totlen;
207 m->m_len = MHLEN;
208
3ab9cb88
MK
209 if (ifr->ifrw_flags & IFRW_W)
210 rcv_xmtbuf((struct ifxmt *)ifr);
193bee4c 211
f1b2fa5b 212 while (totlen > 0) {
193bee4c 213 if (top) {
5ec5a918 214 MGET(m, M_DONTWAIT, MT_DATA);
193bee4c
MK
215 if (m == 0) {
216 m_freem(top);
217 top = 0;
218 goto out;
219 }
5ec5a918 220 m->m_len = MLEN;
193bee4c
MK
221 }
222 len = min(totlen, epkt - cp);
5ec5a918 223 if (len >= MINCLSIZE) {
0468e5fa 224 struct pte *cpte, *ppte;
b454c3ea 225 int x, *ip, i;
0468e5fa 226
5ec5a918
MK
227 MCLGET(m, M_DONTWAIT);
228 if ((m->m_flags & M_EXT) == 0)
25506232 229 goto nopage;
193bee4c 230 len = min(len, MCLBYTES);
5ec5a918 231 m->m_len = len;
b454c3ea 232 if (!claligned(cp))
0468e5fa
BJ
233 goto copy;
234
235 /*
2fdf5fa3 236 * Switch pages mapped to UNIBUS with new page pp,
b454c3ea 237 * as quick form of copy. Remap UNIBUS and invalidate.
0468e5fa 238 */
2fdf5fa3 239 pp = mtod(m, char *);
1ae120d5
MK
240 cpte = kvtopte(cp);
241 ppte = kvtopte(pp);
822a4f2c
MK
242 x = btop(cp - ifr->ifrw_addr);
243 ip = (int *)&ifr->ifrw_mr[x];
5ec5a918 244 for (i = 0; i < MCLBYTES/NBPG; i++) {
0468e5fa 245 struct pte t;
b454c3ea 246 t = *ppte; *ppte++ = *cpte; *cpte = t;
1ae120d5 247 *ip++ = cpte++->pg_pfnum|ifr->ifrw_proto;
c63e9630 248 mtpr(TBIS, cp);
8a13b737 249 cp += NBPG;
2fdf5fa3
MK
250 mtpr(TBIS, (caddr_t)pp);
251 pp += NBPG;
0468e5fa
BJ
252 }
253 goto nocopy;
254 }
255nopage:
5ec5a918 256 if (len < m->m_len) {
25506232 257 /*
5ec5a918 258 * Place initial small packet/header at end of mbuf.
25506232 259 */
5ec5a918
MK
260 if (top == 0 && len + max_linkhdr <= m->m_len)
261 m->m_data += max_linkhdr;
262 m->m_len = len;
263 } else
264 len = m->m_len;
0468e5fa 265copy:
5ec5a918
MK
266 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
267 cp += len;
0468e5fa 268nocopy:
f1b2fa5b
BJ
269 *mp = m;
270 mp = &m->m_next;
193bee4c
MK
271 totlen -= len;
272 if (cp == epkt)
273 cp = ifr->ifrw_addr + ifu->iff_hlen;
4f02060d 274 }
3ab9cb88
MK
275out:
276 if (ifr->ifrw_flags & IFRW_W)
277 restor_xmtbuf((struct ifxmt *)ifr);
0468e5fa 278 return (top);
3ab9cb88
MK
279}
280
281/*
282 * Change the mapping on a transmit buffer so that if_ubaget may
283 * receive from that buffer. Copy data from any pages mapped to Unibus
284 * into the pages mapped to normal kernel virtual memory, so that
285 * they can be accessed and swapped as usual. We take advantage
286 * of the fact that clusters are placed on the xtofree list
287 * in inverse order, finding the last one.
288 */
289static
290rcv_xmtbuf(ifw)
291 register struct ifxmt *ifw;
292{
293 register struct mbuf *m;
294 struct mbuf **mprev;
295 register i;
3ab9cb88
MK
296 char *cp;
297
8011f5df 298 while (i = ffs((long)ifw->ifw_xswapd)) {
5ec5a918 299 cp = ifw->ifw_base + i * MCLBYTES;
3ab9cb88
MK
300 i--;
301 ifw->ifw_xswapd &= ~(1<<i);
3ab9cb88
MK
302 mprev = &ifw->ifw_xtofree;
303 for (m = ifw->ifw_xtofree; m && m->m_next; m = m->m_next)
304 mprev = &m->m_next;
305 if (m == NULL)
44477143 306 break;
5ec5a918 307 bcopy(mtod(m, caddr_t), cp, MCLBYTES);
8011f5df 308 (void) m_free(m);
3ab9cb88 309 *mprev = NULL;
3ab9cb88 310 }
44477143
MK
311 ifw->ifw_xswapd = 0;
312 for (i = 0; i < ifw->ifw_nmr; i++)
313 ifw->ifw_mr[i] = ifw->ifw_wmap[i];
3ab9cb88
MK
314}
315
316/*
317 * Put a transmit buffer back together after doing an if_ubaget on it,
318 * which may have swapped pages.
319 */
320static
321restor_xmtbuf(ifw)
322 register struct ifxmt *ifw;
323{
324 register i;
325
92441f6e 326 for (i = 0; i < ifw->ifw_nmr; i++)
3ab9cb88 327 ifw->ifw_wmap[i] = ifw->ifw_mr[i];
0468e5fa
BJ
328}
329
330/*
331 * Map a chain of mbufs onto a network interface
332 * in preparation for an i/o operation.
333 * The argument chain of mbufs includes the local network
334 * header which is copied to be in the mapped, aligned
335 * i/o space.
336 */
822a4f2c
MK
337if_ubaput(ifu, ifw, m)
338 struct ifubinfo *ifu;
339 register struct ifxmt *ifw;
0468e5fa
BJ
340 register struct mbuf *m;
341{
342 register struct mbuf *mp;
343 register caddr_t cp, dp;
344 register int i;
b454c3ea 345 int xswapd = 0;
e6822062 346 int x, cc, t;
0468e5fa 347
822a4f2c 348 cp = ifw->ifw_addr;
0468e5fa
BJ
349 while (m) {
350 dp = mtod(m, char *);
25506232 351 if (claligned(cp) && claligned(dp) &&
5ec5a918 352 (m->m_len == MCLBYTES || m->m_next == (struct mbuf *)0)) {
1ae120d5
MK
353 struct pte *pte;
354 int *ip;
355
356 pte = kvtopte(dp);
822a4f2c
MK
357 x = btop(cp - ifw->ifw_addr);
358 ip = (int *)&ifw->ifw_mr[x];
5ec5a918 359 for (i = 0; i < MCLBYTES/NBPG; i++)
1ae120d5 360 *ip++ = ifw->ifw_proto | pte++->pg_pfnum;
5ec5a918 361 xswapd |= 1 << (x>>(MCLSHIFT-PGSHIFT));
b454c3ea 362 mp = m->m_next;
822a4f2c
MK
363 m->m_next = ifw->ifw_xtofree;
364 ifw->ifw_xtofree = m;
b454c3ea
BJ
365 cp += m->m_len;
366 } else {
0468e5fa 367 bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
b454c3ea
BJ
368 cp += m->m_len;
369 MFREE(m, mp);
370 }
0468e5fa
BJ
371 m = mp;
372 }
b454c3ea
BJ
373
374 /*
822a4f2c 375 * Xswapd is the set of clusters we just mapped out. Ifu->iff_xswapd
b454c3ea
BJ
376 * is the set of clusters mapped out from before. We compute
377 * the number of clusters involved in this operation in x.
378 * Clusters mapped out before and involved in this operation
379 * should be unmapped so original pages will be accessed by the device.
380 */
822a4f2c 381 cc = cp - ifw->ifw_addr;
5ec5a918 382 x = ((cc - ifu->iff_hlen) + MCLBYTES - 1) >> MCLSHIFT;
822a4f2c 383 ifw->ifw_xswapd &= ~xswapd;
8011f5df 384 while (i = ffs((long)ifw->ifw_xswapd)) {
97da2a42
BJ
385 i--;
386 if (i >= x)
387 break;
822a4f2c 388 ifw->ifw_xswapd &= ~(1<<i);
5ec5a918
MK
389 i *= MCLBYTES/NBPG;
390 for (t = 0; t < MCLBYTES/NBPG; t++) {
822a4f2c 391 ifw->ifw_mr[i] = ifw->ifw_wmap[i];
97da2a42 392 i++;
0468e5fa 393 }
97da2a42 394 }
822a4f2c 395 ifw->ifw_xswapd |= xswapd;
b454c3ea 396 return (cc);
0468e5fa 397}