## diffname carrera/ethersonic.c 1997/1210
## diff -e /dev/null /n/emeliedump/1997/1210/sys/src/brazil/carrera/ethersonic.c
0a
#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"
/*
* National Semiconductor DP83932
* Systems-Oriented Network Interface Controller
* (SONIC)
*/
#define SONICADDR ((Sonic*)Sonicbase)
#define RD(rn) (delay(0), *(ulong*)((ulong)&SONICADDR->rn^4))
#define WR(rn, v) (delay(0), *(ulong*)((ulong)&SONICADDR->rn^4) = (v))
#define ISquad(s) if((ulong)s & 0x7) panic("sonic: Quad alignment");
typedef struct Pbuf Pbuf;
struct Pbuf
{
uchar d[6];
uchar s[6];
uchar type[2];
uchar data[1500];
uchar crc[4];
};
typedef struct
{
ulong cr; /* command */
ulong dcr; /* data configuration */
ulong rcr; /* receive control */
ulong tcr; /* transmit control */
ulong imr; /* interrupt mask */
ulong isr; /* interrupt status */
ulong utda; /* upper transmit descriptor address */
ulong ctda; /* current transmit descriptor address */
ulong pad0x08[5]; /* */
ulong urda; /* upper receive descriptor address */
ulong crda; /* current receive descriptor address */
ulong crba0; /* DO NOT WRITE THESE */
ulong crba1;
ulong rbwc0;
ulong rbwc1;
ulong eobc; /* end of buffer word count */
ulong urra; /* upper receive resource address */
ulong rsa; /* resource start address */
ulong rea; /* resource end address */
ulong rrp; /* resource read pointer */
ulong rwp; /* resource write pointer */
ulong pad0x19[8]; /* */
ulong cep; /* CAM entry pointer */
ulong cap2; /* CAM address port 2 */
ulong cap1; /* CAM address port 1 */
ulong cap0; /* CAM address port 0 */
ulong ce; /* CAM enable */
ulong cdp; /* CAM descriptor pointer */
ulong cdc; /* CAM descriptor count */
ulong sr; /* silicon revision */
ulong wt0; /* watchdog timer 0 */
ulong wt1; /* watchdog timer 1 */
ulong rsc; /* receive sequence counter */
ulong crct; /* CRC error tally */
ulong faet; /* FAE tally */
ulong mpt; /* missed packet tally */
ulong mdt; /* maximum deferral timer */
ulong pad0x30[15]; /* */
ulong dcr2; /* data configuration 2 */
} Sonic;
enum
{
Nrb = 16, /* receive buffers */
Ntb = 8, /* transmit buffers */
};
enum
{
Htx = 0x0001, /* halt transmission */
Txp = 0x0002, /* transmit packet(s) */
Rxdis = 0x0004, /* receiver disable */
Rxen = 0x0008, /* receiver enable */
Stp = 0x0010, /* stop timer */
St = 0x0020, /* start timer */
Rst = 0x0080, /* software reset */
Rrra = 0x0100, /* read RRA */
Lcam = 0x0200, /* load CAM */
Dw32 = 0x0020, /* data width select */
Sterm = 0x0400, /* synchronous termination */
Lbr = 0x4000, /* latched bus retry */
Efm = 0x0010, /* Empty fill mode */
W14tf = 0x0003, /* 14 Word transmit fifo */
Prx = 0x0001, /* packet received ok */
Fae = 0x0004, /* frame alignment error */
Crc = 0x0008, /* CRC error */
Lpkt = 0x0040, /* last packet in rba */
Bc = 0x0080, /* broadcast packet received */
Pro = 0x1000, /* physical promiscuous mode */
Brd = 0x2000, /* accept broadcast packets */
Rnt = 0x4000, /* accept runt packets */
Err = 0x8000, /* accept packets with errors */
Ptx = 0x0001, /* packet transmitted ok */
Pintr = 0x8000, /* programmable interrupt */
Rfo = 0x0001, /* receive fifo overrun */
MpTally = 0x0002, /* missed packet tally counter rollover */
FaeTally= 0x0004, /* frame alignment error tally counter rollover */
CrcTally= 0x0008, /* Crc tally counter rollover */
Rbae = 0x0010, /* receive buffer area exceeded */
Rbe = 0x0020, /* receive buffer exhausted */
Rde = 0x0040, /* receive descriptors exhausted */
Txer = 0x0100, /* transmit error */
Txdn = 0x0200, /* transmission done */
Pktrx = 0x0400, /* packet received */
Pint = 0x0800, /* programmed interrupt */
Lcd = 0x1000, /* load CAM done */
Hbl = 0x2000, /* CD heartbeat lost */
Br = 0x4000, /* bus retry occurred */
AllIntr = 0x7771, /* all of the above */
Rxbuf = sizeof(Pbuf)+4,
Txbuf = sizeof(Pbuf),
};
/*
* Receive Resource Descriptor.
*/
typedef struct
{
ushort pad1;
ushort ptr1; /* buffer pointer in the RRA */
ushort pad2;
ushort ptr0;
ushort pad3;
ushort wc1; /* buffer word count in the RRA */
ushort pad4;
ushort wc0;
} RXrsc;
/*
* Receive Packet Descriptor.
*/
typedef struct
{
ushort pad0;
ushort count; /* packet byte count */
ushort pad1;
ushort status; /* receive status */
ushort pad2;
ushort ptr1; /* buffer pointer */
ushort pad3;
ushort ptr0;
ushort pad4;
ushort link; /* descriptor link and EOL */
ushort pad5;
ushort seqno; /* */
ulong pad6;
ushort pad7;
ushort owner; /* in use */
} RXpkt;
/*
* Transmit Packet Descriptor.
*/
typedef struct
{
ushort pad1;
ushort config; /* */
ushort pad0;
ushort status; /* transmit status */
ushort pad3;
ushort count; /* fragment count */
ushort pad2;
ushort size; /* byte count of entire packet */
ushort pad5;
ushort ptr1;
ushort pad4;
ushort ptr0; /* packet pointer */
ushort pad7;
ushort link; /* descriptor link */
ushort pad6;
ushort fsize; /* fragment size */
} TXpkt;
enum{
Eol = 1, /* end of list bit in descriptor link */
Host = 0, /* descriptor belongs to host */
Interface = -1, /* descriptor belongs to interface */
};
/*
* CAM Descriptor
*/
typedef struct
{
ushort pad0;
ushort cap0; /* CAM address port 0 */
ushort pad1;
ushort cep; /* CAM entry pointer */
ushort pad2;
ushort cap2; /* CAM address port 2 */
ushort pad3;
ushort cap1; /* CAM address port 1 */
ulong pad4;
ushort pad5;
ushort ce; /* CAM enable */
} Cam;
typedef struct Ctlr {
Lock lock;
Lock tlock;
int th; /* first transmit buffer owned by host */
int ti; /* first transmit buffer owned by interface */
int ntq;
int rh; /* first receive buffer owned by host */
int ri; /* first receive buffer owned by interface */
RXrsc* rra; /* receive resource area */
RXpkt* rda; /* receive descriptor area */
TXpkt* tda; /* transmit descriptor area */
Cam* cda; /* CAM descriptor area */
ulong* rb[Nrb]; /* receive buffer area */
ulong* tb[Ntb]; /* transmit buffer area */
} Ctlr;
static Ether* etherxx;
#define LS16(addr) (PADDR(addr) & 0xFFFF)
#define MS16(addr) ((PADDR(addr)>>16) & 0xFFFF)
static void
attach(Ether* ether)
{
Ctlr *ctlr;
ctlr = ether->ctlr;
ilock(&ctlr->lock);
if(!(RD(cr) & Rxen))
WR(cr, Rxen);
iunlock(&ctlr->lock);
}
static void
promiscuous(void* arg, int on)
{
Ctlr *ctlr;
ushort rcr;
ctlr = ((Ether*)arg)->ctlr;
ilock(&ctlr->lock);
rcr = RD(rcr);
if(on)
rcr |= Pro;
else
rcr &= ~Pro;
WR(rcr, rcr);
iunlock(&ctlr->lock);
}
static void
wus(ushort* a, ushort v)
{
a[0] = v;
a[-1] = v;
}
static void
swizzle(uchar* to, ulong *from, int nbytes)
{
ulong *l, l0, l1;
uchar *p;
p = to;
l = from;
for(nbytes = ROUNDUP(nbytes, 8); nbytes; nbytes -= 8){
l1 = *l++;
l0 = *l++;
p[0] = l0;
p[1] = l0>>8;
p[2] = l0>>16;
p[3] = l0>>24;
p[4] = l1;
p[5] = l1>>8;
p[6] = l1>>16;
p[7] = l1>>24;
p += 8;
}
}
static void
swozzle(ulong* to, uchar *from, int nbytes)
{
ulong *l;
uchar *p;
l = to;
p = from;
for(nbytes = ROUNDUP(nbytes, 8); nbytes; nbytes -= 8){
*l++ = (p[7]<<24)|(p[6]<<16)|(p[5]<<8)|p[4];
*l++ = (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0];
p += 8;
}
}
static void
txstart(Ether* ether)
{
Ctlr *ctlr;
Block *bp;
ushort *s;
TXpkt *txpkt;
int len;
ctlr = ether->ctlr;
txpkt = &ctlr->tda[ctlr->th];
while(txpkt->status == Host){
bp = qget(ether->oq);
if(bp == nil)
break;
len = BLEN(bp);
swozzle(ctlr->tb[ctlr->th], bp->rp, len);
txpkt->size = len;
txpkt->fsize = len;
wus(&txpkt->link, txpkt->link|Eol);
txpkt->status = Interface;
s = &ctlr->tda[PREV(ctlr->th, Ntb)].link;
wus(s, *s & ~Eol);
ctlr->th = NEXT(ctlr->th, Ntb);
txpkt = &ctlr->tda[ctlr->th];
WR(cr, Txp);
freeb(bp);
}
}
void
etherintr(void)
{
Ether *ether;
Ctlr *ctlr;
ushort *s;
ulong status;
TXpkt *txpkt;
RXpkt *rxpkt;
int len;
Block *bp;
ether = etherxx;
ctlr = ether->ctlr;
for(status = (RD(isr) & AllIntr); status; status = (RD(isr) & AllIntr)){
/*
* Warnings that something is atoe.
*/
if(status & Hbl){
WR(isr, Hbl);
status &= ~Hbl;
print("sonic: cd heartbeat lost\n");
}
if(status & Br){
WR(cr, Rst);
print("sonic: bus retry occurred\n");
(*(void(*)(void))0xA001C020)();
status &= ~Br;
}
/*
* Transmission complete, for good or bad.
*/
if(status & (Txdn|Txer)){
txpkt = &ctlr->tda[ctlr->ti];
while(txpkt->status != Host){
if(txpkt->status == Interface){
WR(ctda, LS16(txpkt));
WR(cr, Txp);
break;
}
if((txpkt->status & Ptx) == 0)
ether->oerrs++;
txpkt->status = Host;
ctlr->ti = NEXT(ctlr->ti, Ntb);
txpkt = &ctlr->tda[ctlr->ti];
}
WR(isr, status & (Txdn|Txer));
status &= ~(Txdn|Txer);
lock(&ctlr->tlock);
txstart(ether);
unlock(&ctlr->tlock);
}
if((status & (Pktrx|Rde)) == 0)
goto noinput;
/*
* A packet arrived or we ran out of descriptors.
*/
rxpkt = &ctlr->rda[ctlr->rh];
while(rxpkt->owner == Host){
ether->inpackets++;
/*
* If the packet was received OK, pass it up,
* otherwise log the error.
*/
if(rxpkt->status & Prx){
/*
* Sonic delivers CRC as part of the packet count.
*/
len = (rxpkt->count & 0xFFFF)-4;
if(bp = iallocb(ROUNDUP(len, 8))){
swizzle(bp->rp, ctlr->rb[ctlr->rh], len);
bp->wp += len;
etheriq(ether, bp, 1);
}
}
else if(rxpkt->status & Fae)
ether->frames++;
else if(rxpkt->status & Crc)
ether->crcs++;
else
ether->buffs++;
rxpkt->status = 0;
/*
* Finished with this packet, it becomes the
* last free packet in the ring, so give it Eol,
* and take the Eol bit off the previous packet.
* Move the ring index on.
*/
wus(&rxpkt->link, rxpkt->link|Eol);
rxpkt->owner = Interface;
s = &ctlr->rda[PREV(ctlr->rh, Nrb)].link;
wus(s, *s & ~Eol);
ctlr->rh = NEXT(ctlr->rh, Nrb);
rxpkt = &ctlr->rda[ctlr->rh];
}
WR(isr, status & (Pktrx|Rde));
status &= ~(Pktrx|Rde);
noinput:
/*
* We get a 'load CAM done' interrupt
* after initialisation. Ignore it.
*/
if(status & Lcd) {
WR(isr, Lcd);
status &= ~Lcd;
}
if(status & AllIntr) {
WR(isr, status);
print("sonic #%lux\n", status);
}
}
}
static void
transmit(Ether* ether)
{
Ctlr *ctlr;
ctlr = ether->ctlr;
ilock(&ctlr->tlock);
txstart(ether);
iunlock(&ctlr->tlock);
}
static void
reset(Ether* ether)
{
Ctlr *ctlr;
int i;
ushort lolen, hilen, loadr, hiadr;
ctlr = ether->ctlr;
/*
* Reset the SONIC, toggle the Rst bit.
* Set the data config register for synchronous termination
* and 32-bit data-path width.
* Setup the descriptor and buffer area.
*/
WR(cr, Rst);
WR(dcr, 0x2423); /* 5-19 Carrera manual */
WR(cr, 0);
/*
* Initialise the receive resource area (RRA) and
* the receive descriptor area (RDA).
*
* We use a simple scheme of one packet per descriptor.
* We achieve this by setting the EOBC register to be
* 2 (16-bit words) less than the buffer size;
* thus the size of the receive buffers must be sizeof(Pbuf)+4.
* Set up the receive descriptors as a ring.
*/
lolen = (Rxbuf/2) & 0xFFFF;
hilen = ((Rxbuf/2)>>16) & 0xFFFF;
for(i = 0; i < Nrb; i++) {
wus(&ctlr->rra[i].wc0, lolen);
wus(&ctlr->rra[i].wc1, hilen);
ctlr->rda[i].link = LS16(&ctlr->rda[NEXT(i, Nrb)]);
ctlr->rda[i].owner = Interface;
loadr = LS16(ctlr->rb[i]);
wus(&ctlr->rra[i].ptr0, loadr);
wus(&ctlr->rda[i].ptr0, loadr);
hiadr = MS16(ctlr->rb[i]);
wus(&ctlr->rra[i].ptr1, hiadr);
wus(&ctlr->rda[i].ptr1, hiadr);
}
/*
* Check the important resources are QUAD aligned
*/
ISquad(ctlr->rra);
ISquad(ctlr->rda);
/*
* Terminate the receive descriptor ring
* and load the SONIC registers to describe the RDA.
*/
ctlr->rda[Nrb-1].link |= Eol;
WR(crda, LS16(ctlr->rda));
WR(urda, MS16(ctlr->rda));
WR(eobc, Rxbuf/2 - 2);
/*
* Load the SONIC registers to describe the RRA.
* We set the rwp to beyond the area delimited by rsa and
* rea. This means that since we've already allocated all
* the buffers, we'll never get a 'receive buffer area
* exhausted' interrupt and the rrp will just wrap round.
*/
WR(urra, MS16(&ctlr->rra[0]));
WR(rsa, LS16(&ctlr->rra[0]));
WR(rrp, LS16(&ctlr->rra[0]));
WR(rea, LS16(&ctlr->rra[Nrb]));
WR(rwp, LS16(&ctlr->rra[Nrb+1]));
/*
* Initialise the transmit descriptor area (TDA).
* Each descriptor describes one packet, we make no use
* of having the packet in multiple fragments.
* The descriptors are linked in a ring; overlapping transmission
* with buffer queueing will cause some packets to
* go out back-to-back.
*
* Load the SONIC registers to describe the TDA.
*/
for(i = 0; i < Ntb; i++){
ctlr->tda[i].status = Host;
ctlr->tda[i].config = 0;
ctlr->tda[i].count = 1;
ctlr->tda[i].ptr0 = LS16(ctlr->tb[i]);
ctlr->tda[i].ptr1 = MS16(ctlr->tb[i]);
ctlr->tda[i].link = LS16(&ctlr->tda[NEXT(i, Ntb)]);
}
WR(ctda, LS16(&ctlr->tda[0]));
WR(utda, MS16(&ctlr->tda[0]));
/*
* Initialise the software receive and transmit
* ring indexes.
*/
ctlr->rh = 0;
ctlr->ri = 0;
ctlr->th = 0;
ctlr->ti = 0;
/*
* Initialise the CAM descriptor area (CDA).
* We only have one ethernet address to load,
* broadcast is defined by the SONIC as all 1s.
*
* Load the SONIC registers to describe the CDA.
*/
ctlr->cda->cep = 0;
ctlr->cda->cap0 = (ether->addr[1]<<8)|ether->addr[0];
ctlr->cda->cap1 = (ether->addr[3]<<8)|ether->addr[2];
ctlr->cda->cap2 = (ether->addr[5]<<8)|ether->addr[4];
ctlr->cda->ce = 1;
WR(cdp, LS16(ctlr->cda));
WR(cdc, 1);
/*
* Load the Resource Descriptors and Cam contents
*/
WR(cr, Rrra);
while(RD(cr) & Rrra)
;
WR(cr, Lcam);
while(RD(cr) & Lcam)
;
/*
* Configure the receive control, transmit control
* and interrupt-mask registers.
* The SONIC is now initialised, but not enabled.
*/
WR(rcr, Brd);
WR(tcr, 0);
WR(imr, AllIntr);
}
static void
initbufs(Ctlr* ctlr)
{
int i;
uchar *mem, *base;
/* Put the ethernet buffers in the same place
* as the bootrom
*/
mem = (void*)(KZERO|0x2000);
base = mem;
mem = CACHELINE(uchar, mem);
/*
* Descriptors must be built in uncached space
*/
ctlr->rra = UNCACHED(RXrsc, mem);
mem = QUAD(uchar, mem+Nrb*sizeof(RXrsc));
ctlr->rda = UNCACHED(RXpkt, mem);
mem = QUAD(uchar, mem+Nrb*sizeof(RXpkt));
ctlr->tda = UNCACHED(TXpkt, mem);
mem = QUAD(uchar, mem+Ntb*sizeof(TXpkt));
ctlr->cda = UNCACHED(Cam, mem);
mem = CACHELINE(uchar, mem+sizeof(Cam));
for(i = 0; i < Nrb; i++) {
ctlr->rb[i] = UNCACHED(ulong, mem);
mem += sizeof(Pbuf)+4;
mem = QUAD(uchar, mem);
}
for(i = 0; i < Ntb; i++) {
ctlr->tb[i] = UNCACHED(ulong, mem);
mem += sizeof(Pbuf);
mem = QUAD(uchar, mem);
}
if(mem >= base+64*1024)
panic("sonic init");
}
static int
sonicreset(Ether* ether)
{
Ctlr *ctlr;
if(ether->ctlrno != 0)
return 1;
/*
* Map the device registers and allocate
* memory for the receive/transmit rings.
* Set the physical ethernet address and
* prime the interrupt handler.
*/
ether->ctlr = malloc(sizeof(Ctlr));
ctlr = ether->ctlr;
ether->port = Sonicbase;
initbufs(ctlr);
enetaddr(ether->addr);
reset(ether);
/*
* Hack: etherintr is called directly from trap with no arguments.
* There can only be one sonic, so keep a note of the generic ether
* struct.
*/
etherxx = ether;
return 0;
}
static Endev sonicdev = {
"sonic",
sonicreset,
attach,
transmit,
nil, /* interrupt - etherintr called directly from trap */
nil, /* ifstat */
promiscuous,
nil, /* multicast */
0, 0, /* vid, did */
};
Endev* endev[] = {
&sonicdev,
nil,
};
.
## diffname carrera/ethersonic.c 2001/0527 # deleted
## diff -e /n/emeliedump/1997/1210/sys/src/brazil/carrera/ethersonic.c /n/emeliedump/2001/0527/sys/src/9/carrera/ethersonic.c
1,727d
|