2.11BSD/sys/pdpif/if_uba.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1986 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 *
 *	@(#)if_uba.c	1.2 (2.11BSD GTE) 4/3/93
 *
 *	2.11BSD - uballoc and ubmalloc calling conventions changed.
 *		  ubmalloc now only performs address computation, the
 *		  necessary UMRs are allocated at network startup.
 *		  sms@wlv.imsd.contel.com - 9/8/90
 */

#include "param.h"
#include "../machine/seg.h"

#include "systm.h"
#include "domain.h"
#include "protosw.h"
#include "mbuf.h"
#include "buf.h"
#include "pdpuba/ubavar.h"
#include "map.h"
#include "uba.h"
#include "socket.h"
#include "netinet/in.h"
#include "netinet/in_systm.h"
#include "net/if.h"
#include "pdpif/if_uba.h"

/*
 * Routines supporting UNIBUS network interfaces.
 */

if_ubainit(ifu, uban, hlen, nmr)
	register struct ifuba *ifu;
	int uban, hlen, nmr;		/* nmr in 64 byte clicks */
{
	if (ifu->ifu_r.ifrw_click)
		return(1);
	nmr = ctob(nmr);		/* convert clicks back to bytes */
	ifu->ifu_r.ifrw_click = m_ioget(nmr+hlen);
	ifu->ifu_w.ifrw_click = m_ioget(nmr+hlen);
	if (ifu->ifu_r.ifrw_click == 0 || ifu->ifu_w.ifrw_click == 0) {
		ifu->ifu_r.ifrw_click = ifu->ifu_w.ifrw_click = 0;
		return(0);
	}
	ifu->ifu_r.ifrw_info = ubmalloc(ifu->ifu_r.ifrw_click);
	ifu->ifu_w.ifrw_info = ubmalloc(ifu->ifu_w.ifrw_click);
	ifu->ifu_hlen = hlen;
	return(1);
}

/*
 * Pull read data off a interface.
 * Len is length of data, with local net header stripped.
 * Off is non-zero if a trailer protocol was used, and
 * gives the offset of the trailer information.
 * We copy the trailer information and then all the normal
 * data into mbufs.
 */
struct mbuf *
if_rubaget(ifu, totlen, off0, ifp)
	register struct ifuba *ifu;
	int totlen, off0;
	struct ifnet *ifp;
{
	register caddr_t cp = (caddr_t)ifu->ifu_hlen;
	register struct mbuf *m;
	struct mbuf *top, **mp;
	int click = ifu->ifu_r.ifrw_click;
	int off = off0, len;

	top = 0;
	mp = ⊤
	while (totlen > 0) {
		MGET(m, M_DONTWAIT, MT_DATA);
		if (m == 0) {
			m_freem(top);
			top = 0;
			goto out;
		}
		if (off) {
			len = totlen - off;
			cp = (caddr_t) (ifu->ifu_hlen + off);
		} else
			len = totlen;
		if (len >= NBPG) {
			if (ifp)
				goto nopage;
			MCLGET(m);
			if (m->m_len != CLBYTES)
				goto nopage;
			m->m_len = MIN(len, CLBYTES);
			goto copy;
		}
nopage:
		m->m_off = MMINOFF;
		if (ifp) {
			/*
			 *	Leave room for ifp.
			 */
			m->m_len = MIN(MLEN - sizeof(ifp), len);
			m->m_off += sizeof(ifp);
		} else
			m->m_len = MIN(MLEN, len);
copy:
		mbcopyin(click, cp, mtod(m, char *), (u_int)m->m_len);
		cp += m->m_len;
nocopy:
		*mp = m;
		mp = &m->m_next;
		if (off) {
			/* sort of an ALGOL-W style for statement... */
			off += m->m_len;
			if (off == totlen) {
				cp = (caddr_t) ifu->ifu_hlen;
				off = 0;
				totlen = off0;
			}
		} else
			totlen -= m->m_len;
		if (ifp) {
			/*
			 *	Prepend interface pointer to first mbuf.
			 */
			m->m_len += sizeof(ifp);
			m->m_off -= sizeof(ifp);
			*(mtod(m, struct ifnet **)) = ifp;
			ifp = NULL;
		}
	}
out:
	return(top);
}

/*
 * Map a chain of mbufs onto a network interface
 * in preparation for an i/o operation.
 * The argument chain of mbufs includes the local network
 * header.
 */
if_wubaput(ifu, m)
	struct ifuba *ifu;
	register struct mbuf *m;
{
	register struct mbuf *mp;
	register u_short off = 0;
	u_short click = ifu->ifu_w.ifrw_click;

	while (m) {
		mbcopyout(mtod(m, char *), click, off, (u_int)m->m_len);
		off += m->m_len;
		MFREE(m, mp);
		m = mp;
	}
	return(off);
}

#define	KDSA	((u_short *)0172260)	/* supervisor - was 172360.KERNEL */

/*
 *	Map UNIBUS virtual memory over some address in supervisor data
 *	space.  We're similar to the "mapalloc" routine used for
 *	raw I/O, but for different objects.  The kernel's 'ubmap' is
 *	tested since the network's "fake" 'ubmap' has gone away (this
 *	routine was the only one to use it).
 */
ubadr_t
uballoc(addr, size)
	caddr_t addr;
	u_int size;
{
	register int nregs;
	register struct ubmap *ubp;
	ubadr_t paddr, vaddr;
	u_int click, first;
	int page, offset;

	page = (((int)addr >> 13) & 07);
	offset = ((int)addr & 017777);
	click = KDSA[page];
	paddr = (ubadr_t)click << 6;
	paddr += offset;
	if (!mfkd(&ubmap))
		return(paddr);
	nregs = (int)btoub(size);
	first = MALLOC(ub_map, nregs);
#ifdef	DIAGNOSTIC
/*
 * Should never happen since this is only called by initialization routines
 * in the network drivers.
*/
	if	(!first)
		panic("uballoc");
#endif
	ubp = &UBMAP[first];
	vaddr = (ubadr_t)first << 13;
	while (nregs--) {
		ubp->ub_lo = loint(paddr);
		ubp->ub_hi = hiint(paddr);
		ubp++;
		paddr += (ubadr_t) UBPAGE;
	}
	return(vaddr);
}

/*
 *	Computes a physical address within the mapped I/O area managed by
 *	m_ioget.  For a UNIBUS machine, the m_ioget arena is
 *	already mapped by UMRs and mioumr and miostart have the base
 *	virtual and click addresses of the mapped arena.  For Q22 machines
 *	mioumr and miostart are 0, turning the calculation into a ctob
 * 	of the input click address.
 */
ubadr_t
ubmalloc(addr)
	memaddr addr;		/* pdp11 "clicks" */
{
	extern ubadr_t mioumr;
	extern memaddr miostart;

	return(((ubadr_t)(addr - miostart) << 6) + mioumr);
}