From e7e01d6c0e78d81dff4b17ffbc6e97848a462fbe Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 15 Feb 2001 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2001-02-15 --- pc/etherwavelan.c | 165 ++++++++++++++++++++-------------------------- 1 file changed, 72 insertions(+), 93 deletions(-) diff --git a/pc/etherwavelan.c b/pc/etherwavelan.c index 5dbd567b36af7bff25bd86ed1888b93b023b2898..b2f8f45a899272126f5b4661dbb74257d09d463a 100644 --- a/pc/etherwavelan.c +++ b/pc/etherwavelan.c @@ -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, <v, 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;