|
|
|
1992/0918/sys/src/9/pc/devether.c:7,119 –
1992/0922/sys/src/9/pc/devether.c:7,39
(short | long | prev | next)
|
|
1992/0403
| |
#include "io.h"
#include "devtab.h"
|
|
1992/0424
| |
typedef struct Hw Hw;
typedef struct Buffer Buffer;
|
|
1992/0410
| |
typedef struct Type Type;
|
|
1992/0424
| |
typedef struct Ctlr Ctlr;
|
|
1992/0922
| |
/*
* Half-arsed attempt at a general top-level
* ethernet driver. Needs work:
* handle multiple controllers
* much tidying
* set ethernet address
*/
extern EtherHw ether509;
extern EtherHw ether80x3;
|
|
1992/0403
| |
|
|
1992/0424
| |
struct Hw {
|
|
1992/0917
| |
int (*reset)(Ctlr*);
|
|
1992/0909
| |
void (*init)(Ctlr*);
void (*mode)(Ctlr*, int);
void (*online)(Ctlr*, int);
void (*receive)(Ctlr*);
void (*transmit)(Ctlr*);
void (*intr)(Ureg*);
|
|
1992/0915
| |
void (*tweek)(Ctlr*);
|
|
1992/0424
| |
int addr; /* interface address */
|
|
1992/0501
| |
uchar *ram; /* interface shared memory address */
|
|
1992/0906
| |
int bt16; /* true if a 16 bit interface */
int lvl; /* interrupt level */
|
|
1992/0501
| |
int size;
uchar tstart;
uchar pstart;
uchar pstop;
|
|
1992/0922
| |
static EtherHw *etherhw[] = {
ðer509,
ðer80x3,
0
|
|
1992/0404
| |
};
|
|
1992/0424
| |
static Hw wd8013;
|
|
1992/0404
| |
enum {
|
|
1992/0424
| |
Nctlr = 1, /* even one of these is too many */
NType = 9, /* types/interface */
|
|
1992/0403
| |
|
|
1992/0424
| |
Nrb = 16, /* software receive buffers */
Ntb = 4, /* software transmit buffers */
|
|
1992/0922
| |
Nctlr = 1,
|
|
1992/0424
| |
};
|
|
1992/0403
| |
|
|
1992/0922
| |
static struct EtherCtlr ctlr[Nctlr];
|
|
1992/0424
| |
#define NEXT(x, l) (((x)+1)%(l))
#define OFFSETOF(t, m) ((unsigned)&(((t*)0)->m))
#define HOWMANY(x, y) (((x)+((y)-1))/(y))
#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
|
|
1992/0403
| |
|
|
1992/0424
| |
struct Buffer {
uchar owner;
uchar busy;
ushort len;
|
|
1992/0501
| |
uchar pkt[sizeof(Etherpkt)];
|
|
1992/0404
| |
};
|
|
1992/0403
| |
|
|
1992/0404
| |
enum {
|
|
1992/0424
| |
Host = 0, /* buffer owned by host */
Interface = 1, /* buffer owned by interface */
|
|
1992/0404
| |
};
|
|
1992/0403
| |
/*
* one per ethernet packet type
*/
|
|
1992/0410
| |
struct Type {
|
|
1992/0403
| |
QLock;
|
|
1992/0625
| |
Netprot; /* stat info */
|
|
1992/0403
| |
int type; /* ethernet type */
int prom; /* promiscuous mode */
Queue *q;
int inuse;
Ctlr *ctlr;
};
/*
|
|
1992/0424
| |
* per ethernet
|
|
1992/0403
| |
*/
struct Ctlr {
QLock;
|
|
1992/0424
| |
Hw *hw;
|
|
1992/0917
| |
int present;
|
|
1992/0403
| |
|
|
1992/0424
| |
ushort nrb; /* number of software receive buffers */
ushort ntb; /* number of software transmit buffers */
Buffer *rb; /* software receive buffers */
Buffer *tb; /* software transmit buffers */
|
|
1992/0403
| |
|
|
1992/0424
| |
uchar ea[6]; /* ethernet address */
uchar ba[6]; /* broadcast address */
|
|
1992/0403
| |
|
|
1992/0424
| |
Rendez rr; /* rendezvous for a receive buffer */
ushort rh; /* first receive buffer belonging to host */
ushort ri; /* first receive buffer belonging to interface */
|
|
1992/0403
| |
|
|
1992/0424
| |
Rendez tr; /* rendezvous for a transmit buffer */
|
|
1992/0505
| |
QLock tlock; /* semaphore on th */
|
|
1992/0424
| |
ushort th; /* first transmit buffer belonging to host */
ushort ti; /* first transmit buffer belonging to interface */
Type type[NType];
uchar prom; /* true if promiscuous mode */
uchar kproc; /* true if kproc started */
char name[NAMELEN]; /* name of kproc */
|
|
1992/0403
| |
Network net;
|
|
1992/0424
| |
Queue lbq; /* software loopback packet queue */
|
|
1992/0403
| |
int inpackets;
int outpackets;
|
|
1992/0424
| |
int crcs; /* input crc errors */
int oerrs; /* output errors */
int frames; /* framing errors */
int overflows; /* packet overflows */
int buffs; /* buffering errors */
|
|
1992/0403
| |
};
static Ctlr ctlr[Nctlr];
|
|
1992/0425
| |
Chan*
etherattach(char *spec)
|
|
1992/0424
| |
{
|
|
1992/0918/sys/src/9/pc/devether.c:189,195 –
1992/0922/sys/src/9/pc/devether.c:109,115
|
|
1992/0407
| |
static int
|
|
1992/0424
| |
isobuf(void *arg)
|
|
1992/0407
| |
{
Ctlr *cp = arg;
|
|
1992/0922
| |
EtherCtlr *cp = arg;
|
|
1992/0407
| |
|
|
1992/0425
| |
return cp->tb[cp->th].owner == Host;
|
|
1992/0407
| |
}
|
|
1992/0918/sys/src/9/pc/devether.c:197,213 –
1992/0922/sys/src/9/pc/devether.c:117,133
|
|
1992/0403
| |
static void
etheroput(Queue *q, Block *bp)
{
|
|
1992/0406
| |
Ctlr *cp;
|
|
1992/0403
| |
int len, n;
|
|
1992/0410
| |
Type *tp;
|
|
1992/0922
| |
EtherCtlr *cp;
EtherType *tp;
|
|
1992/0403
| |
Etherpkt *p;
|
|
1992/0424
| |
Buffer *tb;
|
|
1992/0922
| |
EtherBuf *tb;
int len, n;
|
|
1992/0403
| |
Block *nbp;
if(bp->type == M_CTL){
|
|
1992/0410
| |
tp = q->ptr;
|
|
1992/0403
| |
if(streamparse("connect", bp))
|
|
1992/0410
| |
tp->type = strtol((char *)bp->rptr, 0, 0);
|
|
1992/0922
| |
tp->type = strtol((char*)bp->rptr, 0, 0);
|
|
1992/0403
| |
else if(streamparse("promiscuous", bp)) {
|
|
1992/0410
| |
tp->prom = 1;
|
|
1992/0424
| |
(*tp->ctlr->hw->mode)(tp->ctlr, 1);
|
|
1992/0918/sys/src/9/pc/devether.c:216,222 –
1992/0922/sys/src/9/pc/devether.c:136,142
|
|
1992/0403
| |
return;
}
|
|
1992/0424
| |
cp = ((Type *)q->ptr)->ctlr;
|
|
1992/0922
| |
cp = ((EtherType*)q->ptr)->ctlr;
|
|
1992/0424
| |
|
|
1992/0403
| |
/*
* give packet a local address, return upstream if destined for
|
|
1992/0918/sys/src/9/pc/devether.c:224,230 –
1992/0922/sys/src/9/pc/devether.c:144,150
|
|
1992/0403
| |
*/
|
|
1992/0406
| |
if(BLEN(bp) < ETHERHDRSIZE && (bp = pullup(bp, ETHERHDRSIZE)) == 0)
return;
|
|
1992/0403
| |
p = (Etherpkt *)bp->rptr;
|
|
1992/0922
| |
p = (Etherpkt*)bp->rptr;
|
|
1992/0406
| |
memmove(p->s, cp->ea, sizeof(cp->ea));
if(memcmp(cp->ea, p->d, sizeof(cp->ea)) == 0){
|
|
1992/0403
| |
len = blen(bp);
|
|
1992/0918/sys/src/9/pc/devether.c:308,315 –
1992/0922/sys/src/9/pc/devether.c:228,235
|
|
1992/0403
| |
static void
etherstopen(Queue *q, Stream *s)
{
|
|
1992/0404
| |
Ctlr *cp = &ctlr[0];
|
|
1992/0410
| |
Type *tp;
|
|
1992/0922
| |
EtherCtlr *cp = &ctlr[0];
EtherType *tp;
|
|
1992/0403
| |
|
|
1992/0410
| |
tp = &cp->type[s->id];
qlock(tp);
|
|
1992/0918/sys/src/9/pc/devether.c:330,338 –
1992/0922/sys/src/9/pc/devether.c:250,258
|
|
1992/0403
| |
static void
etherstclose(Queue *q)
{
|
|
1992/0410
| |
Type *tp;
|
|
1992/0922
| |
EtherType *tp;
|
|
1992/0403
| |
|
|
1992/0410
| |
tp = (Type *)(q->ptr);
|
|
1992/0922
| |
tp = (EtherType*)(q->ptr);
|
|
1992/0424
| |
if(tp->prom)
(*tp->ctlr->hw->mode)(tp->ctlr, 0);
|
|
1992/0410
| |
qlock(tp);
|
|
1992/0918/sys/src/9/pc/devether.c:356,363 –
1992/0922/sys/src/9/pc/devether.c:276,283
|
|
1992/0403
| |
static int
|
|
1992/0404
| |
clonecon(Chan *c)
|
|
1992/0403
| |
{
|
|
1992/0404
| |
Ctlr *cp = &ctlr[0];
|
|
1992/0410
| |
Type *tp;
|
|
1992/0922
| |
EtherCtlr *cp = &ctlr[0];
EtherType *tp;
|
|
1992/0403
| |
|
|
1992/0711
| |
USED(c);
|
|
1992/0410
| |
for(tp = cp->type; tp < &cp->type[NType]; tp++){
|
|
1992/0918/sys/src/9/pc/devether.c:378,384 –
1992/0922/sys/src/9/pc/devether.c:298,304
|
|
1992/0403
| |
static void
|
|
1992/0404
| |
statsfill(Chan *c, char *p, int n)
|
|
1992/0403
| |
{
|
|
1992/0404
| |
Ctlr *cp = &ctlr[0];
|
|
1992/0922
| |
EtherCtlr *cp = &ctlr[0];
|
|
1992/0403
| |
char buf[256];
|
|
1992/0711
| |
USED(c);
|
|
1992/0918/sys/src/9/pc/devether.c:393,399 –
1992/0922/sys/src/9/pc/devether.c:313,319
|
|
1992/0403
| |
typefill(Chan *c, char *p, int n)
{
char buf[16];
|
|
1992/0410
| |
Type *tp;
|
|
1992/0922
| |
EtherType *tp;
|
|
1992/0403
| |
|
|
1992/0410
| |
tp = &ctlr[0].type[STREAMID(c->qid.path)];
sprint(buf, "%d", tp->type);
|
|
1992/0918/sys/src/9/pc/devether.c:401,411 –
1992/0922/sys/src/9/pc/devether.c:321,331
|
|
1992/0403
| |
}
static void
|
|
1992/0501
| |
etherup(Ctlr *cp, void *data, int len)
|
|
1992/0922
| |
etherup(EtherCtlr *cp, void *data, int len)
|
|
1992/0403
| |
{
|
|
1992/0501
| |
Etherpkt *p;
|
|
1992/0404
| |
int t;
|
|
1992/0501
| |
Type *tp;
|
|
1992/0922
| |
EtherType *tp;
|
|
1992/0501
| |
Block *bp;
|
|
1992/0404
| |
|
|
1992/0501
| |
p = data;
|
|
1992/0918/sys/src/9/pc/devether.c:448,454 –
1992/0922/sys/src/9/pc/devether.c:368,374
|
|
1992/0403
| |
static int
isinput(void *arg)
{
|
|
1992/0404
| |
Ctlr *cp = arg;
|
|
1992/0922
| |
EtherCtlr *cp = arg;
|
|
1992/0403
| |
|
|
1992/0424
| |
return cp->lbq.first || cp->rb[cp->ri].owner == Host;
|
|
1992/0403
| |
}
|
|
1992/0918/sys/src/9/pc/devether.c:456,468 –
1992/0922/sys/src/9/pc/devether.c:376,389
|
|
1992/0403
| |
static void
etherkproc(void *arg)
{
|
|
1992/0404
| |
Ctlr *cp = arg;
|
|
1992/0424
| |
Buffer *rb;
|
|
1992/0922
| |
EtherCtlr *cp = arg;
EtherBuf *rb;
|
|
1992/0404
| |
Block *bp;
|
|
1992/0403
| |
if(waserror()){
|
|
1992/0404
| |
print("%s noted\n", cp->name);
|
|
1992/0424
| |
(*cp->hw->init)(cp);
|
|
1992/0922
| |
if(cp->hw->init)
(*cp->hw->init)(cp);
|
|
1992/0404
| |
cp->kproc = 0;
|
|
1992/0403
| |
nexterror();
}
|
|
1992/0918/sys/src/9/pc/devether.c:469,475 –
1992/0922/sys/src/9/pc/devether.c:390,397
|
|
1992/0404
| |
cp->kproc = 1;
|
|
1992/0403
| |
for(;;){
|
|
1992/0915
| |
tsleep(&cp->rr, isinput, cp, 500);
(*cp->hw->tweek)(cp);
|
|
1992/0922
| |
if(cp->hw->tweak)
(*cp->hw->tweak)(cp);
|
|
1992/0424
| |
|
|
1992/0406
| |
/*
* process any internal loopback packets
|
|
1992/0918/sys/src/9/pc/devether.c:493,511 –
1992/0922/sys/src/9/pc/devether.c:415,447
|
|
1992/0424
| |
}
}
|
|
1992/0410
| |
|
|
1992/0922
| |
static void
etherintr(Ureg *ur)
{
EtherCtlr *cp = &ctlr[0];
USED(ur);
(*cp->hw->intr)(cp);
}
|
|
1992/0424
| |
void
etherreset(void)
{
|
|
1992/0922
| |
EtherCtlr *cp;
EtherHw **hw;
|
|
1992/0625
| |
int i;
Ctlr *cp;
|
|
1992/0410
| |
|
|
1992/0625
| |
cp = &ctlr[0];
|
|
1992/0424
| |
cp->hw = &wd8013;
|
|
1992/0917
| |
if((*cp->hw->reset)(cp) < 0){
cp->present = 0;
return;
|
|
1992/0922
| |
for(hw = etherhw; *hw; hw++){
cp->hw = *hw;
if((*cp->hw->reset)(cp) == 0){
cp->present = 1;
setvec(Int0vec + cp->hw->irq, etherintr);
break;
}
|
|
1992/0917
| |
}
cp->present = 1;
|
|
1992/0922
| |
if(cp->present == 0)
return;
|
|
1992/0410
| |
|
|
1992/0424
| |
memset(cp->ba, 0xFF, sizeof(cp->ba));
|
|
1992/0410
| |
|
|
1992/0918/sys/src/9/pc/devether.c:528,534 –
1992/0922/sys/src/9/pc/devether.c:464,470
|
|
1992/0425
| |
etherinit(void)
|
|
1992/0403
| |
{
int ctlrno = 0;
|
|
1992/0424
| |
Ctlr *cp = &ctlr[ctlrno];
|
|
1992/0922
| |
EtherCtlr *cp = &ctlr[ctlrno];
|
|
1992/0424
| |
int i;
|
|
1992/0403
| |
|
|
1992/0917
| |
if(cp->present == 0)
|
|
1992/0918/sys/src/9/pc/devether.c:554,1018 –
1992/0922/sys/src/9/pc/devether.c:490,492
|
|
1992/0424
| |
kproc(cp->name, etherkproc, cp);
|
|
1992/0403
| |
}
}
|
|
1992/0424
| |
typedef struct {
uchar msr; /* 83C584 bus interface */
uchar icr;
uchar iar;
uchar bio;
uchar irr;
uchar laar;
uchar ijr;
uchar gp2;
uchar lan[6];
uchar id;
uchar cksum;
|
|
1992/0403
| |
|
|
1992/0424
| |
union { /* DP8390/83C690 LAN controller */
struct { /* Page0, read */
uchar cr;
uchar clda0;
uchar clda1;
uchar bnry;
uchar tsr;
uchar ncr;
uchar fifo;
uchar isr;
uchar crda0;
uchar crda1;
uchar pad0x0A;
uchar pad0x0B;
uchar rsr;
uchar cntr0;
uchar cntr1;
uchar cntr2;
} r;
struct { /* Page0, write */
uchar cr;
uchar pstart;
uchar pstop;
uchar bnry;
uchar tpsr;
uchar tbcr0;
uchar tbcr1;
uchar isr;
uchar rsar0;
uchar rsar1;
uchar rbcr0;
uchar rbcr1;
uchar rcr;
uchar tcr;
uchar dcr;
uchar imr;
} w;
struct { /* Page1, read/write */
uchar cr;
uchar par[6];
uchar curr;
uchar mar[8];
};
|
|
1992/0917
| |
struct { /* Page2, read */
uchar cr;
uchar pstart;
uchar pstop;
uchar dummy1[1];
uchar tstart;
uchar next;
uchar block;
uchar enh;
uchar dummy2[4];
uchar rcon;
uchar tcon;
uchar dcon;
uchar intmask;
} r2;
struct { /* Page2, write */
uchar cr;
uchar trincrl;
uchar trincrh;
uchar dummy1[2];
uchar next;
uchar block;
uchar enh;
} w2;
|
|
1992/0424
| |
};
} Wd8013;
|
|
1992/0403
| |
|
|
1992/0905
| |
enum {
MENB = 0x40, /* memory enable */
|
|
1992/0917
| |
/* bit definitions for laar */
ZeroWS16 = (1<<5), /* zero wait states for 16-bit ops */
L16EN = (1<<6), /* enable 16-bit LAN operation */
M16EN = (1<<7), /* enable 16-bit memory access */
/* bit defintitions for DP8390/83C690 cr */
Page0 = (0<<6),
Page1 = (1<<6),
Page2 = (2<<6),
RD2 = (4<<3),
TXP = (1<<2),
STA = (1<<1),
STP = (1<<0),
|
|
1992/0905
| |
};
|
|
1992/0424
| |
#define IN(hw, m) inb((hw)->addr+OFFSETOF(Wd8013, m))
#define OUT(hw, m, x) outb((hw)->addr+OFFSETOF(Wd8013, m), (x))
|
|
1992/0501
| |
typedef struct {
uchar status;
uchar next;
uchar len0;
uchar len1;
uchar data[256-4];
} Ring;
|
|
1992/0905
| |
static void
wd8013dumpregs(Hw *hw)
{
print("msr=#%2.2ux\n", IN(hw, msr));
print("icr=#%2.2ux\n", IN(hw, icr));
print("iar=#%2.2ux\n", IN(hw, iar));
print("bio=#%2.2ux\n", IN(hw, bio));
print("irr=#%2.2ux\n", IN(hw, irr));
print("laar=#%2.2ux\n", IN(hw, laar));
print("ijr=#%2.2ux\n", IN(hw, ijr));
print("gp2=#%2.2ux\n", IN(hw, gp2));
print("lan0=#%2.2ux\n", IN(hw, lan[0]));
print("lan1=#%2.2ux\n", IN(hw, lan[1]));
print("lan2=#%2.2ux\n", IN(hw, lan[2]));
print("lan3=#%2.2ux\n", IN(hw, lan[3]));
print("lan4=#%2.2ux\n", IN(hw, lan[4]));
print("lan5=#%2.2ux\n", IN(hw, lan[5]));
print("id=#%2.2ux\n", IN(hw, id));
}
|
|
1992/0906
| |
/* mapping from configuration bits to interrupt level */
int intrmap[] =
{
9, 3, 5, 7, 10, 11, 15, 4,
};
|
|
1992/0424
| |
/*
|
|
1992/0906
| |
* get configuration parameters, enable memory
|
|
1992/0424
| |
*/
|
|
1992/0917
| |
static int
|
|
1992/0424
| |
wd8013reset(Ctlr *cp)
|
|
1992/0403
| |
{
|
|
1992/0424
| |
Hw *hw = cp->hw;
int i;
|
|
1992/0918
| |
uchar msr, icr, laar, irr;
|
|
1992/0905
| |
ulong ram;
|
|
1992/0403
| |
|
|
1992/0918
| |
/* find the ineterface */
SET(msr, icr, irr, laar);
for(hw->addr = 0x200; hw->addr < 0x400; hw->addr += 0x20){
msr = IN(hw, msr);
icr = IN(hw, icr);
irr = IN(hw, irr);
laar = IN(hw, laar);
if((msr&0x80) || (icr&0xf0) || irr == 0xff || laar == 0xff)
continue; /* nothing there */
|
|
1992/0917
| |
|
|
1992/0918
| |
/* ethernet address */
for(i = 0; i < sizeof(cp->ea); i++)
cp->ea[i] = IN(hw, lan[i]);
/* look for an elite ether address */
if(cp->ea[0] == 0x00 && cp->ea[1] == 0x00 && cp->ea[2] == 0xC0)
break;
}
if(hw->addr >= 0x400)
|
|
1992/0917
| |
return -1;
|
|
1992/0915
| |
if(cp->rb == 0){
cp->rb = xspanalloc(sizeof(Buffer)*Nrb, BY2PG, 0);
cp->nrb = Nrb;
cp->tb = xspanalloc(sizeof(Buffer)*Ntb, BY2PG, 0);
cp->ntb = Ntb;
}
|
|
1992/0424
| |
|
|
1992/0906
| |
/* 16 bit operation? */
hw->bt16 = icr & 0x1;
/* address of interface RAM */
ram = KZERO | ((msr & 0x3f) << 13);
if(hw->bt16)
ram |= (laar & 0x3f)<<19;
else
ram |= 0x80000;
|
|
1992/0905
| |
hw->ram = (uchar*)ram;
|
|
1992/0906
| |
/* interrupt level */
hw->lvl = intrmap[((irr>>5) & 0x3) | (icr & 0x4)];
/* ram size */
if(icr&(1<<3))
hw->size = 32*1024;
else
hw->size = 8*1024;
if(hw->bt16)
hw->size <<= 1;
|
|
1992/0909
| |
hw->pstart = HOWMANY(sizeof(Etherpkt), 256);
|
|
1992/0906
| |
hw->pstop = HOWMANY(hw->size, 256);
|
|
1992/0918
| |
print("elite at %lux width %d addr %lux size %d lvl %d\n", hw->addr, hw->bt16?16:8,
|
|
1992/0915
| |
hw->ram, hw->size, hw->lvl);/**/
|
|
1992/0906
| |
/* enable interface RAM, set interface width */
OUT(hw, msr, MENB|msr);
if(hw->bt16)
|
|
1992/0917
| |
OUT(hw, laar, laar|L16EN|M16EN|ZeroWS16);
|
|
1992/0906
| |
|
|
1992/0424
| |
(*hw->init)(cp);
|
|
1992/0906
| |
setvec(Int0vec + hw->lvl, hw->intr);
|
|
1992/0917
| |
return 0;
|
|
1992/0424
| |
}
|
|
1992/0403
| |
|
|
1992/0505
| |
static void
dp8390rinit(Ctlr *cp)
{
Hw *hw = cp->hw;
|
|
1992/0917
| |
OUT(hw, w.cr, Page0|RD2|STP);
|
|
1992/0505
| |
OUT(hw, w.bnry, hw->pstart);
|
|
1992/0917
| |
OUT(hw, w.cr, Page1|RD2|STP);
|
|
1992/0505
| |
OUT(hw, curr, hw->pstart+1);
|
|
1992/0917
| |
OUT(hw, w.cr, Page0|RD2|STA);
|
|
1992/0505
| |
}
|
|
1992/0424
| |
/*
* we leave the chip idling on internal loopback
* and pointing to Page0.
*/
static void
|
|
1992/0909
| |
dp8390init(Ctlr *cp)
|
|
1992/0403
| |
{
|
|
1992/0424
| |
Hw *hw = cp->hw;
int i;
|
|
1992/0917
| |
OUT(hw, w.cr, Page0|RD2|STP);
|
|
1992/0906
| |
if(hw->bt16)
|
|
1992/0917
| |
OUT(hw, w.dcr, (1<<0)|(3<<5)); /* 16 bit interface, 12 byte DMA burst */
|
|
1992/0906
| |
else
OUT(hw, w.dcr, 0x48); /* FT1|LS */
|
|
1992/0424
| |
OUT(hw, w.rbcr0, 0);
OUT(hw, w.rbcr1, 0);
|
|
1992/0915
| |
if(cp->prom)
OUT(hw, w.rcr, 0x14); /* PRO|AB */
else
OUT(hw, w.rcr, 0x04); /* AB */
|
|
1992/0424
| |
OUT(hw, w.tcr, 0x20); /* LB0 */
|
|
1992/0501
| |
OUT(hw, w.bnry, hw->pstart);
OUT(hw, w.pstart, hw->pstart);
OUT(hw, w.pstop, hw->pstop);
|
|
1992/0424
| |
OUT(hw, w.isr, 0xFF);
OUT(hw, w.imr, 0x1F); /* OVWE|TXEE|RXEE|PTXE|PRXE */
|
|
1992/0917
| |
OUT(hw, w.cr, Page1|RD2|STP);
|
|
1992/0424
| |
for(i = 0; i < sizeof(cp->ea); i++)
OUT(hw, par[i], cp->ea[i]);
|
|
1992/0501
| |
OUT(hw, curr, hw->pstart+1);
|
|
1992/0424
| |
|
|
1992/0917
| |
OUT(hw, w.cr, Page0|RD2|STA);
|
|
1992/0424
| |
OUT(hw, w.tpsr, 0);
|
|
1992/0403
| |
}
void
|
|
1992/0424
| |
wd8013mode(Ctlr *cp, int on)
|
|
1992/0403
| |
{
|
|
1992/0424
| |
qlock(cp);
if(on){
cp->prom++;
if(cp->prom == 1)
OUT(cp->hw, w.rcr, 0x14);/* PRO|AB */
}
else {
cp->prom--;
if(cp->prom == 0)
OUT(cp->hw, w.rcr, 0x04);/* AB */
}
qunlock(cp);
|
|
1992/0403
| |
}
|
|
1992/0424
| |
static void
wd8013online(Ctlr *cp, int on)
|
|
1992/0403
| |
{
|
|
1992/0711
| |
USED(on);
|
|
1992/0424
| |
OUT(cp->hw, w.tcr, 0);
|
|
1992/0403
| |
}
|
|
1992/0424
| |
static void
|
|
1992/0915
| |
wd8013tweek(Ctlr *cp)
{
uchar msr;
Hw *hw = cp->hw;
int s;
s = splhi();
msr = IN(hw, msr);
if((msr & MENB) == 0){
/* board has reset itself, start again */
delay(100);
(*hw->reset)(cp);
etherinit();
wakeup(&cp->tr);
wakeup(&cp->rr);
}
splx(s);
}
|
|
1992/0917
| |
/*
* hack to keep away from the card's memory while it is receiving
* a packet. This is only a problem on the NCR 3170 safari.
*
* we peek at the DMA registers and, if they are changing, wait.
*/
void
waitfordma(Hw *hw)
{
uchar a,b,c;
for(;;delay(10)){
a = IN(hw, r.clda0);
b = IN(hw, r.clda0);
if(a != b)
continue;
c = IN(hw, r.clda0);
if(c != b)
continue;
break;
}
}
|
|
1992/0915
| |
static void
|
|
1992/0424
| |
wd8013receive(Ctlr *cp)
|
|
1992/0403
| |
{
|
|
1992/0424
| |
Hw *hw = cp->hw;
Buffer *rb;
uchar bnry, curr, next;
Ring *p;
|
|
1992/0917
| |
int i, len;
|
|
1992/0424
| |
bnry = IN(hw, r.bnry);
|
|
1992/0501
| |
next = bnry+1;
if(next >= hw->pstop)
next = hw->pstart;
|
|
1992/0917
| |
for(i = 0; ; i++){
OUT(hw, w.cr, Page1|RD2|STA);
|
|
1992/0424
| |
curr = IN(hw, curr);
|
|
1992/0917
| |
OUT(hw, w.cr, Page0|RD2|STA);
|
|
1992/0424
| |
if(next == curr)
break;
|
|
1992/0918
| |
if(strcmp(machtype, "NCRD.0") == 0)
waitfordma(hw);
|
|
1992/0424
| |
cp->inpackets++;
p = &((Ring*)hw->ram)[next];
|
|
1992/0505
| |
len = ((p->len1<<8)|p->len0)-4;
if(p->next < hw->pstart || p->next >= hw->pstop || len < 60){
|
|
1992/0917
| |
/*print("%d/%d : #%2.2ux #%2.2ux #%2.2ux #%2.2ux\n", next, len,
|
|
1992/0909
| |
p->status, p->next, p->len0, p->len1);/**/
|
|
1992/0505
| |
dp8390rinit(cp);
|
|
1992/0905
| |
break;
|
|
1992/0505
| |
}
|
|
1992/0424
| |
rb = &cp->rb[cp->ri];
if(rb->owner == Interface){
|
|
1992/0501
| |
rb->len = len;
|
|
1992/0502
| |
if((p->data+len) >= (hw->ram+hw->size)){
|
|
1992/0503
| |
len = (hw->ram+hw->size) - p->data;
|
|
1992/0906
| |
memmove(rb->pkt+len,
|
|
1992/0501
| |
&((Ring*)hw->ram)[hw->pstart],
|
|
1992/0502
| |
(p->data+rb->len) - (hw->ram+hw->size));
|
|
1992/0425
| |
}
|
|
1992/0906
| |
memmove(rb->pkt, p->data, len);
|
|
1992/0424
| |
rb->owner = Host;
|
|
1992/0502
| |
cp->ri = NEXT(cp->ri, cp->nrb);
|
|
1992/0424
| |
}
|
|
1992/0502
| |
p->status = 0;
|
|
1992/0424
| |
next = p->next;
bnry = next-1;
|
|
1992/0501
| |
if(bnry < hw->pstart)
bnry = hw->pstop-1;
|
|
1992/0424
| |
OUT(hw, w.bnry, bnry);
}
|
|
1992/0403
| |
}
|
|
1992/0424
| |
static void
wd8013transmit(Ctlr *cp)
|
|
1992/0403
| |
{
|
|
1992/0424
| |
Hw *hw;
Buffer *tb;
int s;
s = splhi();
|
|
1992/0906
| |
hw = cp->hw;
|
|
1992/0424
| |
tb = &cp->tb[cp->ti];
if(tb->busy == 0 && tb->owner == Interface){
|
|
1992/0906
| |
memmove(hw->ram, tb->pkt, tb->len);
|
|
1992/0424
| |
OUT(hw, w.tbcr0, tb->len & 0xFF);
OUT(hw, w.tbcr1, (tb->len>>8) & 0xFF);
|
|
1992/0917
| |
OUT(hw, w.cr, Page0|RD2|TXP|STA);
|
|
1992/0424
| |
tb->busy = 1;
}
splx(s);
|
|
1992/0403
| |
}
|
|
1992/0424
| |
static void
wd8013intr(Ureg *ur)
|
|
1992/0403
| |
{
|
|
1992/0424
| |
Ctlr *cp = &ctlr[0];
Hw *hw = cp->hw;
Buffer *tb;
|
|
1992/0915
| |
uchar isr;
|
|
1992/0424
| |
|
|
1992/0711
| |
USED(ur);
|
|
1992/0424
| |
while(isr = IN(hw, r.isr)){
OUT(hw, w.isr, isr);
|
|
1992/0917
| |
/*
* we have received packets.
*/
if(isr & (0x04|0x01)){ /* Rxe|Prx - packet received */
(*cp->hw->receive)(cp);
wakeup(&cp->rr);
}
if(isr & 0x10) /* Ovw - overwrite warning */
cp->overflows++;
|
|
1992/0424
| |
if(isr & 0x08) /* Txe - transmit error */
cp->oerrs++;
if(isr & 0x04){ /* Rxe - receive error */
cp->frames += IN(hw, r.cntr0);
cp->crcs += IN(hw, r.cntr1);
cp->buffs += IN(hw, r.cntr2);
}
if(isr & 0x02) /* Ptx - packet transmitted */
cp->outpackets++;
/*
* a packet completed transmission, successfully or
* not. start transmission on the next buffered packet,
* and wake the output routine.
*/
if(isr & (0x08|0x02)){
tb = &cp->tb[cp->ti];
tb->owner = Host;
tb->busy = 0;
|
|
1992/0502
| |
cp->ti = NEXT(cp->ti, cp->ntb);
|
|
1992/0424
| |
(*cp->hw->transmit)(cp);
wakeup(&cp->tr);
}
}
|
|
1992/0409
| |
}
|
|
1992/0909
| |
static Hw wd8013 =
{
|
|
1992/0424
| |
wd8013reset,
|
|
1992/0909
| |
dp8390init,
|
|
1992/0424
| |
wd8013mode,
wd8013online,
wd8013receive,
wd8013transmit,
wd8013intr,
|
|
1992/0915
| |
wd8013tweek,
|
|
1992/0424
| |
};
|