123303Smckusick /*
237476Ssklower * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
335327Sbostic * All rights reserved.
423303Smckusick *
544563Sbostic * %sccs.include.redist.c%
635327Sbostic *
7*45801Sbostic * @(#)if_uba.c 7.16 (Berkeley) 12/16/90
823303Smckusick */
95078Swnj
10*45801Sbostic #include "sys/param.h"
11*45801Sbostic #include "sys/systm.h"
12*45801Sbostic #include "sys/malloc.h"
13*45801Sbostic #include "sys/mbuf.h"
14*45801Sbostic #include "sys/map.h"
15*45801Sbostic #include "sys/buf.h"
16*45801Sbostic #include "sys/cmap.h"
17*45801Sbostic #include "sys/vmmac.h"
18*45801Sbostic #include "sys/socket.h"
19*45801Sbostic #include "sys/syslog.h"
208464Sroot
21*45801Sbostic #include "net/if.h"
228464Sroot
23*45801Sbostic #include "../include/pte.h"
24*45801Sbostic #include "../include/mtpr.h"
2517117Sbloom #include "if_uba.h"
26*45801Sbostic #include "../uba/ubareg.h"
27*45801Sbostic #include "../uba/ubavar.h"
285078Swnj
295078Swnj /*
305078Swnj * Routines supporting UNIBUS network interfaces.
315078Swnj *
325078Swnj * TODO:
335078Swnj * Support interfaces using only one BDP statically.
345078Swnj */
355078Swnj
365078Swnj /*
375078Swnj * Init UNIBUS for interface on uban whose headers of size hlen are to
385078Swnj * end on a page boundary. We allocate a UNIBUS map register for the page
395078Swnj * with the header, and nmr more UNIBUS map registers for i/o on the adapter,
4024794Skarels * doing this once for each read and once for each write buffer. We also
415078Swnj * allocate page frames in the mbuffer pool for these pages.
425078Swnj */
if_ubaminit(ifu,uban,hlen,nmr,ifr,nr,ifw,nw)4324794Skarels if_ubaminit(ifu, uban, hlen, nmr, ifr, nr, ifw, nw)
4424794Skarels register struct ifubinfo *ifu;
4524794Skarels int uban, hlen, nmr, nr, nw;
4624794Skarels register struct ifrw *ifr;
4724794Skarels register struct ifxmt *ifw;
485078Swnj {
4924794Skarels register caddr_t p;
5024794Skarels caddr_t cp;
5137476Ssklower int i, nclbytes, off;
525078Swnj
5321781Skarels if (hlen)
5437476Ssklower off = MCLBYTES - hlen;
5521781Skarels else
5621781Skarels off = 0;
5737476Ssklower nclbytes = roundup(nmr * NBPG, MCLBYTES);
5821781Skarels if (hlen)
5937476Ssklower nclbytes += MCLBYTES;
6024794Skarels if (ifr[0].ifrw_addr)
6124794Skarels cp = ifr[0].ifrw_addr - off;
626866Swnj else {
6337476Ssklower cp = (caddr_t)malloc((u_long)((nr + nw) * nclbytes), M_DEVBUF,
6437476Ssklower M_NOWAIT);
656866Swnj if (cp == 0)
666866Swnj return (0);
6724794Skarels p = cp;
6824794Skarels for (i = 0; i < nr; i++) {
6924794Skarels ifr[i].ifrw_addr = p + off;
7037476Ssklower p += nclbytes;
7124794Skarels }
7224794Skarels for (i = 0; i < nw; i++) {
7324794Skarels ifw[i].ifw_base = p;
7424794Skarels ifw[i].ifw_addr = p + off;
7537476Ssklower p += nclbytes;
7624794Skarels }
7724794Skarels ifu->iff_hlen = hlen;
7824794Skarels ifu->iff_uban = uban;
7924794Skarels ifu->iff_uba = uba_hd[uban].uh_uba;
8037476Ssklower ifu->iff_ubamr = uba_hd[uban].uh_mr;
816866Swnj }
8224794Skarels for (i = 0; i < nr; i++)
8324794Skarels if (if_ubaalloc(ifu, &ifr[i], nmr) == 0) {
8424794Skarels nr = i;
8524794Skarels nw = 0;
8624794Skarels goto bad;
8724794Skarels }
8824794Skarels for (i = 0; i < nw; i++)
8924794Skarels if (if_ubaalloc(ifu, &ifw[i].ifrw, nmr) == 0) {
9024794Skarels nw = i;
9124794Skarels goto bad;
9224794Skarels }
9324794Skarels while (--nw >= 0) {
9424794Skarels for (i = 0; i < nmr; i++)
9524794Skarels ifw[nw].ifw_wmap[i] = ifw[nw].ifw_mr[i];
9624794Skarels ifw[nw].ifw_xswapd = 0;
9725416Skarels ifw[nw].ifw_flags = IFRW_W;
9825624Skarels ifw[nw].ifw_nmr = nmr;
9924794Skarels }
1005078Swnj return (1);
1015078Swnj bad:
10224794Skarels while (--nw >= 0)
10331021Skarels ubarelse(ifu->iff_uban, &ifw[nw].ifw_info);
10424794Skarels while (--nr >= 0)
10531021Skarels ubarelse(ifu->iff_uban, &ifr[nr].ifrw_info);
10637476Ssklower free(cp, M_DEVBUF);
10724794Skarels ifr[0].ifrw_addr = 0;
1085078Swnj return (0);
1095078Swnj }
1105078Swnj
1115078Swnj /*
11224794Skarels * Setup an ifrw structure by allocating UNIBUS map registers,
1135688Ssam * possibly a buffered data path, and initializing the fields of
1145688Ssam * the ifrw structure to minimize run-time overhead.
1155078Swnj */
1165078Swnj static
1175172Swnj if_ubaalloc(ifu, ifrw, nmr)
11824794Skarels struct ifubinfo *ifu;
1195078Swnj register struct ifrw *ifrw;
1205172Swnj int nmr;
1215078Swnj {
1225078Swnj register int info;
1235078Swnj
1245078Swnj info =
12524794Skarels uballoc(ifu->iff_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->iff_hlen,
12624794Skarels ifu->iff_flags);
1275078Swnj if (info == 0)
1285084Swnj return (0);
1295078Swnj ifrw->ifrw_info = info;
1305078Swnj ifrw->ifrw_bdp = UBAI_BDP(info);
1315215Swnj ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT);
13237476Ssklower ifrw->ifrw_mr = &ifu->iff_ubamr[UBAI_MR(info) + (ifu->iff_hlen? 1 : 0)];
1335084Swnj return (1);
1345078Swnj }
1355078Swnj
1365078Swnj /*
1375106Swnj * Pull read data off a interface.
13838982Skarels * Totlen is length of data, with local net header stripped.
1395106Swnj * Off is non-zero if a trailer protocol was used, and
1405106Swnj * gives the offset of the trailer information.
14138982Skarels * We copy the header from the trailer and then all the normal
1425106Swnj * data into mbufs. When full cluster sized units are present
1435106Swnj * on the interface on cluster boundaries we can get them more
1445106Swnj * easily by remapping, and take advantage of this here.
14538982Skarels * Save a pointer to the interface structure and the total length,
14624507Skarels * so that protocols can determine where incoming packets arrived.
14725416Skarels * Note: we may be called to receive from a transmit buffer by some
14825416Skarels * devices. In that case, we must force normal mapping of the buffer,
14925416Skarels * so that the correct data will appear (only unibus maps are
15025416Skarels * changed when remapping the transmit buffers).
1515078Swnj */
1525078Swnj struct mbuf *
if_ubaget(ifu,ifr,totlen,off,ifp)15338982Skarels if_ubaget(ifu, ifr, totlen, off, ifp)
15424794Skarels struct ifubinfo *ifu;
15524794Skarels register struct ifrw *ifr;
15638982Skarels register int totlen;
15738982Skarels int off;
15824507Skarels struct ifnet *ifp;
1595078Swnj {
16024794Skarels struct mbuf *top, **mp;
16124794Skarels register struct mbuf *m;
16226287Skarels register caddr_t cp = ifr->ifrw_addr + ifu->iff_hlen, pp;
16338982Skarels register int len;
16438982Skarels caddr_t epkt = cp + totlen;
1655078Swnj
1665106Swnj top = 0;
1675106Swnj mp = ⊤
16838982Skarels /*
16938982Skarels * Skip the trailer header (type and trailer length).
17038982Skarels */
17138982Skarels if (off) {
17238982Skarels off += 2 * sizeof(u_short);
17338982Skarels totlen -= 2 * sizeof(u_short);
17438982Skarels cp += off;
17538982Skarels }
17638982Skarels MGETHDR(m, M_DONTWAIT, MT_DATA);
17738982Skarels if (m == 0)
17838982Skarels return ((struct mbuf *)NULL);
17938982Skarels m->m_pkthdr.rcvif = ifp;
18038982Skarels m->m_pkthdr.len = totlen;
18138982Skarels m->m_len = MHLEN;
18238982Skarels
18325416Skarels if (ifr->ifrw_flags & IFRW_W)
18425416Skarels rcv_xmtbuf((struct ifxmt *)ifr);
18538982Skarels
1865106Swnj while (totlen > 0) {
18738982Skarels if (top) {
18837476Ssklower MGET(m, M_DONTWAIT, MT_DATA);
18938982Skarels if (m == 0) {
19038982Skarels m_freem(top);
19138982Skarels top = 0;
19238982Skarels goto out;
19338982Skarels }
19438982Skarels m->m_len = MLEN;
19537476Ssklower }
19638982Skarels len = min(totlen, epkt - cp);
19737476Ssklower if (len >= MINCLSIZE) {
1985078Swnj struct pte *cpte, *ppte;
1995172Swnj int x, *ip, i;
2005078Swnj
20137476Ssklower MCLGET(m, M_DONTWAIT);
20237476Ssklower if ((m->m_flags & M_EXT) == 0)
20324507Skarels goto nopage;
20438982Skarels len = min(len, MCLBYTES);
20537476Ssklower m->m_len = len;
2065172Swnj if (!claligned(cp))
2075078Swnj goto copy;
2085078Swnj
2095078Swnj /*
21026287Skarels * Switch pages mapped to UNIBUS with new page pp,
2115172Swnj * as quick form of copy. Remap UNIBUS and invalidate.
2125078Swnj */
21326287Skarels pp = mtod(m, char *);
21437476Ssklower cpte = kvtopte(cp);
21537476Ssklower ppte = kvtopte(pp);
21624794Skarels x = btop(cp - ifr->ifrw_addr);
21724794Skarels ip = (int *)&ifr->ifrw_mr[x];
21837476Ssklower for (i = 0; i < MCLBYTES/NBPG; i++) {
2195078Swnj struct pte t;
2205172Swnj t = *ppte; *ppte++ = *cpte; *cpte = t;
22137476Ssklower *ip++ = cpte++->pg_pfnum|ifr->ifrw_proto;
22239104Skarels mtpr(TBIS, cp);
2235084Swnj cp += NBPG;
22426287Skarels mtpr(TBIS, (caddr_t)pp);
22526287Skarels pp += NBPG;
2265078Swnj }
2275078Swnj goto nocopy;
2285078Swnj }
2295078Swnj nopage:
23037476Ssklower if (len < m->m_len) {
23124507Skarels /*
23237476Ssklower * Place initial small packet/header at end of mbuf.
23324507Skarels */
23437476Ssklower if (top == 0 && len + max_linkhdr <= m->m_len)
23537476Ssklower m->m_data += max_linkhdr;
23637476Ssklower m->m_len = len;
23737476Ssklower } else
23837476Ssklower len = m->m_len;
2395078Swnj copy:
24037476Ssklower bcopy(cp, mtod(m, caddr_t), (unsigned)len);
24137476Ssklower cp += len;
2425078Swnj nocopy:
2435106Swnj *mp = m;
2445106Swnj mp = &m->m_next;
24538982Skarels totlen -= len;
24638982Skarels if (cp == epkt)
24738982Skarels cp = ifr->ifrw_addr + ifu->iff_hlen;
2485078Swnj }
24925416Skarels out:
25025416Skarels if (ifr->ifrw_flags & IFRW_W)
25125416Skarels restor_xmtbuf((struct ifxmt *)ifr);
2525078Swnj return (top);
2535078Swnj }
2545078Swnj
2555078Swnj /*
25625416Skarels * Change the mapping on a transmit buffer so that if_ubaget may
25725416Skarels * receive from that buffer. Copy data from any pages mapped to Unibus
25825416Skarels * into the pages mapped to normal kernel virtual memory, so that
25925416Skarels * they can be accessed and swapped as usual. We take advantage
26025416Skarels * of the fact that clusters are placed on the xtofree list
26125416Skarels * in inverse order, finding the last one.
26225416Skarels */
26325416Skarels static
rcv_xmtbuf(ifw)26425416Skarels rcv_xmtbuf(ifw)
26525416Skarels register struct ifxmt *ifw;
26625416Skarels {
26725416Skarels register struct mbuf *m;
26825416Skarels struct mbuf **mprev;
26925416Skarels register i;
27025416Skarels char *cp;
27125416Skarels
27226393Skarels while (i = ffs((long)ifw->ifw_xswapd)) {
27337476Ssklower cp = ifw->ifw_base + i * MCLBYTES;
27425416Skarels i--;
27525416Skarels ifw->ifw_xswapd &= ~(1<<i);
27625416Skarels mprev = &ifw->ifw_xtofree;
27725416Skarels for (m = ifw->ifw_xtofree; m && m->m_next; m = m->m_next)
27825416Skarels mprev = &m->m_next;
27925416Skarels if (m == NULL)
28030603Skarels break;
28137476Ssklower bcopy(mtod(m, caddr_t), cp, MCLBYTES);
28226393Skarels (void) m_free(m);
28325416Skarels *mprev = NULL;
28425416Skarels }
28530603Skarels ifw->ifw_xswapd = 0;
28630603Skarels for (i = 0; i < ifw->ifw_nmr; i++)
28730603Skarels ifw->ifw_mr[i] = ifw->ifw_wmap[i];
28825416Skarels }
28925416Skarels
29025416Skarels /*
29125416Skarels * Put a transmit buffer back together after doing an if_ubaget on it,
29225416Skarels * which may have swapped pages.
29325416Skarels */
29425416Skarels static
restor_xmtbuf(ifw)29525416Skarels restor_xmtbuf(ifw)
29625416Skarels register struct ifxmt *ifw;
29725416Skarels {
29825416Skarels register i;
29925416Skarels
30025624Skarels for (i = 0; i < ifw->ifw_nmr; i++)
30125416Skarels ifw->ifw_wmap[i] = ifw->ifw_mr[i];
30225416Skarels }
30325416Skarels
30425416Skarels /*
3055078Swnj * Map a chain of mbufs onto a network interface
3065078Swnj * in preparation for an i/o operation.
3075078Swnj * The argument chain of mbufs includes the local network
3085078Swnj * header which is copied to be in the mapped, aligned
3095078Swnj * i/o space.
3105078Swnj */
31124794Skarels if_ubaput(ifu, ifw, m)
31224794Skarels struct ifubinfo *ifu;
31324794Skarels register struct ifxmt *ifw;
3145078Swnj register struct mbuf *m;
3155078Swnj {
3165078Swnj register struct mbuf *mp;
3175078Swnj register caddr_t cp, dp;
3185078Swnj register int i;
3195172Swnj int xswapd = 0;
32021781Skarels int x, cc, t;
3215078Swnj
32224794Skarels cp = ifw->ifw_addr;
3235078Swnj while (m) {
3245078Swnj dp = mtod(m, char *);
32524507Skarels if (claligned(cp) && claligned(dp) &&
32637476Ssklower (m->m_len == MCLBYTES || m->m_next == (struct mbuf *)0)) {
32737476Ssklower struct pte *pte;
32837476Ssklower int *ip;
32937476Ssklower
33037476Ssklower pte = kvtopte(dp);
33124794Skarels x = btop(cp - ifw->ifw_addr);
33224794Skarels ip = (int *)&ifw->ifw_mr[x];
33337476Ssklower for (i = 0; i < MCLBYTES/NBPG; i++)
33437476Ssklower *ip++ = ifw->ifw_proto | pte++->pg_pfnum;
33537476Ssklower xswapd |= 1 << (x>>(MCLSHIFT-PGSHIFT));
3365172Swnj mp = m->m_next;
33724794Skarels m->m_next = ifw->ifw_xtofree;
33824794Skarels ifw->ifw_xtofree = m;
3395172Swnj cp += m->m_len;
3405172Swnj } else {
3415078Swnj bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
3425172Swnj cp += m->m_len;
3435172Swnj MFREE(m, mp);
3445172Swnj }
3455078Swnj m = mp;
3465078Swnj }
3475172Swnj
3485172Swnj /*
34924794Skarels * Xswapd is the set of clusters we just mapped out. Ifu->iff_xswapd
3505172Swnj * is the set of clusters mapped out from before. We compute
3515172Swnj * the number of clusters involved in this operation in x.
3525172Swnj * Clusters mapped out before and involved in this operation
3535172Swnj * should be unmapped so original pages will be accessed by the device.
3545172Swnj */
35524794Skarels cc = cp - ifw->ifw_addr;
35637476Ssklower x = ((cc - ifu->iff_hlen) + MCLBYTES - 1) >> MCLSHIFT;
35724794Skarels ifw->ifw_xswapd &= ~xswapd;
35826393Skarels while (i = ffs((long)ifw->ifw_xswapd)) {
3595215Swnj i--;
3605215Swnj if (i >= x)
3615215Swnj break;
36224794Skarels ifw->ifw_xswapd &= ~(1<<i);
36337476Ssklower i *= MCLBYTES/NBPG;
36437476Ssklower for (t = 0; t < MCLBYTES/NBPG; t++) {
36524794Skarels ifw->ifw_mr[i] = ifw->ifw_wmap[i];
3665215Swnj i++;
3675078Swnj }
3685215Swnj }
36924794Skarels ifw->ifw_xswapd |= xswapd;
3705172Swnj return (cc);
3715078Swnj }
372