static int smscreceive(Dev *ep) { Block *b; uint hd; int n; if(Doburst) b = allocb(Hsburst*512); else b = allocb(Maxpkt+4); if((n = read(ep->dfd, b->wp, b->lim - b->base)) < 0){ freeb(b); return -1; } b->wp += n; while(BLEN(b) >= 4){ hd = GET4(b->rp); b->rp += 4; n = hd >> 16; if(n > BLEN(b)) break; if((hd & Rxerror) == 0){ if(n == BLEN(b)){ etheriq(b, 1); return 0; } etheriq(copyblock(b, n), 1); } b->rp += (n + 3) & ~3; } freeb(b); return 0; }
static void w_rxdone(Ether* ether) { Ctlr* ctlr = (Ctlr*) ether->ctlr; int len, sp; WFrame f; Block* bp=0; Etherpkt* ep; sp = csr_ins(ctlr, WR_RXId); len = w_read(ctlr, sp, 0, &f, sizeof(f)); if(len == 0){ DEBUG("wavelan: read frame error\n"); goto rxerror; } if(f.sts&WF_Err){ goto rxerror; } switch(f.sts){ case WF_1042: case WF_Tunnel: case WF_WMP: len = f.dlen + WSnapHdrLen; bp = iallocb(ETHERHDRSIZE + len + 2); if(!bp) goto rxerror; ep = (Etherpkt*) bp->wp; memmove(ep->d, f.addr1, Eaddrlen); memmove(ep->s, f.addr2, Eaddrlen); memmove(ep->type,&f.type,2); bp->wp += ETHERHDRSIZE; if(w_read(ctlr, sp, WF_802_11_Off, bp->wp, len+2) == 0){ DEBUG("wavelan: read 802.11 error\n"); goto rxerror; } bp->wp = bp->rp+(ETHERHDRSIZE+f.dlen); break; default: len = ETHERHDRSIZE + f.dlen + 2; bp = iallocb(len); if(!bp) goto rxerror; if(w_read(ctlr, sp, WF_802_3_Off, bp->wp, len) == 0){ DEBUG("wavelan: read 800.3 error\n"); goto rxerror; } bp->wp += len; } ctlr->nrx++; etheriq(ether,bp,1); ctlr->signal = ((ctlr->signal*15)+((f.qinfo>>8) & 0xFF))/16; ctlr->noise = ((ctlr->noise*15)+(f.qinfo & 0xFF))/16; return; rxerror: freeb(bp); ctlr->nrxerr++; }
static void receive(Ether *ether) { int i; ulong n; Block *b; Ctlr *ctlr = ether->ctlr; Rx *r; ethercheck(ether); for (i = Nrx-2; i > 0; i--) { r = &ctlr->rx[ctlr->rxhead]; /* *r is uncached */ assert(((uintptr)r & (Descralign - 1)) == 0); if(r->cs & RCSdmaown) /* descriptor busy? */ break; b = ctlr->rxb[ctlr->rxhead]; /* got input buffer? */ if (b == nil) panic("ether1116: nil ctlr->rxb[ctlr->rxhead] " "in receive"); ctlr->rxb[ctlr->rxhead] = nil; ctlr->rxhead = NEXT(ctlr->rxhead, Nrx); if((r->cs & (RCSfirst|RCSlast)) != (RCSfirst|RCSlast)) { ctlr->nofirstlast++; /* partial packet */ freeb(b); continue; } if(r->cs & RCSmacerr) { freeb(b); continue; } n = r->countsize >> 16; /* TODO includes 2 pad bytes? */ assert(n >= 2 && n < 2048); /* clear any cached packet or part thereof */ l2cacheuinvse(b->rp, n+2); cachedinvse(b->rp, n+2); b->wp = b->rp + n; /* * skip hardware padding intended to align ipv4 address * in memory (mv-s104860-u0 §8.3.4.1) */ b->rp += 2; etheriq(ether, b, 1); etheractive(ether); if (i % (Nrx / 2) == 0) { rxreplenish(ctlr); rxkick(ctlr); } } rxreplenish(ctlr); rxkick(ctlr); }
void wifiiq(Wifi *wifi, Block *b) { SNAP s; Wifipkt h, *w; Etherpkt *e; int hdrlen; if(BLEN(b) < WIFIHDRSIZE) goto drop; w = (Wifipkt*)b->rp; hdrlen = wifihdrlen(w); if(BLEN(b) < hdrlen) goto drop; if(w->fc[1] & 0x40) { /* encrypted */ qpass(wifi->iq, b); return; } switch(w->fc[0] & 0x0c) { case 0x00: /* management */ if((w->fc[1] & 3) != 0x00) /* STA->STA */ break; qpass(wifi->iq, b); return; case 0x04: /* control */ break; case 0x08: /* data */ b->rp += hdrlen; switch(w->fc[0] & 0xf0) { default: goto drop; case 0x80: /* QOS */ case 0x00: break; } if(BLEN(b) < SNAPHDRSIZE) break; memmove(&s, b->rp, SNAPHDRSIZE); if(s.dsap != 0xAA || s.ssap != 0xAA || s.control != 3) break; if(s.orgcode[0] != 0 || s.orgcode[1] != 0 || s.orgcode[2] != 0) break; b->rp += SNAPHDRSIZE-ETHERHDRSIZE; h = *w; e = (Etherpkt*)b->rp; memmove(e->d, dstaddr(&h), Eaddrlen); memmove(e->s, srcaddr(&h), Eaddrlen); memmove(e->type, s.type, 2); etheriq(wifi->ether, b, 1); return; } drop: freeb(b); }
static void receive(Ether* ether) { int port; Block* bp; int pktno, status, len; /* assumes ctlr is locked and bank 2 is selected */ /* leaves bank 2 selected on return */ port = ether->port; pktno = ins(port + FifoPorts); if (pktno & FpRxEmpty) { return; } outs(port + Pointer, PtrRead | PtrRcv | PtrAutoInc); status = ins(port + Data1); len = ins(port + Data1) & RxLenMask - HdrSize; if (status & RsOddFrame) len++; if ((status & RsError) || (bp = iallocb(len)) == 0) { if (status & RsAlgnErr) ether->frames++; if (status & (RsTooShort | RsTooLong)) ether->buffs++; if (status & RsBadCrc) ether->crcs++; outs(port + MmuCmd, McRelease); return; } /* packet length is padded to word */ inss(port + Data1, bp->rp, len / 2); bp->wp = bp->rp + (len & ~1); if (len & 1) { *bp->wp = inb(port + Data1); bp->wp++; } etheriq(ether, bp, 1); ether->inpackets++; outs(port + MmuCmd, McRelease); }
static void vgberxeof(Ether* edev) { Ctlr* ctlr; int i; Block* block; ulong length, status; RxDesc* desc; ctlr = edev->ctlr; if(ctlr->debugflags & DumpRx) print("vgbe: rx_eof\n"); for(i = 0; i < RxCount; i++){ /* Remember that block. */ desc = &ctlr->rx_ring[i]; status = le32toh(desc->status); if(status & RxDesc_Status_Own) continue; if(status & RxDesc_Status_Goodframe){ length = status >> RxDesc_Status_SizShift; length &= RxDesc_Status_SizMask; if(ctlr->debugflags & DumpRx) print("vgbe: Rx-desc[%03d] status=%#08ulx ctl=%#08ulx len=%uld bytes\n", i, status, desc->control, length); block = ctlr->rx_blocks[i]; block->wp = block->rp + length; ctlr->stats.rx++; etheriq(edev, block, 1); } else
static void vt6102receive(Ether* edev) { Ds *ds; Block *bp; Ctlr *ctlr; int i, len; ctlr = edev->ctlr; ds = ctlr->rdh; while(!(ds->status & Own) && ds->status != 0){ if(ds->status & Rerr){ for(i = 0; i < Nrxstats; i++){ if(ds->status & (1<<i)) ctlr->rxstats[i]++; } } else if(bp = iallocb(Rdbsz+3)){ len = ((ds->status & LengthMASK)>>LengthSHIFT)-4; ds->bp->wp = ds->bp->rp+len; etheriq(edev, ds->bp, 1); bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4); ds->addr = PCIWADDR(bp->rp); ds->bp = bp; } ds->control = Rdbsz; ds->branch = 0; ds->status = 0; ds->prev->branch = PCIWADDR(ds); coherence(); ds->prev->status = Own; ds = ds->next; }
static void interrupt(Ureg*, void* arg) { Ctlr *ctlr; Ether *ether; int len, status; Des *des; Block *bp; ether = arg; ctlr = ether->ctlr; while((status = csr32r(ctlr, 5)) & (Nis|Ais)){ /* * Acknowledge the interrupts and mask-out * the ones that are implicitly handled. */ csr32w(ctlr, 5, status); status &= (ctlr->mask & ~(Nis|Ti)); if(status & Ais){ if(status & Tps) ctlr->tps++; if(status & Tu) ctlr->tu++; if(status & Tjt) ctlr->tjt++; if(status & Ru) ctlr->ru++; if(status & Rps) ctlr->rps++; if(status & Rwt) ctlr->rwt++; status &= ~(Ais|Rwt|Rps|Ru|Tjt|Tu|Tps); } /* * Received packets. */ if(status & Ri){ des = &ctlr->rdr[ctlr->rdrx]; while(!(des->status & Own)){ if(des->status & Es){ if(des->status & Of) ctlr->of++; if(des->status & Ce) ctlr->ce++; if(des->status & Cs) ctlr->cs++; if(des->status & Tl) ctlr->tl++; if(des->status & Rf) ctlr->rf++; if(des->status & De) ctlr->de++; } else if(bp = iallocb(Rbsz)){ len = ((des->status & Fl)>>16)-4; des->bp->wp = des->bp->rp+len; etheriq(ether, des->bp, 1); des->bp = bp; des->addr = PCIWADDR(bp->rp); } des->control &= Er; des->control |= Rbsz; coherence(); des->status = Own; ctlr->rdrx = NEXT(ctlr->rdrx, ctlr->nrdr); des = &ctlr->rdr[ctlr->rdrx]; } status &= ~Ri; }
static void interrupt(Ureg*, void*arg) { Ctlr*ctlr; Ether*ether = arg; Etherpkt*pkt; ushort ie; int rx, len; Block *b; ctlr = ether->ctlr; if(!ctlr->active) return; /* not ours */ ctlr->interrupts++; ilock(ctlr); ie = *eisr; *eisr = ie; intack(); if(ie==0) iprint("interrupt: no interrupt source?\n"); if(ie&Ei_txdone){ if((*etcr&Etcr_txstart)==0){ if(ctlr->txbusy){ ctlr->txbusy = 0; ctlr->ntx--; ctlr->txfull++; if(ctlr->txfull==Ntx) ctlr->txfull = 0; } txrestart(ctlr); txfill(ether, ctlr); txrestart(ctlr); } else iprint("interrupt: bogus tx interrupt\n"); ie &= ~Ei_txdone; } if(ie&Ei_rxdone){ rx=*ersr&Ersr_rxfpmask; while(ctlr->rxlast!=rx){ ctlr->rxlast++; if(ctlr->rxlast >= Nrx) ctlr->rxlast = 0; pkt = (Etherpkt*)(Ethermem+ctlr->rxlast*Etherfsize); len = *(ushort*)pkt; if((b = iallocb(len+sizeof(ushort))) != nil){ memmove(b->wp, pkt, len+sizeof(ushort)); b->rp += sizeof(ushort); b->wp = b->rp + len; etheriq(ether, b, 1); }else ether->soverflows++; rx=*ersr&Ersr_rxfpmask; } ie &= ~Ei_rxdone; } if(ie&Ei_txretry){ iprint("ethersaturn: txretry!\n"); ie &= ~Ei_txretry; ctlr->txbusy = 0; txrestart(ctlr); } ie &= ~Ei_txcrs; if(ie) iprint("interrupt: unhandled interrupts %.4uX\n", ie); iunlock(ctlr); }
static void interrupt(Ureg*, void *arg) { int len, status, rcvd, xmtd, restart; ushort events; Ctlr *ctlr; BD *dre; Block *b, *nb; Ether *ether = arg; ctlr = ether->ctlr; if(!ctlr->active) return; /* not ours */ /* * Acknowledge all interrupts and whine about those that shouldn't * happen. */ events = ctlr->fcc->fcce; ctlr->fcc->fcce = events; /* clear events */ #ifdef DBG ehisto[events & 0x7f]++; #endif ctlr->interrupts++; if(events & BSY) ctlr->overrun++; if(events & TXE) ether->oerrs++; #ifdef DBG rcvd = xmtd = 0; #endif /* * Receiver interrupt: run round the descriptor ring logging * errors and passing valid receive data up to the higher levels * until we encounter a descriptor still owned by the chip. */ if(events & RXF){ dre = &ctlr->rdr[ctlr->rdrx]; dczap(dre, sizeof(BD)); while(((status = dre->status) & BDEmpty) == 0){ rcvd++; if(status & RxError || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){ if(status & (RxeLG|RxeSH)) ether->buffs++; if(status & RxeNO) ether->frames++; if(status & RxeCR) ether->crcs++; if(status & RxeOV) ether->overflows++; print("eth rx: %ux\n", status); }else{ /* * We have a packet. Read it in. */ len = dre->length-4; b = ctlr->rcvbufs[ctlr->rdrx]; assert(dre->addr == PADDR(b->rp)); dczap(b->rp, len); if(nb = iallocb(Bufsize)){ b->wp += len; etheriq(ether, b, 1); b = nb; b->rp = (uchar*)(((ulong)b->rp + CACHELINESZ-1) & ~(CACHELINESZ-1)); b->wp = b->rp; ctlr->rcvbufs[ctlr->rdrx] = b; ctlr->rdr[ctlr->rdrx].addr = PADDR(b->wp); }else ether->soverflows++; } /* * Finished with this descriptor, reinitialise it, * give it back to the chip, then on to the next... */ dre->length = 0; dre->status = (status & BDWrap) | BDEmpty | BDInt; dcflush(dre, sizeof(BD)); ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre); dre = &ctlr->rdr[ctlr->rdrx]; dczap(dre, sizeof(BD)); } } /* * Transmitter interrupt: handle anything queued for a free descriptor. */ if(events & (TXB|TXE)){ ilock(ctlr); restart = 0; while(ctlr->ntq){ dre = &ctlr->tdr[ctlr->tdri]; dczap(dre, sizeof(BD)); status = dre->status; if(status & BDReady) break; if(status & TxeDEF) ctlr->deferred++; if(status & TxeHB) ctlr->heartbeat++; if(status & TxeLC) ctlr->latecoll++; if(status & TxeRL) ctlr->retrylim++; if(status & TxeUN) ctlr->underrun++; if(status & TxeCSL) ctlr->carrierlost++; if(status & (TxeLC|TxeRL|TxeUN)) restart = 1; ctlr->retrycount += (status>>2)&0xF; b = ctlr->txb[ctlr->tdri]; if(b == nil) panic("fcce/interrupt: bufp"); ctlr->txb[ctlr->tdri] = nil; freeb(b); ctlr->ntq--; ctlr->tdri = NEXT(ctlr->tdri, Ntdre); xmtd++; } if(restart){ ctlr->fcc->gfmr &= ~ENT; delay(10); ctlr->fcc->gfmr |= ENT; cpmop(RestartTx, ctlr->fccid, 0xc); } txstart(ether); iunlock(ctlr); }