📄 etherfcc.c
字号:
/* * FCCn ethernet */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "imm.h"#include "../port/error.h"#include "../port/netif.h"#include "etherif.h"#include "../ppc/ethermii.h"#define DBG 1enum { Nrdre = 128, /* receive descriptor ring entries */ Ntdre = 128, /* transmit descriptor ring entries */ Rbsize = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */ Bufsize = Rbsize+CACHELINESZ, /* extra room for alignment */};enum { /* ether-specific Rx BD bits */ RxMiss= SBIT(7), RxeLG= SBIT(10), RxeNO= SBIT(11), RxeSH= SBIT(12), RxeCR= SBIT(13), RxeOV= SBIT(14), RxeCL= SBIT(15), RxError= (RxeLG|RxeNO|RxeSH|RxeCR|RxeOV|RxeCL), /* various error flags */ /* ether-specific Tx BD bits */ TxPad= SBIT(1), /* pad short frames */ TxTC= SBIT(5), /* transmit CRC */ TxeDEF= SBIT(6), TxeHB= SBIT(7), TxeLC= SBIT(8), TxeRL= SBIT(9), TxeUN= SBIT(14), TxeCSL= SBIT(15), /* psmr */ CRCE= BIT(24), /* Ethernet CRC */ FCE= BIT(10), /* flow control */ PRO= BIT(9), /* promiscuous mode */ FDE= BIT(5), /* full duplex ethernet */ LPB= BIT(3), /* local protect bit */ /* gfmr */ ENET= 0xc, /* ethernet mode */ ENT= BIT(27), ENR= BIT(26), TCI= BIT(2), /* FCC function code register */ GBL= 0x20, BO= 0x18, EB= 0x10, /* Motorola byte order */ TC2= 0x04, DTB= 0x02, BDB= 0x01, /* FCC Event/Mask bits */ GRA= SBIT(8), RXC= SBIT(9), TXC= SBIT(10), TXE= SBIT(11), RXF= SBIT(12), BSY= SBIT(13), TXB= SBIT(14), RXB= SBIT(15),};enum { /* Mcr */ MDIread = 0x60020000, /* read opcode */ MDIwrite = 0x50020000, /* write opcode */};typedef struct Etherparam Etherparam;struct Etherparam {/*0x00*/ FCCparam;/*0x3c*/ ulong stat_buf;/*0x40*/ ulong cam_ptr;/*0x44*/ ulong cmask;/*0x48*/ ulong cpres;/*0x4c*/ ulong crcec;/*0x50*/ ulong alec;/*0x54*/ ulong disfc;/*0x58*/ ushort retlim;/*0x5a*/ ushort retcnt;/*0x5c*/ ushort p_per;/*0x5e*/ ushort boff_cnt;/*0x60*/ ulong gaddr[2];/*0x68*/ ushort tfcstat;/*0x6a*/ ushort tfclen;/*0x6c*/ ulong tfcptr;/*0x70*/ ushort mflr;/*0x72*/ ushort paddr[3];/*0x78*/ ushort ibd_cnt;/*0x7a*/ ushort ibd_start;/*0x7c*/ ushort ibd_end;/*0x7e*/ ushort tx_len;/*0x80*/ uchar ibd_base[32];/*0xa0*/ ulong iaddr[2];/*0xa8*/ ushort minflr;/*0xaa*/ ushort taddr[3];/*0xb0*/ ushort padptr;/*0xb2*/ ushort Rsvdb2;/*0xb4*/ ushort cf_range;/*0xb6*/ ushort max_b;/*0xb8*/ ushort maxd1;/*0xba*/ ushort maxd2;/*0xbc*/ ushort maxd;/*0xbe*/ ushort dma_cnt;/*0xc0*/ ulong octc;/*0xc4*/ ulong colc;/*0xc8*/ ulong broc;/*0xcc*/ ulong mulc;/*0xd0*/ ulong uspc;/*0xd4*/ ulong frgc;/*0xd8*/ ulong ospc;/*0xdc*/ ulong jbrc;/*0xe0*/ ulong p64c;/*0xe4*/ ulong p65c;/*0xe8*/ ulong p128c;/*0xec*/ ulong p256c;/*0xf0*/ ulong p512c;/*0xf4*/ ulong p1024c;/*0xf8*/ ulong cam_buf;/*0xfc*/ ulong Rsvdfc;/*0x100*/};typedef struct Ctlr Ctlr;struct Ctlr { Lock; int fccid; int port; ulong pmdio; ulong pmdck; int init; int active; int duplex; /* 1 == full */ FCC* fcc; Ring; Block* rcvbufs[Nrdre]; Mii* mii; Timer; ulong interrupts; /* statistics */ ulong deferred; ulong heartbeat; ulong latecoll; ulong retrylim; ulong underrun; ulong overrun; ulong carrierlost; ulong retrycount;};static int fccirq[] = {0x20, 0x21, 0x22};static int fccid[] = {FCC1ID, FCC2ID, FCC3ID};#ifdef DBGulong fccrhisto[16];ulong fccthisto[16];ulong fccrthisto[16];ulong fcctrhisto[16];ulong ehisto[0x80];#endifstatic int fccmiimir(Mii*, int, int);static int fccmiimiw(Mii*, int, int, int);static void fccltimer(Ureg*, Timer*);static voidattach(Ether *ether){ Ctlr *ctlr; ctlr = ether->ctlr; ilock(ctlr); ctlr->active = 1; ctlr->fcc->gfmr |= ENR|ENT; iunlock(ctlr); ctlr->tmode = Tperiodic; ctlr->tf = fccltimer; ctlr->ta = ether; ctlr->tns = 5000000000LL; /* 5 seconds */ timeradd(ctlr);}static voidclosed(Ether *ether){ Ctlr *ctlr; ctlr = ether->ctlr; ilock(ctlr); ctlr->active = 0; ctlr->fcc->gfmr &= ~(ENR|ENT); iunlock(ctlr); print("Ether closed\n");}static voidpromiscuous(void* arg, int on){ Ether *ether; Ctlr *ctlr; ether = (Ether*)arg; ctlr = ether->ctlr; ilock(ctlr); if(on || ether->nmaddr) ctlr->fcc->fpsmr |= PRO; else ctlr->fcc->fpsmr &= ~PRO; iunlock(ctlr);}static voidmulticast(void* arg, uchar *addr, int on){ Ether *ether; Ctlr *ctlr; USED(addr, on); /* if on, could SetGroupAddress; if !on, it's hard */ ether = (Ether*)arg; ctlr = ether->ctlr; ilock(ctlr); if(ether->prom || ether->nmaddr) ctlr->fcc->fpsmr |= PRO; else ctlr->fcc->fpsmr &= ~PRO; iunlock(ctlr);}static voidtxstart(Ether *ether){ int len; Ctlr *ctlr; Block *b; BD *dre; ctlr = ether->ctlr; if(ctlr->init) return; while(ctlr->ntq < Ntdre-1){ b = qget(ether->oq); if(b == 0) break; dre = &ctlr->tdr[ctlr->tdrh]; dczap(dre, sizeof(BD)); if(dre->status & BDReady) panic("ether: txstart"); /* * Give ownership of the descriptor to the chip, increment the * software ring descriptor pointer and tell the chip to poll. */ len = BLEN(b); if(ctlr->txb[ctlr->tdrh] != nil) panic("fcc/ether: txstart"); ctlr->txb[ctlr->tdrh] = b; if((ulong)b->rp&1) panic("fcc/ether: txstart align"); /* TO DO: ensure alignment */ dre->addr = PADDR(b->rp); dre->length = len; dcflush(b->rp, len); dcflush(dre, sizeof(BD)); dre->status = (dre->status & BDWrap) | BDReady|TxPad|BDInt|BDLast|TxTC; dcflush(dre, sizeof(BD));/* ctlr->fcc->ftodr = 1<<15; /* transmit now; Don't do this according to errata */ ctlr->ntq++; ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre); }}static voidtransmit(Ether* ether){ Ctlr *ctlr; ctlr = ether->ctlr; ilock(ctlr); txstart(ether); iunlock(ctlr);}static voidinterrupt(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); }#ifdef DBG if(rcvd >= nelem(fccrhisto)) rcvd = nelem(fccrhisto) - 1; if(xmtd >= nelem(fccthisto)) xmtd = nelem(fccthisto) - 1; if(rcvd) fcctrhisto[xmtd]++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -