~kris/9p

9hist

f7380b25d3de5223060c92121c76044b59dc9567 — David du Colombier 31 years ago 72f57de
Plan 9 from Bell Labs 1995-04-08
1 files changed, 110 insertions(+), 93 deletions(-)

M pc/ether8390.c
M pc/ether8390.c => pc/ether8390.c +110 -93
@@ 14,9 14,6 @@

#include "etherif.h"

extern int slowinb(ulong);
extern void slowoutb(ulong, uchar);

enum {
	Cr		= 0x00,		/* command register, all pages */



@@ 149,6 146,26 @@ typedef struct {
	uchar	len1;
} Hdr;

/*
 *  the 8390 register accesses must not be too close together
 */
void
dp8390outb(ulong port, uchar x)
{
	outb(port, x);
	microdelay(0);
}

long
dp8390inb(ulong port)
{
	long x;

	x = inb(port);
	microdelay(0);
	return x;
}

static void
dp8390disable(Dp8390 *dp8390)
{


@@ 163,10 180,10 @@ dp8390disable(Dp8390 *dp8390)
	 * chip there if this is called when probing for a device
	 * at boot.
	 */
	slowoutb(port+Cr, Page0|RDMAabort|Stp);
	slowoutb(port+Rbcr0, 0);
	slowoutb(port+Rbcr1, 0);
	for(timo = 10000; (slowinb(port+Isr) & Rst) == 0 && timo; timo--)
	dp8390outb(port+Cr, Page0|RDMAabort|Stp);
	dp8390outb(port+Rbcr0, 0);
	dp8390outb(port+Rbcr1, 0);
	for(timo = 10000; (dp8390inb(port+Isr) & Rst) == 0 && timo; timo--)
			;
}



@@ 175,13 192,13 @@ dp8390ring(Dp8390 *dp8390)
{
	ulong port = dp8390->dp8390;

	slowoutb(port+Pstart, dp8390->pstart);
	slowoutb(port+Pstop, dp8390->pstop);
	slowoutb(port+Bnry, dp8390->pstop-1);
	dp8390outb(port+Pstart, dp8390->pstart);
	dp8390outb(port+Pstop, dp8390->pstop);
	dp8390outb(port+Bnry, dp8390->pstop-1);

	slowoutb(port+Cr, Page1|RDMAabort|Stp);
	slowoutb(port+Curr, dp8390->pstart);
	slowoutb(port+Cr, Page0|RDMAabort|Stp);
	dp8390outb(port+Cr, Page1|RDMAabort|Stp);
	dp8390outb(port+Curr, dp8390->pstart);
	dp8390outb(port+Cr, Page0|RDMAabort|Stp);

	dp8390->nxtpkt = dp8390->pstart;
}


@@ 200,11 217,11 @@ dp8390setea(Ether *ether)
	 * addresses as we never set the multicast
	 * enable.
	 */
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
	for(i = 0; i < sizeof(ether->ea); i++)
		slowoutb(port+Par0+i, ether->ea[i]);
	slowoutb(port+Cr, cr);
		dp8390outb(port+Par0+i, ether->ea[i]);
	dp8390outb(port+Cr, cr);
}

void


@@ 221,11 238,11 @@ dp8390getea(Ether *ether)
	 * addresses as we never set the multicast
	 * enable.
	 */
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
	for(i = 0; i < sizeof(ether->ea); i++)
		ether->ea[i] = slowinb(port+Par0+i);
	slowoutb(port+Cr, cr);
		ether->ea[i] = dp8390inb(port+Par0+i);
	dp8390outb(port+Cr, cr);
}

void*


@@ 240,25 257,25 @@ dp8390read(Dp8390 *dp8390, void *to, ulong from, ulong len)
	 * using the DP8390 remote DMA facility, and place it at
	 * 'to' in main memory, via the I/O data port.
	 */
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page0|RDMAabort|Sta);
	slowoutb(port+Isr, Rdc);
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
	dp8390outb(port+Isr, Rdc);

	/*
	 * Set up the remote DMA address and count.
	 */
	if(dp8390->bit16)
		len = ROUNDUP(len, 2);
	slowoutb(port+Rbcr0, len & 0xFF);
	slowoutb(port+Rbcr1, (len>>8) & 0xFF);
	slowoutb(port+Rsar0, from & 0xFF);
	slowoutb(port+Rsar1, (from>>8) & 0xFF);
	dp8390outb(port+Rbcr0, len & 0xFF);
	dp8390outb(port+Rbcr1, (len>>8) & 0xFF);
	dp8390outb(port+Rsar0, from & 0xFF);
	dp8390outb(port+Rsar1, (from>>8) & 0xFF);

	/*
	 * Start the remote DMA read and suck the data
	 * out of the I/O port.
	 */
	slowoutb(port+Cr, Page0|RDMAread|Sta);
	dp8390outb(port+Cr, Page0|RDMAread|Sta);
	if(dp8390->bit16)
		inss(dp8390->data, to, len/2);
	else


@@ 271,11 288,11 @@ dp8390read(Dp8390 *dp8390, void *to, ulong from, ulong len)
	 * to the miracles of the bus, we could get this far
	 * and still be talking to a slot full of nothing.
	 */
	for(timo = 10000; (slowinb(port+Isr) & Rdc) == 0 && timo; timo--)
	for(timo = 10000; (dp8390inb(port+Isr) & Rdc) == 0 && timo; timo--)
			;

	slowoutb(port+Isr, Rdc);
	slowoutb(port+Cr, cr);
	dp8390outb(port+Isr, Rdc);
	dp8390outb(port+Cr, cr);
	return to;
}



@@ 298,9 315,9 @@ dp8390write(Dp8390 *dp8390, ulong to, void *from, ulong len)
	 * using the DP8390 remote DMA facility, reading it at
	 * 'from' in main memory, via the I/O data port.
	 */
	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page0|RDMAabort|Sta);
	slowoutb(port+Isr, Rdc);
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
	dp8390outb(port+Isr, Rdc);

	if(dp8390->bit16)
		len = ROUNDUP(len, 2);


@@ 311,24 328,24 @@ dp8390write(Dp8390 *dp8390, ulong to, void *from, ulong len)
	 * the initial set up for read.
	 */
	crda = to-1-dp8390->bit16;
	slowoutb(port+Rbcr0, (len+1+dp8390->bit16) & 0xFF);
	slowoutb(port+Rbcr1, ((len+1+dp8390->bit16)>>8) & 0xFF);
	slowoutb(port+Rsar0, crda & 0xFF);
	slowoutb(port+Rsar1, (crda>>8) & 0xFF);
	slowoutb(port+Cr, Page0|RDMAread|Sta);
	dp8390outb(port+Rbcr0, (len+1+dp8390->bit16) & 0xFF);
	dp8390outb(port+Rbcr1, ((len+1+dp8390->bit16)>>8) & 0xFF);
	dp8390outb(port+Rsar0, crda & 0xFF);
	dp8390outb(port+Rsar1, (crda>>8) & 0xFF);
	dp8390outb(port+Cr, Page0|RDMAread|Sta);

	for(;;){
		crda = slowinb(port+Crda0);
		crda |= slowinb(port+Crda1)<<8;
		crda = dp8390inb(port+Crda0);
		crda |= dp8390inb(port+Crda1)<<8;
		if(crda == to){
			/*
			 * Start the remote DMA write and make sure
			 * the registers are correct.
			 */
			slowoutb(port+Cr, Page0|RDMAwrite|Sta);
			dp8390outb(port+Cr, Page0|RDMAwrite|Sta);

			crda = slowinb(port+Crda0);
			crda |= slowinb(port+Crda1)<<8;
			crda = dp8390inb(port+Crda0);
			crda |= dp8390inb(port+Crda1)<<8;
			if(crda != to)
				panic("crda write %d to %d\n", crda, to);



@@ 349,15 366,15 @@ dp8390write(Dp8390 *dp8390, ulong to, void *from, ulong len)
	 * be almost immediate.
	 */
	tries = 0;
	while((slowinb(port+Isr) & Rdc) == 0){
	while((dp8390inb(port+Isr) & Rdc) == 0){
		if(tries++ >= 100000){
			print("dp8390write dma timed out\n");
			break;
		}
	}

	slowoutb(port+Isr, Rdc);
	slowoutb(port+Cr, cr);
	dp8390outb(port+Isr, Rdc);
	dp8390outb(port+Cr, cr);
	splx(s);

	return (void*)to;


@@ 369,10 386,10 @@ getcurr(Dp8390 *dp8390)
	ulong port = dp8390->dp8390;
	uchar cr, curr;

	cr = slowinb(port+Cr) & ~Txp;
	slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = slowinb(port+Curr);
	slowoutb(port+Cr, cr);
	cr = dp8390inb(port+Cr) & ~Txp;
	dp8390outb(port+Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = dp8390inb(port+Curr);
	dp8390outb(port+Cr, cr);
	return curr;
}



@@ 416,9 433,9 @@ receive(Ether *ether)
		  || len < 60 || len > sizeof(Etherpkt)){
			print("dp8390: H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d\n",
				hdr.status, hdr.next, hdr.len0, hdr.len1, len);
			slowoutb(port+Cr, Page0|RDMAabort|Stp);
			dp8390outb(port+Cr, Page0|RDMAabort|Stp);
			dp8390ring(dp8390);
			slowoutb(port+Cr, Page0|RDMAabort|Sta);
			dp8390outb(port+Cr, Page0|RDMAabort|Sta);
			return;
		}



@@ 467,7 484,7 @@ receive(Ether *ether)
		hdr.next--;
		if(hdr.next < dp8390->pstart)
			hdr.next = dp8390->pstop-1;
		slowoutb(port+Bnry, hdr.next);
		dp8390outb(port+Bnry, hdr.next);
	}
}



@@ 519,9 536,9 @@ write(Ether *ether, void *buf, long len)
	if(dp8390->ram == 0)
		dp8390write(dp8390, dp8390->tstart*Dp8390BufSz, pkt, len);

	slowoutb(port+Tbcr0, len & 0xFF);
	slowoutb(port+Tbcr1, (len>>8) & 0xFF);
	slowoutb(port+Cr, Page0|RDMAabort|Txp|Sta);
	dp8390outb(port+Tbcr0, len & 0xFF);
	dp8390outb(port+Tbcr1, (len>>8) & 0xFF);
	dp8390outb(port+Cr, Page0|RDMAabort|Txp|Sta);

	return len;
}


@@ 541,24 558,24 @@ overflow(Ether *ether)
	 * The following procedure is taken from the DP8390[12D] datasheet,
	 * it seems pretty adamant that this is what has to be done.
	 */
	txp = slowinb(port+Cr) & Txp;
	slowoutb(port+Cr, Page0|RDMAabort|Stp);
	txp = dp8390inb(port+Cr) & Txp;
	dp8390outb(port+Cr, Page0|RDMAabort|Stp);
	delay(2);
	slowoutb(port+Rbcr0, 0);
	slowoutb(port+Rbcr1, 0);
	dp8390outb(port+Rbcr0, 0);
	dp8390outb(port+Rbcr1, 0);

	resend = 0;
	if(txp && (slowinb(port+Isr) & (Txe|Ptx)) == 0)
	if(txp && (dp8390inb(port+Isr) & (Txe|Ptx)) == 0)
		resend = 1;

	slowoutb(port+Tcr, Lb);
	slowoutb(port+Cr, Page0|RDMAabort|Sta);
	dp8390outb(port+Tcr, Lb);
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);
	receive(ether);
	slowoutb(port+Isr, Ovw);
	slowoutb(port+Tcr, 0);
	dp8390outb(port+Isr, Ovw);
	dp8390outb(port+Tcr, 0);

	if(resend)
		slowoutb(port+Cr, Page0|RDMAabort|Txp|Sta);
		dp8390outb(port+Cr, Page0|RDMAabort|Txp|Sta);
}

static void


@@ 579,12 596,12 @@ interrupt(Ureg *ur, void *arg)
	 * While there is something of interest,
	 * clear all the interrupts and process.
	 */
	slowoutb(port+Imr, 0x00);
	while(isr = slowinb(port+Isr)){
	dp8390outb(port+Imr, 0x00);
	while(isr = dp8390inb(port+Isr)){

		if(isr & Ovw){
			overflow(ether);
			slowoutb(port+Isr, Ovw);
			dp8390outb(port+Isr, Ovw);
			ether->overflows++;
		}



@@ 594,7 611,7 @@ interrupt(Ureg *ur, void *arg)
		 */
		if(isr & (Rxe|Prx)){
			receive(ether);
			slowoutb(port+Isr, Rxe|Prx);
			dp8390outb(port+Isr, Rxe|Prx);
		}

		/*


@@ 603,14 620,14 @@ interrupt(Ureg *ur, void *arg)
		 * and wake the output routine.
		 */
		if(isr & (Txe|Ptx)){
			r = slowinb(port+Tsr);
			r = dp8390inb(port+Tsr);
			if(isr & Txe){
				if((r & (Cdh|Fu|Crs|Abt)))
					print("dp8390: Tsr#%2.2ux\n", r);
				ether->oerrs++;
			}

			slowoutb(port+Isr, Txe|Ptx);
			dp8390outb(port+Isr, Txe|Ptx);

			if(isr & Ptx)
				ether->outpackets++;


@@ 619,13 636,13 @@ interrupt(Ureg *ur, void *arg)
		}

		if(isr & Cnt){
			ether->frames += slowinb(port+Cntr0);
			ether->crcs += slowinb(port+Cntr1);
			ether->buffs += slowinb(port+Cntr2);
			slowoutb(port+Isr, Cnt);
			ether->frames += dp8390inb(port+Cntr0);
			ether->crcs += dp8390inb(port+Cntr1);
			ether->buffs += dp8390inb(port+Cntr2);
			dp8390outb(port+Isr, Cnt);
		}
	}
	slowoutb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
	dp8390outb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
}

static void


@@ 637,9 654,9 @@ promiscuous(void *arg, int on)
	 * Set/reset promiscuous mode.
	 */
	if(on)
		slowoutb(dp8390->dp8390+Rcr, Pro|Ab);
		dp8390outb(dp8390->dp8390+Rcr, Pro|Ab);
	else
		slowoutb(dp8390->dp8390+Rcr, Ab);
		dp8390outb(dp8390->dp8390+Rcr, Ab);
}

static void


@@ 653,8 670,8 @@ attach(Ether *ether)
	 * mode. Clear the missed-packet counter, it
	 * increments while in monitor mode.
	 */
	slowoutb(dp8390->dp8390+Rcr, Ab);
	slowinb(dp8390->dp8390+Cntr2);
	dp8390outb(dp8390->dp8390+Rcr, Ab);
	dp8390inb(dp8390->dp8390+Cntr2);
}

int


@@ 673,15 690,15 @@ dp8390reset(Ether *ether)
	 */ 
	dp8390disable(dp8390);
	if(dp8390->bit16)
		slowoutb(port+Dcr, Ft4|Ls|Wts);
		dp8390outb(port+Dcr, Ft4|Ls|Wts);
	else
		slowoutb(port+Dcr, Ft4|Ls);
		dp8390outb(port+Dcr, Ft4|Ls);

	slowoutb(port+Rbcr0, 0);
	slowoutb(port+Rbcr1, 0);
	dp8390outb(port+Rbcr0, 0);
	dp8390outb(port+Rbcr1, 0);

	slowoutb(port+Tcr, 0);
	slowoutb(port+Rcr, Mon);
	dp8390outb(port+Tcr, 0);
	dp8390outb(port+Rcr, Mon);

	/*
	 * Init the ring hardware and software ring pointers.


@@ 689,16 706,16 @@ dp8390reset(Ether *ether)
	 * it yet.
	 */
	dp8390ring(dp8390);
	slowoutb(port+Tpsr, dp8390->tstart);
	dp8390outb(port+Tpsr, dp8390->tstart);

	slowoutb(port+Isr, 0xFF);
	slowoutb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
	dp8390outb(port+Isr, 0xFF);
	dp8390outb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);

	/*
	 * Leave the chip initialised,
	 * but in monitor mode.
	 */
	slowoutb(port+Cr, Page0|RDMAabort|Sta);
	dp8390outb(port+Cr, Page0|RDMAabort|Sta);

	/*
	 * Set up the software configuration.