## diffname mpc/etherscc.c 1999/0122
## diff -e /dev/null /n/emeliedump/1999/0122/sys/src/brazil/mpc/etherscc.c
0a
/*
* SCCn ethernet
*/
#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 "etherif.h"
enum {
Nrdre = 16, /* receive descriptor ring entries */
Ntdre = 16, /* transmit descriptor ring entries */
Rbsize = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */
Bufsize = (Rbsize+7)&~7, /* aligned */
};
enum {
/* ether-specific Rx BD bits */
RxMiss= 1<<8,
RxeLG= 1<<5,
RxeNO= 1<<4,
RxeSH= 1<<3,
RxeCR= 1<<2,
RxeOV= 1<<1,
RxeCL= 1<<0,
RxError= (RxeLG|RxeNO|RxeSH|RxeCR|RxeOV|RxeCL), /* various error flags */
/* ether-specific Tx BD bits */
TxPad= 1<<14, /* pad short frames */
TxTC= 1<<10, /* transmit CRC */
TxeDEF= 1<<9,
TxeHB= 1<<8,
TxeLC= 1<<7,
TxeRL= 1<<6,
TxeUN= 1<<1,
TxeCSL= 1<<0,
/* scce */
RXB= 1<<0,
TXB= 1<<1,
BSY= 1<<2,
RXF= 1<<3,
TXE= 1<<4,
/* psmr */
PRO= 1<<9, /* promiscuous mode */
/* gsmrl */
ENR= 1<<5,
ENT= 1<<4,
};
typedef struct Etherparam Etherparam;
struct Etherparam {
SCCparam;
ulong c_pres; /* preset CRC */
ulong c_mask; /* constant mask for CRC */
ulong crcec; /* CRC error counter */
ulong alec; /* alighnment error counter */
ulong disfc; /* discard frame counter */
ushort pads; /* short frame PAD characters */
ushort ret_lim; /* retry limit threshold */
ushort ret_cnt; /* retry limit counter */
ushort mflr; /* maximum frame length reg */
ushort minflr; /* minimum frame length reg */
ushort maxd1; /* maximum DMA1 length reg */
ushort maxd2; /* maximum DMA2 length reg */
ushort maxd; /* rx max DMA */
ushort dma_cnt; /* rx dma counter */
ushort max_b; /* max bd byte count */
ushort gaddr[4]; /* group address filter */
ulong tbuf0_data0; /* save area 0 - current frm */
ulong tbuf0_data1; /* save area 1 - current frm */
ulong tbuf0_rba0;
ulong tbuf0_crc;
ushort tbuf0_bcnt;
ushort paddr[3]; /* physical address LSB to MSB increasing */
ushort p_per; /* persistence */
ushort rfbd_ptr; /* rx first bd pointer */
ushort tfbd_ptr; /* tx first bd pointer */
ushort tlbd_ptr; /* tx last bd pointer */
ulong tbuf1_data0; /* save area 0 - next frame */
ulong tbuf1_data1; /* save area 1 - next frame */
ulong tbuf1_rba0;
ulong tbuf1_crc;
ushort tbuf1_bcnt;
ushort tx_len; /* tx frame length counter */
ushort iaddr[4]; /* individual address filter*/
ushort boff_cnt; /* back-off counter */
ushort taddr[3]; /* temp address */
};
typedef struct {
Lock;
int sccid;
int port;
int init;
int active;
SCC* scc;
Ring;
ulong interrupts; /* statistics */
ulong deferred;
ulong heartbeat;
ulong latecoll;
ulong retrylim;
ulong underrun;
ulong overrun;
ulong carrierlost;
ulong retrycount;
} Ctlr;
static int sccirq[] = {-1, 0x1E, 0x1D, 0x1C, 0x1B};
static int sccid[] = {-1, SCC1ID, SCC2ID, SCC3ID, SCC4ID};
static int sccbase[] = {-1, 0xA00, 0xA20, 0xA40, 0xA60};
static int sccparam[] = {-1, SCC1P, SCC2P, SCC3P, SCC4P};
static void
attach(Ether *ether)
{
Ctlr *ctlr;
ctlr = ether->ctlr;
ctlr->active = 1;
ctlr->scc->gsmrl |= ENR|ENT;
eieio();
// m->bcsr[1] &= ~DisableEther;
}
static void
closed(Ether *ether)
{
Ctlr *ctlr;
ctlr = ether->ctlr;
if(0){
if(ether->port == 2)
scc2stop(ctlr->scc);
ilock(ctlr);
ctlr->active = 0;
iunlock(ctlr);
print("Ether closed\n");
}
}
static void
promiscuous(void* arg, int on)
{
Ether *ether;
Ctlr *ctlr;
ether = (Ether*)arg;
ctlr = ether->ctlr;
ilock(ctlr);
if(on || ether->nmaddr)
ctlr->scc->psmr |= PRO;
else
ctlr->scc->psmr &= ~PRO;
iunlock(ctlr);
}
static void
multicast(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->scc->psmr |= PRO;
else
ctlr->scc->psmr &= ~PRO;
iunlock(ctlr);
}
static void
txstart(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];
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);
dcflush(b->rp, len);
if(ctlr->txb[ctlr->tdrh] != nil)
panic("scc/ether: txstart");
ctlr->txb[ctlr->tdrh] = b;
if((ulong)b->rp&1)
panic("scc/ether: txstart align"); /* TO DO: ensure alignment */
dre->addr = PADDR(b->rp);
dre->length = len;
eieio();
dre->status = (dre->status & BDWrap) | BDReady|TxPad|BDInt|BDLast|TxTC;
eieio();
ctlr->scc->todr = 1<<15; /* transmit now */
eieio();
ctlr->ntq++;
ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
}
}
static void
transmit(Ether* ether)
{
Ctlr *ctlr;
ctlr = ether->ctlr;
ilock(ctlr);
txstart(ether);
iunlock(ctlr);
}
static void
interrupt(Ureg*, Ether *ether)
{
int len, events, status;
Ctlr *ctlr;
BD *dre;
Block *b;
ctlr = ether->ctlr;
if(!ctlr->active)
return; /* not ours */
/*
* Acknowledge all interrupts and whine about those that shouldn't
* happen.
*/
events = ctlr->scc->scce;
eieio();
ctlr->scc->scce = events;
eieio();
ctlr->interrupts++;
if(events & (TXE|BSY|RXB)){
if(events & RXB)
ctlr->overrun++;
if(events & TXE)
ether->oerrs++;
if(0 || events & TXE)
print("ETHER.SCC#%d: scce = 0x%uX\n", ether->ctlrno, events);
}
/*
* 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|RXB) || 1){
dre = &ctlr->rdr[ctlr->rdrx];
while(((status = dre->status) & BDEmpty) == 0){
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;
if((b = iallocb(len)) != 0){
memmove(b->wp, KADDR(dre->addr), len);
b->wp += len;
etheriq(ether, b, 1);
dcflush(KADDR(dre->addr), len);
}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;
eieio();
ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
dre = &ctlr->rdr[ctlr->rdrx];
}
}
/*
* Transmitter interrupt: handle anything queued for a free descriptor.
*/
if(events & TXB){
lock(ctlr);
while(ctlr->ntq){
dre = &ctlr->tdr[ctlr->tdri];
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++;
ctlr->retrycount += (status>>2)&0xF;
b = ctlr->txb[ctlr->tdri];
if(b == nil)
panic("scce/interrupt: bufp");
ctlr->txb[ctlr->tdri] = nil;
freeb(b);
ctlr->ntq--;
ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
}
txstart(ether);
unlock(ctlr);
}
if(events & TXE)
cpmop(RestartTx, ctlr->sccid, 0);
}
static long
ifstat(Ether* ether, void* a, long n, ulong offset)
{
char *p;
int len;
Ctlr *ctlr;
if(n == 0)
return 0;
ctlr = ether->ctlr;
p = malloc(READSTR);
len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts);
len += snprint(p+len, READSTR-len, "carrierlost: %lud\n", ctlr->carrierlost);
len += snprint(p+len, READSTR-len, "heartbeat: %lud\n", ctlr->heartbeat);
len += snprint(p+len, READSTR-len, "retrylimit: %lud\n", ctlr->retrylim);
len += snprint(p+len, READSTR-len, "retrycount: %lud\n", ctlr->retrycount);
len += snprint(p+len, READSTR-len, "latecollisions: %lud\n", ctlr->latecoll);
len += snprint(p+len, READSTR-len, "rxoverruns: %lud\n", ctlr->overrun);
len += snprint(p+len, READSTR-len, "txunderruns: %lud\n", ctlr->underrun);
snprint(p+len, READSTR-len, "framesdeferred: %lud\n", ctlr->deferred);
n = readstr(offset, a, n, p);
free(p);
return n;
}
/*
* This follows the MPC823 user guide: section16.9.23.7's initialisation sequence,
* except that it sets the right bits for the MPC823ADS board when SCC2 is used,
* and those for the 860/821 development board for SCC1.
*/
static void
sccsetup(Ctlr *ctlr, SCC *scc, uchar *ea)
{
int i, rcs, tcs;
Etherparam *p;
IMM *io;
io = ioplock();
if(ctlr->port == 2){
io->papar |= SIBIT(12)|SIBIT(13); /* enable TXD2 and RXD2 pins */
io->padir &= ~(SIBIT(12)|SIBIT(13));
io->paodr &= ~SIBIT(12);
io->pcpar &= ~(SIBIT(9)|SIBIT(8)); /* enable CLSN (CTS2) and RENA (CD2) */
io->pcdir &= ~(SIBIT(9)|SIBIT(8));
io->pcso |= SIBIT(9)|SIBIT(8);
io->papar |= SIBIT(6)|SIBIT(5); /* enable CLK2 and CLK3 */
io->padir &= ~(SIBIT(6)|SIBIT(5));
eieio();
rcs = CLK2;
tcs = CLK3;
}else{
io->papar |= SIBIT(14)|SIBIT(15); /* enable TXD1 and RXD1 pins */
io->padir &= ~(SIBIT(14)|SIBIT(15));
io->paodr &= ~SIBIT(14);
io->pcpar &= ~(SIBIT(10)|SIBIT(11)); /* enable CLSN (CTS1) and RENA (CD1) */
io->pcdir &= ~(SIBIT(10)|SIBIT(11));
io->pcso |= SIBIT(10)|SIBIT(11);
eieio();
io->papar |= SIBIT(6)|SIBIT(7); /* enable CLK2 and CLK1 */
io->padir &= ~(SIBIT(6)|SIBIT(7));
eieio();
io->pcpar &= ~(SIBIT(4)|SIBIT(5)|SIBIT(6)); /* ETHLOOP, TPFULDL~, TPSQEL~ */
io->pcdir |= SIBIT(4)|SIBIT(5)|SIBIT(6);
io->pcdat &= ~SIBIT(4);
io->pcdat |= SIBIT(5)|SIBIT(6);
eieio();
rcs = CLK2;
tcs = CLK1;
}
iopunlock();
sccnmsi(ctlr->port, rcs, tcs); /* connect the clocks */
p = (Etherparam*)KADDR(ctlr->sccid==SCC1ID? SCC1P: SCC2P);
memset(p, 0, sizeof(*p));
p->rfcr = 0x18;
p->tfcr = 0x18;
p->mrblr = Bufsize;
p->rbase = PADDR(ctlr->rdr);
p->tbase = PADDR(ctlr->tdr);
cpmop(InitRxTx, ctlr->sccid, 0);
p->c_pres = ~0;
p->c_mask = 0xDEBB20E3;
p->crcec = 0;
p->alec = 0;
p->disfc = 0;
p->pads = 0x8888;
p->ret_lim = 0xF;
p->mflr = Rbsize;
p->minflr = ETHERMINTU+4;
p->maxd1 = Bufsize;
p->maxd2 = Bufsize;
p->p_per = 0; /* only moderate aggression */
for(i=0; i<Eaddrlen; i+=2)
p->paddr[2-i/2] = (ea[i+1]<<8)|ea[i]; /* it's not the obvious byte order */
scc->psmr = (2<<10)|(5<<1); /* 32-bit CRC, ignore 22 bits before SFD */
scc->dsr = 0xd555;
scc->gsmrh = 0; /* normal operation */
scc->gsmrl = (1<<28)|(4<<21)|(1<<19)|0xC; /* transmit clock invert, 48 bit preamble, repetitive 10 preamble, ethernet */
eieio();
scc->scce = ~0; /* clear all events */
eieio();
scc->sccm = TXE | RXF | TXB; /* enable interrupts */
eieio();
if(ctlr->sccid == SCC2ID){
io->pbpar |= IBIT(18); /* enable TENA pin (RTS2) */
io->pbdir |= IBIT(18);
}else{
io->pbpar |= IBIT(19); /* enable TENA pin (RTS1) */
io->pbdir |= IBIT(19);
}
eieio();
/* enable is deferred until attach */
}
static int
reset(Ether* ether)
{
uchar ea[Eaddrlen];
Ctlr *ctlr;
SCC *scc;
if(m->speed < 24){
print("%s ether: system speed must be >= 24MHz for ether use\n", ether->type);
return -1;
}
if(!(ether->port >= 1 && ether->port <= 4)){
print("%s ether: no SCC port %d\n", ether->type, ether->port);
return -1;
}
ether->irq = VectorCPIC + sccirq[ether->port];
scc = IOREGS(sccbase[ether->port], SCC);
if(ether->port == 2)
scc2claim(1, DisableEther, scc2stop, scc);
ctlr = malloc(sizeof(*ctlr));
ether->ctlr = ctlr;
memset(ctlr, 0, sizeof(*ctlr));
ctlr->scc = scc;
ctlr->port = ether->port;
ctlr->sccid = sccid[ether->port];
if(ioringinit(ctlr, Nrdre, Ntdre, Bufsize) < 0)
panic("etherscc init");
sccsetup(ctlr, scc, ether->ea);
ether->mbps = 10; /* TO DO: could be 100mbps on 860T */
ether->attach = attach;
ether->closed = closed;
ether->transmit = transmit;
ether->interrupt = interrupt;
ether->ifstat = ifstat;
ether->arg = ether;
ether->promiscuous = promiscuous;
ether->multicast = multicast;
/*
* Until we know where to find it, insist that the plan9.ini
* entry holds the Ethernet address.
*/
memset(ea, 0, Eaddrlen);
if(memcmp(ea, ether->ea, Eaddrlen) == 0){
print("no ether address");
return -1;
}
return 0;
}
void
etherscclink(void)
{
addethercard("SCC", reset);
addethercard("SCC2", reset);
}
.
## diffname mpc/etherscc.c 1999/0508
## diff -e /n/emeliedump/1999/0122/sys/src/brazil/mpc/etherscc.c /n/emeliedump/1999/0508/sys/src/brazil/mpc/etherscc.c
551c
// addethercard("SCC2", reset);
.
502c
print("%s ether: no SCC port %ld\n", ether->type, ether->port);
.
486c
// step 30:
scc->gsmrh = 0; /* normal operation */
// step 31:
scc->gsmrl = 0x1088000c;
// step 32:
scc->dsr = 0xd555;
// step 33:
scc->psmr = 0x080A; /* 32-bit CRC, non-promiscuous */
// step 34
io->pcpar |= SIBIT(15); /* enable TENA pin (RTS2) */
io->pcdir &= ~SIBIT(15);
// step 35: done at attach time
.
477,484c
// step 29:
// set by setvec
.
475c
p->p_per = 0; /* only moderate aggression */
.
473c
// step 28:
.
467,471c
// step 22
p->p_per = 0; /* only moderate aggression */
// step 23:
memset(p->iaddr, 0, sizeof(p->iaddr));
// step 24:
memset(p->taddr, 0, sizeof(p->taddr));
// step 25:
// step 26:
// step 27:
.
465c
p->paddr[2-i/2] = (ea[i+1]<<8)|ea[i];
.
463a
// step 19:
p->maxd1 = Bufsize; /* was 0x5F0 */
p->maxd2 = Bufsize; /* was 0x5F0 */
// step 20:
memset(p->gaddr, 0, sizeof(p->gaddr));
// step 21:
.
460,462d
458a
// step 18:
.
457a
// step 17:
.
456a
// step 16:
.
455a
// step 15:
.
452a
// step 14:
.
451a
// step 13:
.
450a
// step 10
p->rfcr = 0x18; // manuals say 0x10
p->tfcr = 0x18;
// step 11
p->mrblr = Bufsize;
// step 12:
.
449c
// step 9:
cpmop(InitRxTx, SCC1ID, 0);
.
441,445c
// step 8:
.
439c
// sccnmsi(ctlr->port, rcs, tcs); /* connect the clocks */
.
434,436d
428,432c
// step 7: set dma priority
io->sdcr = 1;
.
424,426c
// step 5/6: route clocks
io->sicr = (7<<3) | (5);
eieio();
.
419,422c
// step 4: enable clocks
io->papar |= SIBIT(6)|SIBIT(4); /* enable CLK2 and CLK4 */
io->padir &= ~(SIBIT(6)|SIBIT(4));
eieio();
.
412,417c
// setp 3
io->pcpar &= ~SIBIT(15); /* disble TENA pin */
.
408,410c
// step 1: enable TXD RXD ports
io->papar |= SIBIT(14)|SIBIT(15);
io->padir &= ~(SIBIT(14)|SIBIT(15));
io->paodr &= ~SIBIT(14);
// step 2: enable CLSN and RENA ports
io->pcpar &= ~(SIBIT(11)|SIBIT(10));
io->pcdir &= ~(SIBIT(11)|SIBIT(10));
io->pcso |= SIBIT(11)|SIBIT(10);
eieio();
.
404,406c
if(ctlr->port != 1)
panic("only do SCC1 at the momment");
.
399,402c
p = (Etherparam*)KADDR(SCC1P);
.
397a
print("sccsetup\n");
.
135d
## diffname mpc/etherscc.c 1999/0608
## diff -e /n/emeliedump/1999/0508/sys/src/brazil/mpc/etherscc.c /n/emeliedump/1999/0608/sys/src/brazil/mpc/etherscc.c
397,398d
## diffname mpc/etherscc.c 1999/0623
## diff -e /n/emeliedump/1999/0608/sys/src/brazil/mpc/etherscc.c /n/emeliedump/1999/0623/sys/src/brazil/mpc/etherscc.c
249a
Ether *ether = arg;
.
244c
interrupt(Ureg*, void *arg)
.
## diffname mpc/etherscc.c 2000/0516
## diff -e /n/emeliedump/1999/0623/sys/src/brazil/mpc/etherscc.c /n/emeliedump/2000/0516/sys/src/9/mpc/etherscc.c
586c
// addethercard("SCC3", reset);
.
530a
print("etherscc: reset\n");
.
517,519c
// step 34: enable TENA
switch(ctlr->port) {
case 2:
io->pcpar |= SIBIT(14);
io->pcdir &= ~SIBIT(14);
break;
case 3:
io->pcpar |= SIBIT(13);
io->pcdir &= ~SIBIT(13);
break;
}
.
439c
cpmop(InitRxTx, sccid[ctlr->port], 0);
.
432,433d
429c
.
426a
case 3:
p = (Etherparam*)KADDR(SCC3P);
// step 1: enable TXD RXD ports
io->pbpar |= IBIT(24)|IBIT(25);
io->pbdir |= IBIT(24)|IBIT(25);
io->pbodr &= ~(IBIT(24)|IBIT(25));
// step 2: enable CLSN and RENA ports
io->pcpar &= ~(SIBIT(4)|SIBIT(5));
io->pcdir &= ~(SIBIT(4)|SIBIT(5));
io->pcso |= SIBIT(4)|SIBIT(5);
eieio();
// setp 3
io->pcpar &= ~SIBIT(13);
io->pcdir &= ~SIBIT(13);
// step 4: enable clocks
io->papar |= SIBIT(4)|SIBIT(5);
io->padir &= ~(SIBIT(4)|SIBIT(5));
eieio();
// step 5/6: route clocks
iopunlock();
sccnmsi(3, CLK3, CLK4);
io = ioplock();
break;
}
.
423,425c
// step 5/6: route clocks
iopunlock();
sccnmsi(2, CLK1, CLK2); /* connect the clocks */
io = ioplock();
break;
.
418,421c
// setp 3: disble TENA pin */
io->pcpar &= ~SIBIT(14);
io->pcdir &= ~SIBIT(14);
// step 4: enable clocks CLK3 and CLK4
io->papar |= SIBIT(6)|SIBIT(7);
io->padir &= ~(SIBIT(6)|SIBIT(7));
.
415,416c
// step 2: enable CLSN and RENA ports
io->pcpar &= ~(SIBIT(8)|SIBIT(9));
io->pcdir &= ~(SIBIT(8)|SIBIT(9));
io->pcso |= SIBIT(8)|SIBIT(9);
.
404,413c
// step 1: enable TXD RXD ports
io->papar |= SIBIT(12)|SIBIT(13);
io->padir &= ~(SIBIT(12)|SIBIT(13));
io->paodr &= ~(SIBIT(12)|SIBIT(13));
.
401,402c
switch(ctlr->port) {
default:
iopunlock();
return;
case 2:
p = (Etherparam*)(SCC2P);
.
399d
394c
int i;
.
354,355d
350a
if(events & TXE)
cpmop(RestartTx, ctlr->sccid, 0);
.
323c
if(events & (TXB|TXE)){
.
291c
print("eth rx: %ux\n", status);
.
279c
if(events & (RXF|RXB)){
.
273a
.
271,272d
143a
Ctlr *ctlr;
ctlr = ether->ctlr;
.
140,142d
## diffname mpc/etherscc.c 2001/0527 # deleted
## diff -e /n/emeliedump/2000/0516/sys/src/9/mpc/etherscc.c /n/emeliedump/2001/0527/sys/src/9/mpc/etherscc.c
1,630d
|