~kris/9p

9hist

59b326371a85d41285987e6efd8a0bc7928480b9 — David du Colombier 34 years ago ef82c5e
Plan 9 from Bell Labs 1992-04-04
4 files changed, 259 insertions(+), 139 deletions(-)

M pc/devether.c
M pc/kbd.c
M pc/main.c
M port/segment.c
M pc/devether.c => pc/devether.c +248 -113
@@ 1,7 1,7 @@
/*
 * Western Digital ethernet adapter
 * BUGS:
 *	more than one controller
 *	no more than one controller
 *	fix for different controller types
 */
#include "u.h"


@@ 15,24 15,35 @@

typedef struct Ctlr Ctlr;
typedef struct Pktype Pktype;
typedef struct Ring Ring;

enum {
	IObase		= 0x360,
	RAMbase		= 0xC8000,
	RAMsize		= 8*1024,
	BUFsize		= 256,

	Nctlr		= 1,
	NPktype		= 9,		/* types/interface */
};

/*
 * register offsets from IObase
 */
enum {
	EA		= 0x08,		/* Ethernet Address in ROM */
	ID		= 0x0E,		/* interface type */

	NIC		= 0x10,		/* National DP8390 Chip */
	Cr		= NIC+0x00,	/* Page [01] */

	Clda0		= NIC+0x01,	/* read */
	Pstart		= Clda0,	/* write */
	Clda1		= NIC+0x02,	/* read */
	Pstop		= Clda1,	/* write */
	Bnry		= NIC+0x03,	/* Page 0 */
	Pstart		= NIC+0x01,	/* write */
	Pstop		= NIC+0x02,	/* write */
	Bnry		= NIC+0x03,
	Tsr		= NIC+0x04,	/* read */
	Tpsr		= Tsr,		/* write */
	Ncr		= NIC+0x05,
	Tbcr0		= NIC+0x05,	/* write */
	Tbcr1		= NIC+0x06,	/* write */
	Isr		= NIC+0x07,
	Rbcr0		= NIC+0x0A,
	Rbcr1		= NIC+0x0B,


@@ 47,19 58,25 @@ enum {

	Par0		= NIC+0x01,	/* Page 1 */
	Curr		= NIC+0x07,
	Mar0		= NIC+0x08,
	Mar1		= NIC+0x09,
	Mar2		= NIC+0x0A,
	Mar3		= NIC+0x0B,
	Mar4		= NIC+0x0C,
	Mar5		= NIC+0x0D,
	Mar6		= NIC+0x0E,
	Mar7		= NIC+0x0F,
};

	RAMbase		= 0xC8000,
/*
 * some register bits
 */
enum {
	Prx		= 0x01,		/* Isr:	packet received */
	Ptx		= 0x02,		/*	packet transmitted */
	Rxe		= 0x04,		/*	receive error */
	Txe		= 0x08,		/*	transmit error */
	Ovw		= 0x10,		/*	overwrite warning */
	Rst		= 0x80,		/*	reset status */
};

	Nctlr		= 1,
	NPktype		= 9,		/* types/interface */
struct Ring {
	uchar	status;
	uchar	next;
	ushort	len;
	uchar	data[BUFsize-4];
};

/*


@@ 81,9 98,12 @@ struct Ctlr {
	QLock;

	Rendez	rr;			/* rendezvous for an input buffer */
	uchar	bnry;
	uchar	curr;
	uchar	ovw;
	Queue	rq;

	Qlock	xl;
	QLock	xl;
	Rendez	xr;

	int	iobase;			/* I/O base address */


@@ 117,6 137,8 @@ etheroput(Queue *q, Block *bp)
	Etherpkt *p;
	Block *nbp;

panic("etheroput\n");
#ifdef notdef
	c = ((Pktype *)q->ptr)->ctlr;
	if(bp->type == M_CTL){
		t = q->ptr;


@@ 126,8 148,10 @@ etheroput(Queue *q, Block *bp)
			t->prom = 1;
			qlock(c);
			c->prom++;
			if(c->prom == 1)
			if(c->prom == 1){
				outb(t->ctlr->iobase+Cr, 0x22);	/* Page0, RD2|STA */
				outb(c->iobase+Rcr, 0x14);	/* PRO|AB */
			}
			qunlock(c);
		}
		freeb(bp);


@@ 226,6 250,7 @@ etheroput(Queue *q, Block *bp)
	poperror();

	enet.outpackets++;
#endif
}

/*


@@ 237,17 262,17 @@ etheroput(Queue *q, Block *bp)
static void
etherstopen(Queue *q, Stream *s)
{
	Ctlr *c = &ctlr[0];
	Pktype *t;

	t = &c->pktype[s->id];
	qlock(t);
	RD(q)->ptr = WR(q)->ptr = t;
	t->type = 0;
	t->q = RD(q);
	t->inuse = 1;
	t->ctlr = c;
	qunlock(t);
	Ctlr *cp = &ctlr[0];
	Pktype *pp;

	pp = &cp->pktype[s->id];
	qlock(pp);
	RD(q)->ptr = WR(q)->ptr = pp;
	pp->type = 0;
	pp->q = RD(q);
	pp->inuse = 1;
	pp->ctlr = cp;
	qunlock(pp);
}

/*


@@ 259,23 284,25 @@ etherstopen(Queue *q, Stream *s)
static void
etherstclose(Queue *q)
{
	Pktype *t;

	t = (Pktype *)(q->ptr);
	if(t->prom){
		qlock(t->ctlr);
		t->ctlr->prom--;
		if(t->ctlr->prom == 0)
			/* turn off promiscuous mode here */;
		qunlock(t->ctlr);
	Pktype *pp;

	pp = (Pktype *)(q->ptr);
	if(pp->prom){
		qlock(pp->ctlr);
		pp->ctlr->prom--;
		if(pp->ctlr->prom == 0){
			outb(pp->ctlr->iobase+Cr, 0x22);/* Page0, RD2|STA */
			outb(pp->ctlr->iobase+Rcr, 0x04);/* AB */
		}
		qunlock(pp->ctlr);
	}
	qlock(t);
	t->type = 0;
	t->q = 0;
	t->prom = 0;
	t->inuse = 0;
	netdisown(&t->ctlr->net, t - t->ctlr->pktype);
	qunlock(t);
	qlock(pp);
	pp->type = 0;
	pp->q = 0;
	pp->prom = 0;
	pp->inuse = 0;
	netdisown(&pp->ctlr->net, pp - pp->ctlr->pktype);
	qunlock(pp);
}

static Qinfo info = {


@@ 287,35 314,35 @@ static Qinfo info = {
};

static int
clonecon(Chan *chan)
clonecon(Chan *c)
{
	Ctlr *c = &ctlr[0];
	Pktype *t;
	Ctlr *cp = &ctlr[0];
	Pktype *pp;

	for(t = c->pktype; t < &c->pktype[NPktype]; t++){
		qlock(t);
		if(t->inuse || t->q){
			qunlock(t);
	for(pp = cp->pktype; pp < &cp->pktype[NPktype]; pp++){
		qlock(pp);
		if(pp->inuse || pp->q){
			qunlock(pp);
			continue;
		}
		t->inuse = 1;
		netown(&c->net, t - c->pktype, u->p->user, 0);
		qunlock(t);
		return t - c->pktype;
		pp->inuse = 1;
		netown(&cp->net, pp - cp->pktype, u->p->user, 0);
		qunlock(pp);
		return pp - cp->pktype;
	}
	exhausted("ether channels");
}

static void
statsfill(Chan *chan, char *p, int n)
statsfill(Chan *c, char *p, int n)
{
	Ctlr *c = &ctlr[0];
	Ctlr *cp = &ctlr[0];
	char buf[256];

	sprint(buf, "in: %d\nout: %d\ncrc errs %d\noverflows: %d\nframe errs %d\nbuff errs: %d\noerrs %d\naddr: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x\n",
		c->inpackets, c->outpackets, c->crcs,
		c->overflows, c->frames, c->buffs, c->oerrs,
		c->ea[0], c->ea[1], c->ea[2], c->ea[3], c->ea[4], c->ea[5]);
		cp->inpackets, cp->outpackets, cp->crcs,
		cp->overflows, cp->frames, cp->buffs, cp->oerrs,
		cp->ea[0], cp->ea[1], cp->ea[2], cp->ea[3], cp->ea[4], cp->ea[5]);
	strncpy(p, buf, n);
}



@@ 323,96 350,205 @@ static void
typefill(Chan *c, char *p, int n)
{
	char buf[16];
	Pktype *t;
	Pktype *pp;

	t = &ctlr[0].pktype[STREAMID(c->qid.path)];
	sprint(buf, "%d", t->type);
	pp = &ctlr[0].pktype[STREAMID(c->qid.path)];
	sprint(buf, "%d", pp->type);
	strncpy(p, buf, n);
}

static void
intr(Ureg *ur)
{
	panic("ether intr\n");
	Ctlr *cp = &ctlr[0];
	uchar isr, curr;

	outb(cp->iobase+Cr, 0x22);			/* Page0, RD2|STA */
	while(isr = inb(cp->iobase+Isr)){
		outb(cp->iobase+Isr, isr);
		if(isr & Txe)
			cp->oerrs++;
		if(isr & Rxe){
			cp->frames += inb(cp->iobase+Cntr0);
			cp->crcs += inb(cp->iobase+Cntr1);
			cp->buffs += inb(cp->iobase+Cntr2);
		}
		if(isr & Ptx)
			cp->outpackets++;
		if(isr & (Txe|Ptx)){
			panic("tx intr\n");
		}
		/*
		 * the receive ring is full.
		 * put the NIC into loopback mode to give
		 * kproc a chance to process some packets.
		 */
		if(isr & Ovw){
			outb(cp->iobase+Cr, 0x21);	/* Page0, RD2|STP */
			outb(cp->iobase+Rbcr0, 0);
			outb(cp->iobase+Rbcr1, 0);
			while((inb(cp->iobase+Isr) & Rst) == 0)
				delay(1);
			outb(cp->iobase+Tcr, 0x20);	/* LB0 */
			outb(cp->iobase+Cr, 0x22);	/* Page0, RD2|STA */
			cp->ovw = 1;
		}
		/*
		 * we have received packets.
		 * this is the only place, other than the init code,
		 * where we set the controller to Page1.
		 * we must be careful to reset it back to Page0 in case
		 * we interrupted some other part of this driver.
		 */
		if(isr & (Ovw|Prx)){
			outb(cp->iobase+Cr, 0x62);	/* Page1, RD2|STA */
			cp->curr = inb(cp->iobase+Curr);
			outb(cp->iobase+Cr, 0x22);	/* Page0, RD2|STA */
			wakeup(&cp->rr);
		}
	}
}

/*
 * the following initialisation procedure
 * is mandatory
 * after this, the chip is still offline
 * we leave the chip idling on internal loopback
 */
static void
init(Ctlr *c)
init(Ctlr *cp)
{
	int i;

	outb(c->iobase+Cr, 0x21);	/* Page0, RD2|STP */
	outb(c->iobase+Dcr, 0x48);	/* FT1|LS */
	outb(c->iobase+Rbcr0, 0);
	outb(c->iobase+Rbcr1, 0);
	outb(c->iobase+Rcr, 0x04);	/* AB */
	outb(c->iobase+Tcr, 0);
	outb(c->iobase+Bnry, 6);
	outb(c->iobase+Pstart, 6);	/* 6*256 */
	outb(c->iobase+Pstop, 32);	/* 8*1024/256 */
	outb(c->iobase+Isr, 0xFF);
	outb(c->iobase+Imr, 0x0F);	/* TXEE|RXEE|PTXE|PRXE */

	outb(c->iobase+Cr, 0x61);	/* Page1, RD2|STP */
	for(i = 0; i < sizeof(c->ea); i++)
		outb(c->iobase+Par0+i, c->ea[i]);
	outb(c->iobase+Curr, 6);	/* 6*256 */
	outb(cp->iobase+Cr, 0x21);		/* Page0, RD2|STP */
	outb(cp->iobase+Dcr, 0x48);		/* FT1|LS */
	outb(cp->iobase+Rbcr0, 0);
	outb(cp->iobase+Rbcr1, 0);
	outb(cp->iobase+Rcr, 0x04);		/* AB */
	outb(cp->iobase+Tcr, 0x20);		/* LB0 */
	outb(cp->iobase+Bnry, 6);
	cp->bnry = 6;
	outb(cp->iobase+Pstart, 6);		/* 6*256 */
	outb(cp->iobase+Pstop, 32);		/* 8*1024/256 */
	outb(cp->iobase+Isr, 0xFF);
	outb(cp->iobase+Imr, 0x1F);		/* OVWE|TXEE|RXEE|PTXE|PRXE */

	outb(cp->iobase+Cr, 0x61);		/* Page1, RD2|STP */
	for(i = 0; i < sizeof(cp->ea); i++)
		outb(cp->iobase+Par0+i, cp->ea[i]);
	outb(cp->iobase+Curr, 6);		/* 6*256 */
	cp->curr = 6;

	outb(cp->iobase+Cr, 0x22);		/* Page0, RD2|STA */
	outb(cp->iobase+Tpsr, 0);
}

void
etherreset(void)
{
	Ctlr *c = &ctlr[0];
	Ctlr *cp = &ctlr[0];
	int i;

	c->iobase = IObase;
	init(c);
	cp->iobase = IObase;
	init(cp);
	setvec(Ethervec, intr);

	for(i = 0; i < sizeof(c->ea); i++)
		c->ea[i] = inb(c->iobase+EA+i);
	memset(c->ba, 0xFF, sizeof(c->ba));

	c->net.name = "ether";
	c->net.nconv = NPktype;
	c->net.devp = &info;
	c->net.protop = 0;
	c->net.listen = 0;
	c->net.clone = clonecon;
	c->net.ninfo = 2;
	c->net.prot = c->prot;
	c->net.info[0].name = "stats";
	c->net.info[0].fill = statsfill;
	c->net.info[1].name = "type";
	c->net.info[1].fill = typefill;
	for(i = 0; i < sizeof(cp->ea); i++)
		cp->ea[i] = inb(cp->iobase+EA+i);
	memset(cp->ba, 0xFF, sizeof(cp->ba));

	cp->net.name = "ether";
	cp->net.nconv = NPktype;
	cp->net.devp = &info;
	cp->net.protop = 0;
	cp->net.listen = 0;
	cp->net.clone = clonecon;
	cp->net.ninfo = 2;
	cp->net.prot = cp->prot;
	cp->net.info[0].name = "stats";
	cp->net.info[0].fill = statsfill;
	cp->net.info[1].name = "type";
	cp->net.info[1].fill = typefill;
}

static void
etherup(Ctlr *cp, Etherpkt *p, int len)
{
	Block *bp;
	Pktype *pp;
	int t;

	t = (p->type[0]<<8) | p->type[1];
	for(pp = &cp->pktype[0]; pp < &cp->pktype[NPktype]; pp++){
		/*
		 *  check before locking just to save a lock
		 */
		if(pp->q == 0 || (t != pp->type && pp->type != -1))
			continue;

		/*
		 *  only a trace channel gets packets destined for other machines
		 */
		if(pp->type != -1 && p->d[0] != 0xFF && memcmp(p->d, cp->ea, sizeof(p->d)))
			continue;

		/*
		 *  check after locking to make sure things didn't
		 *  change under foot
		 */
		if(canqlock(pp) == 0)
			continue;
		if(pp->q == 0 || pp->q->next->len > Streamhi || (t != pp->type && pp->type != -1)){
			qunlock(pp);
			continue;
		}
		if(waserror() == 0){
			bp = allocb(len);
			memmove(bp->rptr, (uchar *)p, len);
			bp->wptr += len;
			bp->flags |= S_DELIM;
			PUTNEXT(pp->q, bp);
		}
		poperror();
		qunlock(pp);
	}
}

static int
isinput(void *arg)
{
	Ctlr *c = arg;
	Ctlr *cp = arg;

	return 0;
	return cp->bnry != cp->curr;
}

static void
etherkproc(void *arg)
{
	Ctlr *c = arg;
	Ctlr *cp = arg;
	Block *bp;
	uchar bnry, curr;
	Ring *rp;

	if(waserror()){
		print("someone noted %s\n", c->name);
		c->kproc = 0;
		print("%s noted\n", cp->name);
		init(cp);
		cp->kproc = 0;
		nexterror();
	}
	c->kproc = 1;
	cp->kproc = 1;
	for(;;){
		sleep(&c->rr, isinput, c);
		sleep(&cp->rr, isinput, cp);
		while(bp = getq(&cp->rq)){
			cp->inpackets++;
			etherup(cp, (Etherpkt*)bp->rptr, BLEN(bp));
			freeb(bp);
		}
#ifdef foo
			bnry = inb(cp->iobase+Bnry);
			while(bnry != cp->curr){
				rp = &((Ring *)RAMbase)[bnry];
			}
#endif
	}
}



@@ 425,8 561,7 @@ etherinit(void)
	 * put the receiver online
	 * and start the kproc
	 */
	outb(c->iobase+Cr, 0x22);	/* Page0, RD2|STA */
	outb(c->iobase+Tpsr, 0);
	outb(ctlr[ctlrno].iobase+Tcr, 0);
	if(ctlr[ctlrno].kproc == 0){
		sprint(ctlr[ctlrno].name, "ether%dkproc", ctlrno);
		kproc(ctlr[ctlrno].name, etherkproc, &ctlr[ctlrno]);

M pc/kbd.c => pc/kbd.c +0 -13
@@ 182,19 182,6 @@ i8042a20(void)
	outready();
}

/*
 *  ask 8042 to reset the 386
 */
void
i8042reset(void)
{
	outready();
	outb(Cmd, 0xD1);
	outready();
	outb(Data, 0x0);
	outready();
}

void
kbdinit(void)
{

M pc/main.c => pc/main.c +2 -2
@@ 430,8 430,8 @@ exit(void)
		headreset();		/* via headland chip */
		break;
	case At:
		i8042reset();		/* via keyboard controller */
		break;
		putcr3(0);		/* crash and burn */
		for(;;);
	}
}


M port/segment.c => port/segment.c +9 -11
@@ 275,20 275,18 @@ imagereclaim(void)
	if(!canqlock(&ireclaim))	/* Somebody is already cleaning the page cache */
		return;

	for(;;) {
		lock(&palloc);
		for(p = palloc.head; p; p = p->next) {
			if(p->image)
	lock(&palloc);
	for(p = palloc.head; p; p = p->next) {
		if(p->image)
		if(p->ref == 0)
		if(p->image != &swapimage) {
			lockpage(p);
			if(p->ref == 0)
			if(p->image != &swapimage) {
				lockpage(p);
				if(p->ref == 0)
					uncachepage(p);
				unlockpage(p);
			}
				uncachepage(p);
			unlockpage(p);
		}
		unlock(&palloc);
	}
	unlock(&palloc);
	qunlock(&ireclaim);
}