Ultrix-3.1/sys/sys/mbuf11.c

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


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

/*
 * SCCSID: @(#)mbuf11.c	3.0	4/21/86
 *	based on mbuf11.c  1.01    82/09/23
 */

#include <sys/param.h>
#ifdef	UCB_NET
#include <sys/seg.h>
#include <sys/mbuf.h>
#include <netinet/in_systm.h>

/*#define debug   1               /* consistency checks */

#ifdef debug
#define MBTRACE(type,arg) mbtrace(type,arg)
#else
#define MBTRACE(t,a)
#endif

#define IOSIZE  8192            /* area for DMA buffers */
#define NMBCACHE 8              /* cache of mbufs */
extern int nwords;		/* init arena size, bytes=(nwords-2)*WORD */

#define MBXGET(c) { \
	if ((c) = mbfree) { \
		mapseg5(mbfree,MBMAPSIZE); if (MBX->m_ref) panic("MBXGET"); \
		MBX->m_ref = 1;  MBTRACE(6,mbfree);  mbfree = (u_int)MBX->m_mbuf; }}

#define MBXFREE(c) { \
	mapseg5(c,MBMAPSIZE); if (MBX->m_ref != 1) panic("MBXFREE"); \
	MBX->m_ref = 0;  MBX->m_type = 0; MBTRACE(7,c);  MBX->m_mbuf = (struct mbuf *)mbfree; \
	mbfree = (c); }

struct mbuf *mbcache[NMBCACHE]; /* mbuf cache for fast allocation */
int     mbicache;               /* # entries in cache and index of next add */

extern memaddr	mbbase;		/* click address of mbuffer base */
extern u_int	mbsize;		/* size of mbuf area */
u_int   mbend;
u_int   miobase;                /* click of DMA area */
extern u_int   miosize;		/* size of area used for DMA */
u_int   mbfree;                 /* free list */
int	m_want, ms_want;

/*
 * Get an mbuf, consisting of an inaddress header (mbuf) and
 * an external data portion (mbufx).  Try to save some time by using
 * the cache.
 */
struct mbuf *
m_bget(canwait, type)
int canwait;
int type;
{
	register struct mbuf *m;
	int s = splimp();
	u_int click;
	segm	map5;

	saveseg5(map5);
	for (;;) {
		if (mbicache) {
			m = mbcache[--mbicache];
			mbstat.m_mbfree--;
			splx(s);
			MBTRACE(0,m);
			m->m_next = m->m_act = m->m_len = 0;
	/*@*/		m->m_off = MMINOFF;
			mapseg5(m->m_click, MBMAPSIZE);
			MBX->m_type = type;
			restorseg5(map5);
			return(m);
		}
	/* otherwise do it the hard way */
		MSGET(m, struct mbuf, MT_DATA, 0, canwait);
		if (m == 0)
			break;
		MBXGET(click);
		if (!click) {
			MSFREE(m);
			if (canwait) {
				restorseg5(map5);
				m_want++;
				sleep(&mbfree, PZERO - 1);
				continue;
			} else {
				mbstat.m_drops++;
				m = 0;
			}
			break;
		}
		m->m_click = click;
		m->m_next = m->m_act = m->m_len = 0;
		m->m_off = MMINOFF;
		MBX->m_mbuf = m;
		MBX->m_type = type;
		mbstat.m_mbfree--;
		mbstat.m_mbufs = MIN(mbstat.m_mbfree,mbstat.m_mbufs);
		break;
	}
	restorseg5(map5);
	splx(s);
	MBTRACE(1,m);
	return (m);
}

/*
 * Return an mbuf.  If not the last reference, just return the header;
 * else return both mbuf/mbufx.  Use the cache if empty slot exists.
 */
struct mbuf *
m_bfree(m)
	struct mbuf *m;
{
	register struct mbuf *n;
	int s = splimp();
	u_int click;

	MAPSAVE();
	n = m->m_next;
#ifdef debug
	MBTRACE(2,m);
	if (m->m_click < mbbase || m->m_click > mbend)
		panic("m_bf");
#endif
	click = m->m_click;
	mapseg5(click,MBMAPSIZE);
	if (MBX->m_ref != 1) {
		if (MBX->m_ref < 1 || MBX->m_ref > 4) panic("m_bf2");
		MBX->m_ref--;
		MSFREE(m);
		goto out;
	}
	mbstat.m_mbfree++;
	if (mbicache < NMBCACHE) {
		int *ip = (int *) m; ip--;
		if ((*ip & 01) == 0) panic("m_bf3");
		mbcache[mbicache++] = m;
		goto out;
	}
	MSFREE(m);
	MBXFREE(click);
out:
	MAPREST();
	if (m_want) {
		m_want = 0;
		wakeup((caddr_t)m_want);
	}
	splx(s);
	return (n);
}

/*
 * Allocate a contiguous buffer for DMA IO.  Called from if_ubainit().
 * TODO: fix net device drivers to handle scatter/gather to mbufs
 * on their own; thus avoiding the copy to/from this area.
 */
u_int
m_ioget(size)
{
	u_int base;

	size = ((size + 077) & ~077);   /* round up byte size */
	if (size > miosize) return(0);
	miosize -= size;
	base = miobase;
	miobase += (size>>6);
	MBTRACE(3,base);
	return(base);
}

/*	C storage allocator
 *	circular first-fit strategy
 *	works with noncontiguous, but monotonically linked, arena
 *	each block is preceded by a ptr to the (pointer of) 
 *	the next following block
 *	blocks are exact number of words long 
 *	aligned to the data type requirements of ALIGN
 *	pointers to blocks must have BUSY bit 0
 *	bit in ptr is 1 for busy, 0 for idle
 *	gaps in arena are merely noted as busy blocks
 *	last block of arena (pointed to by alloct) is empty and
 *	has a pointer to first
 *	idle blocks are coalesced during space search
 *
 *	a different implementation may need to redefine
 *	ALIGN, NALIGN, BLOCK, BUSY, INT
 *	where INT is integer type to which a pointer can be cast
*/
#define INT int
#define ALIGN int
#define NALIGN 1
#define WORD sizeof(union store)
#define BLOCK 1024	/* a multiple of WORD*/
#define BUSY 1
#define NULL 0

#define testbusy(p) ((INT)(p)&BUSY)
#define setbusy(p) (union store *)((INT)(p)|BUSY)
#define clearbusy(p) (union store *)((INT)(p)&~BUSY)

union store { union store *ptr;
	      ALIGN dummy[NALIGN];
	      int calloc;	/*calloc clears an array of integers*/
};

extern union store allocs[];  /* initial arena */
union store *allocp;    /*search ptr*/
union store *alloct;    /*arena top*/

#ifdef debug
#define ASSERT(p) if(!(p))botch("p");else
botch(s)
char *s;
{
	printf("botch %s\n",s);
	panic("mbuf11");
}
#ifdef longdebug
allock()
{
	register union store *p;
	int x;
	x = 0;
	for(p= &allocs[0]; clearbusy(p->ptr) > p; p=clearbusy(p->ptr)) {
		if(p==allocp)
			x++;
	}
	ASSERT(p==alloct);
	return(x==1||p==allocp);
}
#endif longdebug
#else
#define ASSERT(p)
#endif debug

char *
m_sget(nbytes,clr,canwait)
unsigned nbytes,clr;
{
	register union store *p, *q;
	register nw;
	int temp,val;
	int s = splimp();

	nw = (nbytes+WORD+WORD-1)/WORD;
top:
	ASSERT(allocp>=allocs && allocp<=alloct);
#ifdef	longdebug
	ASSERT(allock());
#endif	logndebug
	for(p=allocp; ; ) {
		for(temp=0; ; ) {
			if(!testbusy(p->ptr)) {
				while(!testbusy((q=p->ptr)->ptr)) {
					ASSERT(q>p&&q<alloct);
					p->ptr = q->ptr;
				}
				if(q>=p+nw && p+nw>=p)
					goto found;
			}
			q = p;
			p = clearbusy(p->ptr);
			if(p>q)
				ASSERT(p<=alloct);
			else if(q!=alloct || p!=allocs) {
				ASSERT(q==alloct&&p==allocs);
				goto bad;
			} else if(++temp>1)
				break;
		}
		/* malloc would call sbrk here and try again */
		mbstat.m_drops++;
		goto bad;
	}
found:
	allocp = p + nw;
	ASSERT(allocp<=alloct);
	if(q>allocp) {
		allocp->ptr = p->ptr;
	}
	p->ptr = setbusy(allocp);
	mbstat.m_clfree -= /* (clearbusy(p->ptr) - p) */ nw * WORD;
	mbstat.m_clusters = MIN(mbstat.m_clusters, mbstat.m_clfree);
	val = (char *)(p+1);
	splx(s);
	if (clr)
		bzero(val,((nbytes+1)& ~1));
	MBTRACE(4,val);
	return(val);
bad:
	if (canwait == M_WAIT) {
		ms_want++;
		sleep((caddr_t)&allocp, PZERO - 1);
		goto top;
	}
	splx(s);
	return(NULL);
}

/*	freeing strategy tuned for LIFO allocation
*/
m_sfree(ap)
register char *ap;
{
	register union store *p = (union store *)ap;
	int s = splimp();

	MBTRACE(5,ap);
	/* ASSERT(p>clearbusy(allocs[1].ptr)&&p<=alloct); */
	ASSERT(p>allocs&&p<=alloct);
#ifdef	longdebug
	ASSERT(allock());
#endif	longdebug
	/* allocp = --p;   leaves old blocks around longer for debugging */
		--p;
	ASSERT(testbusy(p->ptr));
	p->ptr = clearbusy(p->ptr);
	ASSERT(p->ptr > p && p->ptr <= alloct);
	mbstat.m_clfree += ((p->ptr) - p) * WORD;
	if (ms_want) {
		ms_want = 0;
		wakeup((caddr_t)&allocp);
	}
	splx(s);
}

/*
 * Mbuf address to data address, with bounds checking.  Called from
 * "mtod" macro which does type cast.
 */
mtodf(m)
register struct mbuf *m;
{
#ifdef	debug
	if (m < (struct mbuf *)&allocs[0] || m > (struct mbuf *) alloct)
		panic("allocs-mtodf");
	if (m->m_click < mbbase || m->m_click > mbend)
		panic("m_click-mtodf");
	if (m->m_off < MMINOFF)
		panic("m_off-MIN-mtodf");
	if (m->m_off > MMAXOFF) {
		printf("m %o, m_off %o\n",m, m->m_off);
		panic("m_off-MAX-mtodf");
	}
	if (m->m_len < 0 || m->m_len > MLEN)
		panic("m_len-mtodf");
#else !debug
	if (m < (struct mbuf *)&allocs[0] || m > (struct mbuf *) alloct
#ifdef debug
	    || m->m_click < mbbase || m->m_click > mbend
	    || m->m_off < MMINOFF || m->m_off > MMAXOFF
	    || m->m_len < 0 || m->m_len > MLEN
#endif
		) panic("mtodf");
#endif debug
	mapseg5(m->m_click,MBMAPSIZE);
	MBX->m_mbuf = m;
	return ((int)MBX + m->m_off);
}

/*
 * Initialize the buffer pool.  Called from netinit/main.
 */
mbinit()
{
	register i;
	u_int base;

	MAPSAVE();
	/* setup the arena */
	allocs[0].ptr = &allocs[nwords-1];
	allocs[nwords-1].ptr = setbusy(&allocs[0]);
	alloct = &allocs[nwords-1];
	allocp = &allocs[0];
	mbstat.m_clusters = mbstat.m_clfree = (nwords-2) * WORD;
	/* setup DMA IO area */
	miobase = mbbase;
	mbbase += (miosize>>6);
	mbsize -= miosize;
	/* link the mbufs */
	mbstat.m_mbufs = mbstat.m_mbfree = mbsize/MSIZE;
	base = mbbase;
	mbend = mbbase + (mbsize >> 6);

	for(i=0 ; i<(mbsize/MSIZE); i++) {
		mapseg5(base,MBMAPSIZE);
		MBX->m_ref = 1;
		MBXFREE(base);
		base += (MSIZE>>6);
	}
	MAPREST();
}


#ifdef debug

#define NMBTBUF 40

struct mbtbuf {
	u_int   mt_type;        /* type plus KISA6 */
	u_int   mt_pc;
	u_int   mt_arg;
} mbtbuf[NMBTBUF], *mbitbuf = mbtbuf;

mbtrace(type,arg)
{
	int s = spl7();
	register int *ip;
	register struct mbtbuf *mt = mbitbuf;
	extern int _ovno;

	if (++mbitbuf >= &mbtbuf[NMBTBUF])
		mbitbuf = mbtbuf;
	mt->mt_type = (type << 12) | _ovno;
	ip = &type;  ip--;  ip--;
	ip = *ip;  ip++;
	mt->mt_pc = *ip;
	mt->mt_arg = arg;
	splx(s);
}

#ifdef	notdef
mbprint(m,s)
register struct mbuf *m;
char *s;
{
	register char *ba;
	int col,i,bc;

#ifndef	debug
	return;
#endif
	MAPSAVE();
	printf("MB %s\n",s);
	for (;;) {
		if (m == 0) break;
		ba = mtod(m, char *);
		col = 0;  bc = m->m_len;
		printf("m%o next%o off%o len%o click%o act%o back%o ref%o\n",
			m, m->m_next, m->m_off, m->m_len, m->m_click, m->m_act,
			MBX->m_mbuf, MBX->m_ref);
		for(; bc ; bc--) {
			i = *ba++ & 0377;
			printf("%o ",i);
			if(++col > 31) {
				col = 0;
				printf("\n  ");
			}
		}
		printf("\n");
		m = m->m_next;
	}
	MAPREST();
}

#endif	notdef
#endif debug
#endif	UCB_NET