xref: /csrg-svn/sys/vax/if/if_uba.c (revision 45801)
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 = &top;
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