~kris/9p

9hist

244de504da87fbf32ea972b6cffe57e7db8d0904 — David du Colombier 29 years ago 2a5a438
Plan 9 from Bell Labs 1997-09-19
2 files changed, 141 insertions(+), 187 deletions(-)

M pc/devastar.c
M pc/etherelnk3.c
M pc/devastar.c => pc/devastar.c +2 -2
@@ 1346,8 1346,8 @@ astarinput(Astarchan *ac)
			if(rp > ep)
				rp = bp;
		}
		if(qproduce(ac->iq, buf, n) < 0)
			break;	/* flow controlled */
		if(ac->opens == 0 || qproduce(ac->iq, buf, n) < 0)
			break;	/* flow controlled or not open */
		if(a->needpage)
			setpage(a, 0);
		ccb->inrp = LEUS(rp - a->addr);

M pc/etherelnk3.c => pc/etherelnk3.c +139 -185
@@ 6,7 6,6 @@
 *	autoSelect;
 *	PCI latency timer and master enable;
 *	errata list;
 *	limit 3C90x transmit queue;
 *	rewrite all initialisation.
 *
 * Product ID:


@@ 365,32 364,26 @@ enum {						/* 3C90x extended register set */
	dnIndicate		= 0x80000000,	/* FrameStartHeader (dpd->control) */

	updnLastFrag		= 0x80000000,	/* (dpd->len) */

	Nup			= 32,
	Ndn			= 16,
};

/*
 * Up/Dn Packet Descriptor.
 * The hardware info (np, control, addr, len) must be 8-byte aligned.
 * Up/Dn Packet Descriptors.
 * The hardware info (np, control, addr, len) must be 8-byte aligned
 * and this structure size must be a multiple of 8.
 */
typedef struct Dpd Dpd;
typedef struct Dpd {
typedef struct Pd Pd;
typedef struct Pd {
	ulong	np;				/* next pointer */
	ulong	control;			/* FSH or UpPktStatus */
	ulong	addr;
	ulong	len;

	Dpd*	next;
	Pd*	next;
	Block*	bp;
	void*	base;				/* base of this allocation */
} Dpd;

typedef struct Upd {
	ulong	np;				/* next pointer */
	ulong	control;			/* FSH or UpPktStatus */
	ulong	addr;
	ulong	len;

	uchar	data[sizeof(Etherpkt)];
} Upd;
} Pd;

typedef struct {
	Lock	wlock;				/* window access */


@@ 403,23 396,29 @@ typedef struct {
	int	txthreshold;
	int	txbusy;

	//Lock	upqlock;			/* full-busmaster -based reception */
	Block*	upqhead;
	Block*	upqtail;
	int	upalloc;
	int	nupd;

	Lock	dpdlock;			/* pool of free Dpd's */
	Dpd*	dpdpool;
	int	nup;				/* full-busmaster -based reception */
	void*	upbase;
	Pd*	upr;
	Pd*	uphead;

	Lock	dnqlock;			/* full-busmaster -based transmission */
	Dpd*	dnqhead;
	Dpd*	dnqtail;
	Lock	dnlock;				/* full-busmaster -based transmission */
	int	ndn;
	void*	dnbase;
	Pd*	dnr;
	Pd*	dnhead;
	Pd*	dntail;
	int	dnq;

	long	interrupts;			/* statistics */
	long	timer;
	long	stats[BytesRcvdOk+3];

	int	upqmax;
	int	upstalls;
	int	dnqmax;
	long	dninterrupts;
	long	dnqueued;

	int	xcvr;				/* transceiver type */
	int	rxstatus9;			/* old-style RxStatus register */
	int	rxearly;			/* RxEarlyThreshold */


@@ 428,81 427,48 @@ typedef struct {
	int	dnenabled;
} Ctlr;

static Block*
updalloc(ulong np)
static void
init905(Ctlr* ctlr)
{
	Block *bp;
	Upd *upd;
	Pd *pd, *prev;

	/*
	 * The hardware info (np, control, addr, len)
	 * must be 8-byte aligned.
	 * Create rings for the receive and transmit sides.
	 * Take care with alignment:
	 *	make sure ring base is 8-byte aligned;
	 *	make sure each entry is 8-byte aligned.
	 */
	if(bp = iallocb(sizeof(Upd)+8)){
		bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 8);
		bp->wp = bp->rp;
		upd = (Upd*)bp->rp;
		upd->np = np;
		upd->control = 0;
		upd->addr = PADDR(upd->data);
		upd->len = updnLastFrag|sizeof(Etherpkt);
	ctlr->upbase = malloc((ctlr->nup+1)*sizeof(Pd));
	ctlr->upr = (Pd*)ROUNDUP((ulong)ctlr->upbase, 8);

	prev = ctlr->upr;
	for(pd = &ctlr->upr[ctlr->nup-1]; pd >= ctlr->upr; pd--){
		pd->np = PADDR(&prev->np);
		pd->control = 0;
		bp = allocb(sizeof(Etherpkt));
		pd->addr = PADDR(bp->rp);
		pd->len = updnLastFrag|sizeof(Etherpkt);

		pd->next = prev;
		prev = pd;
		pd->bp = bp;
	}
	ctlr->uphead = ctlr->upr;

	return bp;
}

static void
init905(Ctlr* ctlr)
{
	int i;
	ulong np;
	Block *bp;
	Upd *upd;

	np = 0;
	for(i = 0; i < 64; i++){
		bp = updalloc(np);
		if(ctlr->upqhead == 0)
			ctlr->upqtail = bp;
		bp->next = ctlr->upqhead;
		ctlr->upqhead = bp;
		np = PADDR(bp->rp);
	}
	ctlr->upqtail->next = ctlr->upqhead;
	upd = (Upd*)ctlr->upqtail->rp;
	upd->np = PADDR(ctlr->upqhead->rp);
}
	ilock(&ctlr->dnlock);
	ctlr->dnbase = malloc((ctlr->ndn+1)*sizeof(Pd));
	ctlr->dnr = (Pd*)ROUNDUP((ulong)ctlr->dnbase, 8);

static Dpd*
dpdalloc(Ctlr* ctlr)
{
	Dpd *dpd;
	void *base;

	ilock(&ctlr->dpdlock);
	if(dpd = ctlr->dpdpool){
		ctlr->dpdpool = dpd->next;
		iunlock(&ctlr->dpdlock);
		dpd->next = 0;
		dpd->bp = 0;
	}
	else{
		iunlock(&ctlr->dpdlock);
		base = smalloc(sizeof(Dpd)+8);
		dpd = (Dpd*)ROUNDUP((ulong)base, 8);
		dpd->base = base;
	prev = ctlr->dnr;
	for(pd = &ctlr->dnr[ctlr->ndn-1]; pd >= ctlr->dnr; pd--){
		pd->next = prev;
		prev = pd;
	}

	return dpd;
}

static void
dpdfree(Ctlr* ctlr, Dpd* dpd)
{
	ilock(&ctlr->dpdlock);
	dpd->next = ctlr->dpdpool;
	ctlr->dpdpool = dpd;
	iunlock(&ctlr->dpdlock);
	ctlr->dnhead = ctlr->dnr;
	ctlr->dntail = ctlr->dnr;
	ctlr->dnq = 0;
	iunlock(&ctlr->dnlock);
}

static Block*


@@ 629,7 595,7 @@ attach(Ether* ether)
		startdma(ether, PADDR(ctlr->rbp->rp));
	else{
		if(ctlr->upenabled)
			outl(port+UpListPtr, PADDR(ctlr->upqhead->rp));
			outl(port+UpListPtr, PADDR(&ctlr->uphead->np));
	}

	ctlr->attached = 1;


@@ 726,16 692,17 @@ txstart(Ether* ether)
}

static void
start905(Ether* ether, Dpd* add)
txstart905(Ether* ether)
{
	Ctlr *ctlr;
	int dnlistptr, port;
	Dpd *dpd;
	Block *bp;
	Pd *pd;

	ctlr = ether->ctlr;
	port = ether->port;

	ilock(&ctlr->dnqlock);
	ilock(&ctlr->dnlock);
	COMMAND(port, Stall, dnStall);
	while(STATUS(port) & commandInProgress)
		;


@@ 744,64 711,53 @@ start905(Ether* ether, Dpd* add)
	 * Free any completed packets.
	 */
	dnlistptr = inl(port+DnListPtr);
	while(dpd = ctlr->dnqhead){
		if(PADDR(dpd) == dnlistptr)
	pd = ctlr->dntail;
	while(ctlr->dnq){
		if(PADDR(&pd->np) == dnlistptr)
			break;
		ctlr->dnqhead = dpd->next;
		if(dpd->bp)
			freeb(dpd->bp);
		dpdfree(ctlr, dpd);
		if(pd->bp){
			freeb(pd->bp);
			pd->bp = nil;
		}
		ctlr->dnq--;
		pd = pd->next;
	}
	ctlr->dntail = pd;

	/*
	 * Add any new packets to the queue.
	 */
	if(add){
		if(ctlr->dnqhead){
			dpd = ctlr->dnqtail;
			dpd->next = add;
			dpd->np = PADDR(&add->np);
			dpd->control &= ~dnIndicate;
		}
		else
			ctlr->dnqhead = add;
		ctlr->dnqtail = add;
	while(ctlr->dnq < (ctlr->ndn-1)){
		bp = qget(ether->oq);
		if(bp == nil)
			break;

		pd = ctlr->dnhead->next;
		pd->np = 0;
		pd->control = dnIndicate|BLEN(bp);
		pd->addr = PADDR(bp->rp);
		pd->len = updnLastFrag|BLEN(bp);
		pd->bp = bp;

		if(ctlr->dnq == 0)
			ctlr->dntail = pd;
		ctlr->dnhead->np = PADDR(&pd->np);
		ctlr->dnhead->control &= ~dnIndicate;
		ctlr->dnhead = pd;
		ctlr->dnq++;

		ctlr->dnqueued++;
	}

	if(ctlr->dnq > ctlr->dnqmax)
		ctlr->dnqmax = ctlr->dnq;

	/*
	 * If the adapter is not currently processing anything
	 * and there is something on the queue, start it processing.
	 */
	if(dnlistptr == 0 && ctlr->dnqhead)
		outl(port+DnListPtr, PADDR(ctlr->dnqhead));
	if(dnlistptr == 0 && ctlr->dnq)
		outl(port+DnListPtr, PADDR(&ctlr->dnhead->np));

	COMMAND(port, Stall, dnUnStall);
	iunlock(&ctlr->dnqlock);
}

static void
transmit905(Ether* ether)
{
	Ctlr *ctlr;
	Block *bp;
	Dpd* dpd;

	bp = qget(ether->oq);
	if(bp == nil)
		return;

	ctlr = ether->ctlr;

	dpd = dpdalloc(ctlr);
	dpd->next = 0;
	dpd->bp = bp;

	dpd->np = 0;
	dpd->control = dnIndicate|BLEN(bp);
	dpd->addr = PADDR(bp->rp);
	dpd->len = updnLastFrag|BLEN(bp);

	start905(ether, dpd);
	iunlock(&ctlr->dnlock);
}

static void


@@ 814,7 770,7 @@ transmit(Ether* ether)
	ctlr = ether->ctlr;

	if(ctlr->dnenabled){
		transmit905(ether);
		txstart905(ether);
		return;
	}



@@ 830,56 786,44 @@ static void
receive905(Ether* ether)
{
	Ctlr *ctlr;
	int port;
	Block *bp, *xbp;
	Upd *upd;
	int len, port, q;
	Pd *pd;
	Block *bp;

	ctlr = ether->ctlr;
	port = ether->port;

	//ilock(&ctlr->upqlock);
	COMMAND(port, Stall, upStall);
	while(STATUS(port) & commandInProgress)
		;

	bp = ctlr->upqhead;
	upd = (Upd*)bp->rp;
	while(upd->control & upPktComplete){
		if(upd->control & upError){
			if(upd->control & upOverrun)
	if(inl(port+UpPktStatus) & upStalled)
		ctlr->upstalls++;
	q = 0;
	for(pd = ctlr->uphead; pd->control & upPktComplete; pd = pd->next){
		if(pd->control & upError){
			if(pd->control & upOverrun)
				ether->overflows++;
			if(upd->control & (upOversizedFrame|upRuntFrame))
			if(pd->control & (upOversizedFrame|upRuntFrame))
				ether->buffs++;
			if(upd->control & upAlignmentError)
			if(pd->control & upAlignmentError)
				ether->frames++;
			if(upd->control & upCRCError)
			if(pd->control & upCRCError)
				ether->crcs++;

			upd->control = 0;
		}
		else if(xbp = updalloc(upd->np)){
			bp->rp += sizeof(Upd)-sizeof(Etherpkt);
			bp->wp = bp->rp + (upd->control & rxBytes);

			xbp->next = bp->next;
			bp->next = 0;

			etheriq(ether, bp, 1);
			bp = xbp;
		else if(bp = iallocb(sizeof(Etherpkt)+4)){
			len = pd->control & rxBytes;
			pd->bp->wp = pd->bp->rp+len;
			etheriq(ether, pd->bp, 1);
			pd->bp = bp;
			pd->addr = PADDR(bp->rp);
		}

		upd = (Upd*)ctlr->upqtail->rp;
		upd->np = PADDR(bp->rp);
		ctlr->upqtail->next = bp;
		ctlr->upqtail = bp;
		ctlr->upqhead = bp->next;
		pd->control = 0;
		COMMAND(port, Stall, upUnStall);

		bp = ctlr->upqhead;
		upd = (Upd*)bp->rp;
		q++;
	}
	ctlr->uphead = pd;

	COMMAND(port, Stall, upUnStall);
	//iunlock(&ctlr->upqlock);
	if(q > ctlr->upqmax)
		ctlr->upqmax = q;
}

static void


@@ 1044,8 988,8 @@ interrupt(Ureg*, void* arg)
		}

		if(status & (upComplete)){
			COMMAND(port, AcknowledgeInterrupt, upComplete);
			receive905(ether);
			COMMAND(port, AcknowledgeInterrupt, upComplete);
			status &= ~upComplete;
		}



@@ 1103,9 1047,10 @@ interrupt(Ureg*, void* arg)
		}

		if(status & dnComplete){
			txstart905(ether);
			COMMAND(port, AcknowledgeInterrupt, dnComplete);
			start905(ether, 0);
			status &= ~dnComplete;
			ctlr->dninterrupts++;
		}

		if(status & updateStats){


@@ 1164,6 1109,12 @@ ifstat(Ether* ether, void* a, long n, ulong offset)
	len += snprint(p+len, READSTR-len, "framesdeferred: %lud\n", ctlr->stats[FramesDeferred]);
	len += snprint(p+len, READSTR-len, "bytesrcvdok: %lud\n", ctlr->stats[BytesRcvdOk]);
	len += snprint(p+len, READSTR-len, "bytesxmittedok: %lud\n", ctlr->stats[BytesRcvdOk+1]);
len += snprint(p+len, READSTR-len, "up: q %lud s %lud\n",
    ctlr->upqmax, ctlr->upstalls);
ctlr->upqmax = 0;
len += snprint(p+len, READSTR-len, "dn: q %lud i %lud m %d\n",
    ctlr->dnqueued, ctlr->dninterrupts, ctlr->dnqmax);
ctlr->dnqmax = 0;
	snprint(p+len, READSTR-len, "badssd: %lud\n", ctlr->stats[BytesRcvdOk+2]);

	n = readstr(offset, a, n, p);


@@ 1761,8 1712,11 @@ etherelnk3reset(Ether* ether)
		if(!(x & 0x01))
			outl(port+PktStatus, upRxEarlyEnable);

		if(ctlr->upenabled)
		if(ctlr->upenabled || ctlr->dnenabled){
			ctlr->nup = Nup;
			ctlr->ndn = Ndn;
			init905(ctlr);
		}
		else
			ctlr->rbp = rbpalloc(allocb);
		outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256));