123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "../port/error.h"
- #include "../port/netif.h"
- #include "msaturn.h"
- #include "etherif.h"
- enum{
- Etcr = Saturn + 0x0c00,
- Etsr = Saturn + 0x0c02,
- Ercr = Saturn + 0x0c04,
- Ersr = Saturn + 0x0c06,
- Eisr = Saturn + 0x0d04,
- Eimr = Saturn + 0x0d06,
- Emacaddr0 = Saturn + 0x0e02,
- Miicr = Saturn + 0x0f02,
- Miiwdr = Saturn + 0x0f04,
- Miirdr = Saturn + 0x0f06,
- Ethermem = 0xf2c00000,
- Etherfsize = 0x2000,
- Nrx = 14,
- Ntx = 2, // Nrx + Ntx must be 16
- Ersr_rxfpmask = 0xf,
- Ersr_rxevent = RBIT(0, ushort),
- Etcr_txfpmask = 0xf,
- Ercr_rxenab = RBIT(0, ushort),
- Ercr_auienab = RBIT(2, ushort),
- Etcr_txstart = RBIT(1, ushort),
- Etcr_retries = 0xf<<8,
- Ei_txecall = RBIT(0, ushort),
- Ei_txretry = RBIT(2, ushort),
- Ei_txdefer = RBIT(3, ushort),
- Ei_txcrs = RBIT(4, ushort),
- Ei_txdone = RBIT(5, ushort),
- Ei_rxcrcerr = RBIT(8, ushort),
- Ei_rxdrib = RBIT(9, ushort),
- Ei_rxdone = RBIT(10, ushort),
- Ei_rxshort = RBIT(11, ushort),
- Ei_rxlong = RBIT(12, ushort),
- Miicr_regshift = 6,
- Miicr_read = RBIT(10, ushort),
- Miicr_preambledis = RBIT(12, ushort),
- Miicr_accack = RBIT(14, ushort),
- Miicr_accbsy = RBIT(15, ushort),
- };
- typedef struct {
- Lock;
- int txbusy;
- int txempty;
- int txfull;
- int ntx; /* number of entries in transmit ring */
- int rxlast;
- int active;
- ulong interrupts; /* statistics */
- ulong overflows;
- } Ctlr;
- static ushort*etcr=(ushort*)Etcr;
- static ushort*etsr=(ushort*)Etsr;
- static ushort*ercr=(ushort*)Ercr;
- static ushort*ersr=(ushort*)Ersr;
- static ushort*eimr=(ushort*)Eimr;
- static ushort*eisr=(ushort*)Eisr;
- static ushort*miicr=(ushort*)Miicr;
- static ushort*miirdr=(ushort*)Miirdr;
- static void
- txfill(Ether*ether, Ctlr*ctlr)
- {
- int len;
- Block *b;
- ushort*dst;
- while(ctlr->ntx<Ntx){
- if((b=qget(ether->oq)) == nil)
- break;
- len = BLEN(b);
- dst = (ushort*)(Ethermem+(ctlr->txempty+Nrx)*Etherfsize);
- *dst = len;
- memmove(&dst[1], b->rp, len);
- ctlr->ntx++;
- ctlr->txempty++;
- if(ctlr->txempty==Ntx)
- ctlr->txempty = 0;
- freeb(b);
- }
- }
- static void
- txrestart(Ctlr*ctlr)
- {
- if(ctlr->ntx==0 || ctlr->txbusy)
- return;
- ctlr->txbusy = 1;
- *etcr = Etcr_txstart|Etcr_retries|(ctlr->txfull+Nrx);
- }
- static void interrupt(Ureg*, void*);
- static void
- transmit(Ether*ether)
- {
- Ctlr *ctlr;
- ctlr = ether->ctlr;
- ilock(ctlr);
- txfill(ether, ctlr);
- txrestart(ctlr);
- iunlock(ctlr);
- }
- 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 int
- reset(Ether* ether)
- {
- Ctlr*ctlr;
- *ercr = 0;
- ctlr = malloc(sizeof(*ctlr));
- memset(ctlr, 0, sizeof(*ctlr));
- ctlr->active = 1;
- ether->ctlr = ctlr;
- ether->transmit = transmit;
- ether->interrupt = interrupt;
- ether->irq = Vecether;
- ether->arg = ether;
- memmove(ether->ea, (ushort*)Emacaddr0, Eaddrlen);
- *ercr = Ercr_rxenab|Ercr_auienab|(Nrx-1);
- *eimr = Ei_rxdone|Ei_txretry|Ei_txdone;
-
- iprint("reset: ercr %.4uX\n", *ercr);
- return 0;
- }
- void
- ethersaturnlink(void)
- {
- addethercard("saturn", reset);
- }
|