~kris/9p

9hist

e7e01d6c0e78d81dff4b17ffbc6e97848a462fbe — David du Colombier 25 years ago def0bd0
Plan 9 from Bell Labs 2001-02-15
1 files changed, 72 insertions(+), 93 deletions(-)

M pc/etherwavelan.c
M pc/etherwavelan.c => pc/etherwavelan.c +72 -93
@@ 1,8 1,8 @@
/*
	Lucent Wavelan IEEE 802.11 pcmcia.
	There is almost no documentation for the card.
	the driver is done using both the freebsd and the linux
	driver as `documentation'.
	the driver is done using both the FreeBSD, Linux and
	original Plan 9 drivers as `documentation'.

	Has been used with the card plugged in during all up time.
	no cards removals/insertions yet.


@@ 12,10 12,10 @@
	long. When it gets robust, locks should be revisited.

	BUGS: check endian, alignment and mem/io issues;
	      multicast;
	      receive watchdog interrupts.
	TODO: automatic power management;
	      improve locking;
	      remove copy in transmit.
	      improve locking.
 */
#include "u.h"
#include "../port/lib.h"


@@ 123,7 123,7 @@ enum
enum
{
	WDfltIRQ	= 3,		// default irq
	WDfltIOB	= 0x100,	// default IO base
	WDfltIOB	= 0x180,	// default IO base

	WIOLen		= 0x40,		// Hermes IO length



@@ 150,13 150,14 @@ enum
		WCmdIni		= 0x0000,
		WCmdEna		= 0x0001,
		WCmdDis		= 0x0002,
		WCmdTx		= 0x000b,
		WCmdMalloc	= 0x000a,
		WCmdAskStats	= 0x0011,
		WCmdMsk		= 0x003f,
		WCmdAccRd	= 0x0021,
		WCmdReclaim	= 0x0100,
		WCmdAccWr	= 0x0121,
		WCmdBusy	= 0x8000,
		WCmdTxFree	= 0x000b|0x0100,
	WR_Parm0	= 0x02,
	WR_Parm1	= 0x04,
	WR_Parm2	= 0x06,


@@ 289,7 290,6 @@ struct Ctlr
	char	nodename[WNameLen];
	WFrame	txf;
	uchar	txbuf[1536];
	int	txlen;

	int	hascrypt;		// card has encryption
	int	crypt;			// encryption off/on


@@ 572,7 572,7 @@ w_enable(Ether* ether)
	ctlr->txmid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8);
	if (ctlr->txdid == -1 || ctlr->txmid == -1)
		DEBUG("wavelan: alloc failed");
	ctlr->txbusy= 0;
	ctlr->txbusy = 0;
	w_intena(ctlr);
	return 0;
}


@@ 637,85 637,68 @@ rxerror:
	ctlr->nrxerr++;
}

static int
w_txstart(Ether* ether, int again)
static void
w_txstart(Ether* ether)
{
	Etherpkt* ep;
	Ctlr* ctlr = (Ctlr*) ether->ctlr;
	Block* bp;
	int txid;
	Etherpkt *pkt;
	Ctlr *ctlr;
	Block *bp;
	int len, off;

	if (ctlr == 0 || ctlr->attached == 0 )
		return -1;
	if (ctlr->txbusy && again==0)
		return -1;
	if((ctlr = ether->ctlr) == nil || ctlr->attached == 0 || ctlr->txbusy)
		return;

	if (again){
		bp = 0;		// a watchdog reenabled the card.
		goto retry;	// must retry a previously failed tx.
	}
	if((bp = qget(ether->oq)) == nil)
		return;
	pkt = (Etherpkt*)bp->rp;

	bp = qget(ether->oq);
	if (bp == 0)
		return 0;
	ep = (Etherpkt*) bp->rp;
	ctlr->txbusy = 1;

	// BUG: only IP/ARP/RARP seem to be ok for 802.3
	// Other packets should be just copied to the board.
	// The driver is not doing so, though.
	// Besides, the Block should be used instead of txbuf,
	// to save a memory copy.
	memset(ctlr->txbuf,0,sizeof(ctlr->txbuf));
	memset(&ctlr->txf,0,sizeof(ctlr->txf));
	ctlr->txf.framectl = WF_Data;
	memmove(ctlr->txf.addr1, ep->d, Eaddrlen);
	memmove(ctlr->txf.addr2, ep->s, Eaddrlen);
	memmove(ctlr->txf.dstaddr, ep->d, Eaddrlen);
	memmove(ctlr->txf.srcaddr, ep->s, Eaddrlen);
	memmove(&ctlr->txf.type,ep->type,2);
	ctlr->txlen = BLEN(bp);
	ctlr->txf.dlen = ctlr->txlen - WSnapHdrLen;
	hnputs((uchar*)&ctlr->txf.dat[0], WSnap0);
	hnputs((uchar*)&ctlr->txf.dat[1], WSnap1);
	hnputs((uchar*)&ctlr->txf.len, ctlr->txlen - WSnapHdrLen);
	if (ctlr->txlen - ETHERHDRSIZE > 1536){
		print("wavelan: txbuf overflow");
		freeb(bp);
		return -1;
	//
	// If the packet header type field is > 1500 it is an IP or
	// ARP datagram, otherwise it is an 802.3 packet. See RFC1042.
	//
	memset(&ctlr->txf, 0, sizeof(ctlr->txf));
	if(((pkt->type[0]<<8)|pkt->type[1]) > 1500){
		ctlr->txf.framectl = WF_Data;
		memmove(ctlr->txf.addr1, pkt->d, Eaddrlen);
		memmove(ctlr->txf.addr2, pkt->s, Eaddrlen);
		memmove(ctlr->txf.dstaddr, pkt->d, Eaddrlen);
		memmove(ctlr->txf.srcaddr, pkt->s, Eaddrlen);
		memmove(&ctlr->txf.type, pkt->type, 2);
		bp->rp += ETHERHDRSIZE;
		len = BLEN(bp);
		off = WF_802_11_Off;
		ctlr->txf.dlen = len+ETHERHDRSIZE-WSnapHdrLen;
		hnputs((uchar*)&ctlr->txf.dat[0], WSnap0);
		hnputs((uchar*)&ctlr->txf.dat[1], WSnap1);
		hnputs((uchar*)&ctlr->txf.len, len+ETHERHDRSIZE-WSnapHdrLen);
	}
	else{
		len = BLEN(bp);
		off = WF_802_3_Off;
		ctlr->txf.dlen = len;
	}
	memmove(ctlr->txbuf, bp->rp+sizeof(ETHERHDRSIZE)+10,
			ctlr->txlen - ETHERHDRSIZE);
retry:
	txid = ctlr->txdid;
	w_write(ctlr, txid, 0, &ctlr->txf, sizeof(ctlr->txf));

	w_write(ctlr, txid, WF_802_11_Off, ctlr->txbuf,
			ctlr->txlen - ETHERHDRSIZE + 2);
	if (w_cmd(ctlr, WCmdTxFree, txid)){
	w_write(ctlr, ctlr->txdid, 0, &ctlr->txf, sizeof(ctlr->txf));
	w_write(ctlr, ctlr->txdid, off, bp->rp, len+2);

	if(w_cmd(ctlr, WCmdReclaim|WCmdTx, ctlr->txdid)){
		DEBUG("wavelan: transmit failed\n");
		ctlr->txbusy=0;	// added
		ctlr->ntxerr++;
		freeb(bp);
		return -1;
	}
	ctlr->txtmout = 2;
	else{
		ctlr->txbusy = 1;
		ctlr->txtmout = 2;
	}
	freeb(bp);
	return 0;
}

static void
w_txdone(Ctlr* ctlr, int sts)
{
	int b = ctlr->txbusy;

	ctlr->txbusy = 0;
	ctlr->txtmout= 0;
	if (sts & WTxErrEv){
	ctlr->txtmout = 0;
	if (sts & WTxErrEv)
		ctlr->ntxerr++;
		if (sts&1) // it was a watchdog, stay busy to retry.
			ctlr->txbusy = b;
	} else
	else
		ctlr->ntx++;
}



@@ 725,14 708,14 @@ w_stats(Ctlr* ctlr)
	int i, rc, sp;
	Wltv ltv;
	ulong* p = (ulong*)&ctlr->WStats;
	ulong* pend= (ulong*)&ctlr->end;
	ulong* pend = (ulong*)&ctlr->end;

	sp = csr_ins(ctlr, WR_InfoId);
	ltv.len = ltv.type = 0;
	w_read(ctlr, sp, 0, &ltv, 4);
	if (ltv.type == WTyp_Stats){
		ltv.len--;
		for (i = 0; i < ltv.len && p < pend ; i++){
		for (i = 0; i < ltv.len && p < pend; i++){
			rc = csr_ins(ctlr, WR_Data1);
			if (rc > 0xf000)
				rc = ~rc & 0xffff;


@@ 791,7 774,7 @@ w_intr(Ether *ether)
	}

	w_intena(ctlr);
	w_txstart(ether,0);
	w_txstart(ether);
}

// Watcher to ensure that the card still works properly and


@@ 838,12 821,11 @@ w_timer(void* arg)
		if ((ctlr->ticks % 10) == 0) {
			if (ctlr->txtmout && --ctlr->txtmout == 0){
				ctlr->nwatchdogs++;
				w_txdone(ctlr, WTxErrEv|1); // 1: keep it busy
				w_txdone(ctlr, WTxErrEv);
				if (w_enable(ether)){
					DEBUG("wavelan: wdog enable failed\n");
				}
				if (ctlr->txbusy)
					w_txstart(ether,1);
				w_txstart(ether);
			}
			if ((ctlr->ticks % 120) == 0)
			if (ctlr->txbusy == 0)


@@ 1045,11 1027,11 @@ option(Ctlr* ctlr, char* buf, long n)
	}
	else if(cistrcmp(cb->f[0], "mode") == 0){
		if(cistrcmp(cb->f[1], "managed") == 0)
			ctlr->ptype = 1;
			ctlr->ptype = WPTypeManaged;
		else if(cistrcmp(cb->f[1], "wds") == 0)
			ctlr->ptype = 2;
			ctlr->ptype = WPTypeWDS;
		else if(cistrcmp(cb->f[1], "adhoc") == 0)
			ctlr->ptype = 3;
			ctlr->ptype = WPTypeAdHoc;
		else if((i = atoi(cb->f[1])) >= 1 && i <= 3)
			ctlr->ptype = i;
		else


@@ 1127,8 1109,9 @@ ctl(Ether* ether, void* buf, long n)
		error(Ebadctl);
	}
	if(ctlr->txbusy)
		w_txdone(ctlr, WTxErrEv|1);	// retry tx later.
		w_txdone(ctlr, WTxErrEv);
	w_enable(ether);
	w_txstart(ether);
	iunlock(&ctlr->Lock);

	return n;


@@ 1144,7 1127,7 @@ transmit(Ether* ether)

	ilock(&ctlr->Lock);
	ctlr->ntxrq++;
	w_txstart(ether,0);
	w_txstart(ether);
	iunlock(&ctlr->Lock);
}



@@ 1211,8 1194,8 @@ reset(Ether* ether)
		DEBUG("no wavelan found\n");
		goto abort;
	}
	DEBUG("#l%d: port=0x%lx irq=%ld\n",
			ether->ctlrno, ether->port, ether->irq);
//	DEBUG("#l%d: port=0x%lx irq=%ld\n",
//			ether->ctlrno, ether->port, ether->irq);

	w_intdis(ctlr);
	if (w_cmd(ctlr,WCmdIni,0)){


@@ 1255,10 1238,6 @@ reset(Ether* ether)
		goto abort;
	}
	memmove(ether->ea, ltv.addr, Eaddrlen);
	DEBUG("#l%d: %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n",
			ether->ctlrno,
			ether->ea[0], ether->ea[1], ether->ea[2],
			ether->ea[3], ether->ea[4], ether->ea[5]);

	if (ctlr->chan == 0)
		ctlr->chan = ltv_ins(ctlr, WTyp_Chan);


@@ 1283,11 1262,11 @@ reset(Ether* ether)
	ether->multicast = multicast;
	ether->arg = ether;

	DEBUG("#l%d: irq %ld port %lx type %s",
		ether->ctlrno, ether->irq, ether->port,	ether->type);
	DEBUG(" %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n",
		ether->ea[0], ether->ea[1], ether->ea[2],
		ether->ea[3], ether->ea[4], ether->ea[5]);
//	DEBUG("#l%d: irq %ld port %lx type %s",
//		ether->ctlrno, ether->irq, ether->port,	ether->type);
//	DEBUG(" %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n",
//		ether->ea[0], ether->ea[1], ether->ea[2],
//		ether->ea[3], ether->ea[4], ether->ea[5]);

	iunlock(&ctlr->Lock);
	return 0;