summaryrefslogtreecommitdiff
path: root/os
diff options
context:
space:
mode:
Diffstat (limited to 'os')
-rw-r--r--os/ip/devip.c2
-rw-r--r--os/ip/ip.h1
-rw-r--r--os/ip/ipifc.c88
-rw-r--r--os/ip/iproute.c2
-rw-r--r--os/ip/ipv6.h14
-rw-r--r--os/ip/tcp.c72
-rw-r--r--os/pc/ether2000.c6
-rw-r--r--os/pc/ether2114x.c10
-rw-r--r--os/pc/ether79c970.c11
-rw-r--r--os/pc/ether8139.c12
-rw-r--r--os/pc/ether82543gc.c12
-rw-r--r--os/pc/ether82557.c26
-rw-r--r--os/pc/ether83815.c169
-rw-r--r--os/pc/ether8390.c6
-rw-r--r--os/pc/etherdp83820.c1246
-rw-r--r--os/pc/etherec2t.c1
-rw-r--r--os/pc/etherelnk3.c10
-rw-r--r--os/pc/etherga620.c143
-rw-r--r--os/pc/etherigbe.c97
-rw-r--r--os/pc/ethersmc.c1
-rw-r--r--os/pc/ethervt6102.c1025
-rw-r--r--os/pc/etherwavelan.c11
-rw-r--r--os/pc/fns.h4
-rw-r--r--os/pc/i8253.c2
-rw-r--r--os/pc/io.h50
-rw-r--r--os/pc/memory.c18
-rw-r--r--os/pc/mmu.c16
-rw-r--r--os/pc/pci.c1
-rw-r--r--os/port/chan.c34
-rw-r--r--os/port/dev.c2
-rw-r--r--os/port/ethermii.c6
-rw-r--r--os/port/lib.h5
32 files changed, 2847 insertions, 256 deletions
diff --git a/os/ip/devip.c b/os/ip/devip.c
index 8564e987..bb37d341 100644
--- a/os/ip/devip.c
+++ b/os/ip/devip.c
@@ -982,7 +982,6 @@ Fsstdannounce(Conv* c, char* argv[], int argc)
case 2:
return setladdrport(c, argv[1], 1);
}
- return nil;
}
/*
@@ -1033,7 +1032,6 @@ Fsstdbind(Conv* c, char* argv[], int argc)
case 2:
return setladdrport(c, argv[1], 0);
}
- return nil;
}
static void
diff --git a/os/ip/ip.h b/os/ip/ip.h
index ca49430a..5d504160 100644
--- a/os/ip/ip.h
+++ b/os/ip/ip.h
@@ -669,5 +669,4 @@ extern Chan* chandial(char*, char*, char*, Chan**);
/*
* global to all of the stack
*/
-extern int debug;
extern void (*igmpreportfn)(Ipifc*, uchar*);
diff --git a/os/ip/ipifc.c b/os/ip/ipifc.c
index 345c7404..a044a57e 100644
--- a/os/ip/ipifc.c
+++ b/os/ip/ipifc.c
@@ -11,11 +11,11 @@
#define DPRINT if(0)print
enum {
- Maxmedia = 32,
- Nself = Maxmedia*5,
- NHASH = (1<<6),
- NCACHE = 256,
- QMAX = 64*1024-1,
+ Maxmedia = 32,
+ Nself = Maxmedia*5,
+ NHASH = (1<<6),
+ NCACHE = 256,
+ QMAX = 64*1024-1,
};
Medium *media[Maxmedia] =
@@ -135,7 +135,7 @@ ipifcbind(Conv *c, char **argv, int argc)
if(argc > 2)
strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
else
- sprint(ifc->dev, "%s%d", m->name, c->x);
+ snprint(ifc->dev, sizeof ifc->dev, "%s%d", m->name, c->x);
ifc->dev[sizeof(ifc->dev)-1] = 0;
/* set up parameters */
@@ -144,15 +144,15 @@ ipifcbind(Conv *c, char **argv, int argc)
ifc->maxtu = ifc->m->maxtu;
if(ifc->m->unbindonclose == 0)
ifc->conv->inuse++;
- ifc->rp.mflag = 0; // default not managed
- ifc->rp.oflag = 0;
- ifc->rp.maxraint = 600000; // millisecs
- ifc->rp.minraint = 200000;
- ifc->rp.linkmtu = 0; // no mtu sent
- ifc->rp.reachtime = 0;
- ifc->rp.rxmitra = 0;
- ifc->rp.ttl = MAXTTL;
- ifc->rp.routerlt = 3*(ifc->rp.maxraint);
+ ifc->rp.mflag = 0; // default not managed
+ ifc->rp.oflag = 0;
+ ifc->rp.maxraint = 600000; // millisecs
+ ifc->rp.minraint = 200000;
+ ifc->rp.linkmtu = 0; // no mtu sent
+ ifc->rp.reachtime = 0;
+ ifc->rp.rxmitra = 0;
+ ifc->rp.ttl = MAXTTL;
+ ifc->rp.routerlt = 3*(ifc->rp.maxraint);
/* any ancillary structures (like routes) no longer pertain */
ifc->ifcid++;
@@ -229,7 +229,7 @@ ipifcstate(Conv *c, char *state, int n)
ifc = (Ipifc*)c->ptcl;
- m = snprint(state, n, sfixedformat,
+ m = snprint(state, n, sfixedformat,
ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
@@ -328,7 +328,7 @@ ipifccreate(Conv *c)
ifc->reassemble = 0;
}
-/*
+/*
* called after last close of ipifc data or ctl
* called with c locked, we must unlock
*/
@@ -424,7 +424,7 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
/* ignore if this is already a local address for this ifc */
for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
if(ipcmp(lifc->local, ip) == 0) {
- if(lifc->tentative != tentative)
+ if(lifc->tentative != tentative)
lifc->tentative = tentative;
if(lifcp != nil) {
lifc->onlink = lifcp->onlink;
@@ -506,7 +506,7 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
addselfcache(f, ifc, lifc, bcast, Rbcast);
addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
- }
+ }
else {
if(ipcmp(ip, v6loopback) == 0) {
/* add node-local mcast address */
@@ -535,7 +535,7 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
out:
wunlock(ifc);
- if(tentative && sendnbrdisc)
+ if(tentative && sendnbrdisc)
icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
return nil;
}
@@ -721,29 +721,29 @@ ipifcsetpar6(Ipifc *ifc, char **argv, int argc)
return Ebadarg;
while (argsleft > 1) {
- if(strcmp(argv[i],"recvra")==0)
+ if(strcmp(argv[i],"recvra")==0)
ifc->recvra6 = (atoi(argv[i+1]) != 0);
- else if(strcmp(argv[i],"sendra")==0)
+ else if(strcmp(argv[i],"sendra")==0)
ifc->sendra6 = (atoi(argv[i+1]) != 0);
- else if(strcmp(argv[i],"mflag")==0)
+ else if(strcmp(argv[i],"mflag")==0)
ifc->rp.mflag = (atoi(argv[i+1]) != 0);
- else if(strcmp(argv[i],"oflag")==0)
+ else if(strcmp(argv[i],"oflag")==0)
ifc->rp.oflag = (atoi(argv[i+1]) != 0);
else if(strcmp(argv[i],"maxraint")==0)
ifc->rp.maxraint = atoi(argv[i+1]);
else if(strcmp(argv[i],"minraint")==0)
ifc->rp.minraint = atoi(argv[i+1]);
- else if(strcmp(argv[i],"linkmtu")==0)
+ else if(strcmp(argv[i],"linkmtu")==0)
ifc->rp.linkmtu = atoi(argv[i+1]);
- else if(strcmp(argv[i],"reachtime")==0)
+ else if(strcmp(argv[i],"reachtime")==0)
ifc->rp.reachtime = atoi(argv[i+1]);
- else if(strcmp(argv[i],"rxmitra")==0)
+ else if(strcmp(argv[i],"rxmitra")==0)
ifc->rp.rxmitra = atoi(argv[i+1]);
- else if(strcmp(argv[i],"ttl")==0)
+ else if(strcmp(argv[i],"ttl")==0)
ifc->rp.ttl = atoi(argv[i+1]);
- else if(strcmp(argv[i],"routerlt")==0)
+ else if(strcmp(argv[i],"routerlt")==0)
ifc->rp.routerlt = atoi(argv[i+1]);
- else
+ else
return Ebadarg;
argsleft -= 2;
@@ -778,7 +778,7 @@ ipifcrecvra6(Ipifc *ifc, char **argv, int argc)
int i;
i = 0;
- if(argc > 1)
+ if(argc > 1)
i = atoi(argv[1]);
ifc->recvra6 = (i!=0);
return nil;
@@ -826,7 +826,7 @@ ipifcctl(Conv* c, char**argv, int argc)
return ipifcaddpref6(ifc, argv, argc);
else if(strcmp(argv[0], "setpar6") == 0)
return ipifcsetpar6(ifc, argv, argc);
- else if(strcmp(argv[0], "sendra6") == 0)
+ else if(strcmp(argv[0], "sendra6") == 0)
return ipifcsendra6(ifc, argv, argc);
else if(strcmp(argv[0], "recvra6") == 0)
return ipifcrecvra6(ifc, argv, argc);
@@ -1097,7 +1097,7 @@ ipselftabread(Fs *f, char *cp, ulong offset, int n)
}
int
-iptentative(Fs *f, uchar *addr)
+iptentative(Fs *f, uchar *addr)
{
Ipself *p;
@@ -1210,8 +1210,8 @@ v6addrtype(uchar *addr)
#define v6addrcurr(lifc) (( (lifc)->origint + (lifc)->preflt >= (NOW/10^3) ) || ( (lifc)->preflt == 0xffffffff ))
-void
-findprimaryip6(Fs *f, uchar *local)
+static void
+findprimaryipv6(Fs *f, uchar *local)
{
Conv **cp, **e;
Ipifc *ifc;
@@ -1231,7 +1231,7 @@ findprimaryip6(Fs *f, uchar *local)
ifc = (Ipifc*)(*cp)->ptcl;
for(lifc = ifc->lifc; lifc; lifc = lifc->next){
atypel = v6addrtype(lifc->local);
- if(atypel > atype)
+ if(atypel > atype)
if(v6addrcurr(lifc)) {
ipmove(local, lifc->local);
atype = atypel;
@@ -1243,10 +1243,10 @@ findprimaryip6(Fs *f, uchar *local)
}
/*
- * returns first ip address configured
+ * returns first ip address configured
*/
-void
-findprimaryip(Fs *f, uchar *local)
+static void
+findprimaryipv4(Fs *f, uchar *local)
{
Conv **cp, **e;
Ipifc *ifc;
@@ -1258,7 +1258,7 @@ findprimaryip(Fs *f, uchar *local)
if(*cp == 0)
continue;
ifc = (Ipifc*)(*cp)->ptcl;
- for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ if((lifc = ifc->lifc) != nil){
ipmove(local, lifc->local);
return;
}
@@ -1329,10 +1329,10 @@ findlocalip(Fs *f, uchar *local, uchar *remote)
switch(version){
case V4:
- findprimaryip(f, local);
+ findprimaryipv4(f, local);
break;
case V6:
- findprimaryip6(f, local);
+ findprimaryipv6(f, local);
break;
default:
panic("findlocalip2: version %d", version);
@@ -1642,7 +1642,7 @@ adddefroute6(Fs *f, uchar *gate, int force)
Route *r;
r = v6lookup(f, v6Unspecified, nil);
- if(r!=nil)
+ if(r!=nil)
if(!(force) && (strcmp(r->tag,"ra")!=0)) // route entries generated
return; // by all other means take
// precedence over router annc
@@ -1705,7 +1705,7 @@ ipifcaddpref6(Ipifc *ifc, char**argv, int argc)
lifc->preflt = preflt;
lifc->origint = origint;
- if(ifc->m->pref2addr!=nil)
+ if(ifc->m->pref2addr!=nil)
ifc->m->pref2addr(prefix, ifc->mac);
else
return Ebadarg;
diff --git a/os/ip/iproute.c b/os/ip/iproute.c
index 3229435e..1888a89c 100644
--- a/os/ip/iproute.c
+++ b/os/ip/iproute.c
@@ -662,7 +662,7 @@ sprintroute(Route *r, Routewalk *rw)
iname = "-";
if(nifc != -1) {
iname = ifbuf;
- sprint(ifbuf, "%d", nifc);
+ snprint(ifbuf, sizeof ifbuf, "%d", nifc);
}
p = seprint(rw->p, rw->e, rformat, addr, mask, gate, t, r->tag, iname);
if(rw->o < 0){
diff --git a/os/ip/ipv6.h b/os/ip/ipv6.h
index 8da63cfd..d0a06cf5 100644
--- a/os/ip/ipv6.h
+++ b/os/ip/ipv6.h
@@ -61,12 +61,12 @@ enum { /* Header Types */
RSVP = 46,
AH = 51,
ESP = 52,
- ICMPv6 = 58,
+ ICMPv6 = 58,
NNH = 59,
DOH = 60,
ISO_IP = 80,
IGRP = 88,
- OSPF = 89,
+ OSPF = 89,
Maxhdrtype = 256,
};
@@ -98,7 +98,7 @@ enum {
// various flags & constants
- v6MINTU = 1280,
+ v6MINTU = 1280,
HOP_LIMIT = 255,
ETHERHDR_LEN = 14,
IPV6HDR_LEN = 40,
@@ -113,7 +113,7 @@ enum {
MTU_OPTION = 5,
SRC_UNSPEC = 0,
- SRC_UNI = 1,
+ SRC_UNI = 1,
TARG_UNI = 2,
TARG_MULTI = 3,
@@ -124,7 +124,7 @@ enum {
// Router constants (all times in milliseconds)
MAX_INITIAL_RTR_ADVERT_INTERVAL = 16000,
- MAX_INITIAL_RTR_ADVERTISEMENTS = 3,
+ MAX_INITIAL_RTR_ADVERTISEMENTS = 3,
MAX_FINAL_RTR_ADVERTISEMENTS = 3,
MIN_DELAY_BETWEEN_RAS = 3000,
MAX_RA_DELAY_TIME = 500,
@@ -140,9 +140,9 @@ enum {
MAX_MULTICAST_SOLICIT = 3,
MAX_UNICAST_SOLICIT = 3,
MAX_ANYCAST_DELAY_TIME = 1000,
- MAX_NEIGHBOR_ADVERTISEMENT = 3,
+ MAX_NEIGHBOR_ADVERTISEMENT = 3,
REACHABLE_TIME = 30000,
- RETRANS_TIMER = 1000,
+ RETRANS_TIMER = 1000,
DELAY_FIRST_PROBE_TIME = 5000,
};
diff --git a/os/ip/tcp.c b/os/ip/tcp.c
index c2bf7274..c6e0a54f 100644
--- a/os/ip/tcp.c
+++ b/os/ip/tcp.c
@@ -54,7 +54,7 @@ enum
TCP_CONNECT = 1, /* Outgoing connection */
SYNACK_RXTIMER = 250, /* ms between SYNACK retransmits */
- TCPREXMTTHRESH = 3, /* dupack threshhold for rxt */
+ TCPREXMTTHRESH = 3, /* dupack threshhold for rxt */
FORCE = 1,
CLONE = 2,
@@ -285,7 +285,7 @@ struct Limbo
};
int tcp_irtt = DEF_RTT; /* Initial guess at round trip time */
-ushort tcp_mss = DEF_MSS; /* Maximum segment size to be sent */
+ushort tcp_mss = DEF_MSS; /* Maximum segment size to be sent */
enum {
/* MIB stats */
@@ -350,7 +350,7 @@ struct Tcppriv
ulong stats[Nstats];
};
-/*
+/*
* Setting tcpporthogdefense to non-zero enables Dong Lin's
* solution to hijacked systems staking out port's as a form
* of DoS attack.
@@ -375,7 +375,7 @@ void tcprcvwin(Conv*);
void tcpacktimer(void*);
void tcpkeepalive(void*);
void tcpsetkacounter(Tcpctl*);
-void tcprxmit(Conv*);
+void tcprxmit(Conv*);
void tcpsettimer(Tcpctl*);
void tcpsynackrtt(Conv*);
void tcpsetscale(Conv*, Tcpctl*, ushort, ushort);
@@ -711,7 +711,7 @@ backoff(int n)
}
void
-localclose(Conv *s, char *reason) /* called with tcb locked */
+localclose(Conv *s, char *reason) /* called with tcb locked */
{
Tcpctl *tcb;
Reseq *rp,*rp1;
@@ -1804,8 +1804,8 @@ update(Conv *s, Tcp *seg)
/*
* update window
*/
- if( seq_gt(seg->ack, tcb->snd.wl2)
- || (tcb->snd.wl2 == seg->ack && seg->wnd > tcb->snd.wnd)){
+ if(seq_gt(seg->ack, tcb->snd.wl2)
+ || (tcb->snd.wl2 == seg->ack && seg->wnd > tcb->snd.wnd)){
tcb->snd.wnd = seg->wnd;
tcb->snd.wl2 = seg->ack;
}
@@ -1821,9 +1821,9 @@ update(Conv *s, Tcp *seg)
return;
}
- /*
+ /*
* any positive ack turns off fast rxt,
- * (should we do new-reno on partial acks?)
+ * (should we do new-reno on partial acks?)
*/
if(!tcb->snd.recovery || seq_ge(seg->ack, tcb->snd.rxt)) {
tcb->snd.dupacks = 0;
@@ -1925,7 +1925,7 @@ tcpiput(Proto *tcp, Ipifc*, Block *bp)
f = tcp->f;
tpriv = tcp->priv;
-
+
tpriv->stats[InSegs]++;
h4 = (Tcp4hdr*)(bp->rp);
@@ -1939,7 +1939,7 @@ tcpiput(Proto *tcp, Ipifc*, Block *bp)
h4->Unused = 0;
hnputs(h4->tcplen, length-TCP4_PKT);
- if(!(bp->flag & Btcpck) && (h4->tcpcksum[0] || h4->tcpcksum[1]) &&
+ if(!(bp->flag & Btcpck) && (h4->tcpcksum[0] || h4->tcpcksum[1]) &&
ptclcsum(bp, TCP4_IPLEN, length-TCP4_IPLEN)) {
tpriv->stats[CsumErrs]++;
tpriv->stats[InErrs]++;
@@ -1978,7 +1978,7 @@ tcpiput(Proto *tcp, Ipifc*, Block *bp)
h6->ploadlen[0] = h6->ploadlen[1] = h6->proto = 0;
h6->ttl = proto;
hnputl(h6->vcf, length);
- if((h6->tcpcksum[0] || h6->tcpcksum[1]) &&
+ if((h6->tcpcksum[0] || h6->tcpcksum[1]) &&
ptclcsum(bp, TCP6_IPLEN, length+TCP6_PHDRSIZE)) {
tpriv->stats[CsumErrs]++;
tpriv->stats[InErrs]++;
@@ -2277,7 +2277,7 @@ reset:
qpassnolim(s->rq, bp);
bp = nil;
- /*
+ /*
* Force an ack every 2 data messages. This is
* a hack for rob to make his home system run
* faster.
@@ -2412,20 +2412,20 @@ tcpoutput(Conv *s)
for(msgs = 0; msgs < 100; msgs++) {
tcb = (Tcpctl*)s->ptcl;
-
+
switch(tcb->state) {
case Listen:
case Closed:
case Finwait2:
return;
}
-
+
/* force an ack when a window has opened up */
if(tcb->rcv.blocked && tcb->rcv.wnd > 0){
tcb->rcv.blocked = 0;
tcb->flags |= FORCE;
}
-
+
sndcnt = qlen(s->wq)+tcb->flgcnt;
sent = tcb->snd.ptr - tcb->snd.una;
@@ -2841,8 +2841,7 @@ int
addreseq(Tcpctl *tcb, Tcppriv *tpriv, Tcp *seg, Block *bp, ushort length)
{
Reseq *rp, *rp1;
- int i;
- static int once;
+ int i, rqlen, qmax;
rp = malloc(sizeof(Reseq));
if(rp == nil){
@@ -2864,9 +2863,9 @@ addreseq(Tcpctl *tcb, Tcppriv *tpriv, Tcp *seg, Block *bp, ushort length)
return 0;
}
- length = 0;
+ rqlen = 0;
for(i = 0;; i++) {
- length += rp1->length;
+ rqlen += rp1->length;
if(rp1->next == nil || seq_lt(seg->seq, rp1->next->seg.seq)) {
rp->next = rp1->next;
rp1->next = rp;
@@ -2876,12 +2875,29 @@ addreseq(Tcpctl *tcb, Tcppriv *tpriv, Tcp *seg, Block *bp, ushort length)
}
rp1 = rp1->next;
}
- if(length > QMAX && once++ == 0){
- print("very long tcp resequence queue: %d\n", length);
- for(rp1 = tcb->reseq, i = 0; i < 10 && rp1 != nil; rp1 = rp1->next, i++)
- print("0x%lux 0x%lux 0x%ux\n", rp1->seg.seq, rp1->seg.ack,
- rp1->seg.flags);
- return -1;
+ qmax = QMAX<<tcb->rcv.scale;
+ if(rqlen > qmax){
+ print("resequence queue > window: %d > %d\n", rqlen, qmax);
+ i = 0;
+ for(rp1 = tcb->reseq; rp1 != nil; rp1 = rp1->next){
+ print("%#lux %#lux %#ux\n", rp1->seg.seq,
+ rp1->seg.ack, rp1->seg.flags);
+ if(i++ > 10){
+ print("...\n");
+ break;
+ }
+ }
+
+ // delete entire reassembly queue; wait for retransmit.
+ // - should we be smarter and only delete the tail?
+ for(rp = tcb->reseq; rp != nil; rp = rp1){
+ rp1 = rp->next;
+ freeblist(rp->bp);
+ free(rp);
+ }
+ tcb->reseq = nil;
+
+ return -1;
}
return 0;
}
@@ -2994,7 +3010,7 @@ tcpadvise(Proto *tcp, Block *bp, char *msg)
v4tov6(source, h4->tcpsrc);
psource = nhgets(h4->tcpsport);
pdest = nhgets(h4->tcpdport);
- }
+ }
else {
ipmove(dest, h6->tcpdst);
ipmove(source, h6->tcpsrc);
@@ -3122,7 +3138,7 @@ tcpsettimer(Tcpctl *tcb)
/* round trip dependency */
x = backoff(tcb->backoff) *
- (tcb->mdev + (tcb->srtt>>LOGAGAIN) + MSPTICK) / MSPTICK;
+ (tcb->mdev + (tcb->srtt>>LOGAGAIN) + MSPTICK) / MSPTICK;
/* bounded twixt 1/2 and 64 seconds */
if(x < 500/MSPTICK)
diff --git a/os/pc/ether2000.c b/os/pc/ether2000.c
index 4ea8fd4f..8fc8911e 100644
--- a/os/pc/ether2000.c
+++ b/os/pc/ether2000.c
@@ -132,7 +132,6 @@ ne2000pnp(Ether* edev)
static int
ne2000reset(Ether* edev)
{
- static int first;
ushort buf[16];
ulong port;
Dp8390 *dp8390;
@@ -198,11 +197,14 @@ ne2000reset(Ether* edev)
* initialisation has been tried, but that wouldn't be
* enough, there are other ethernet boards which could
* match.
+ * Parallels has buf[0x0E] == 0x00 whereas real hardware
+ * usually has 0x57.
*/
dp8390reset(edev);
memset(buf, 0, sizeof(buf));
dp8390read(dp8390, buf, 0, sizeof(buf));
- if((buf[0x0E] & 0xFF) != 0x57 || (buf[0x0F] & 0xFF) != 0x57){
+ i = buf[0x0E] & 0xFF;
+ if((i != 0x00 && i != 0x57) || (buf[0x0F] & 0xFF) != 0x57){
iofree(edev->port);
free(edev->ctlr);
return -1;
diff --git a/os/pc/ether2114x.c b/os/pc/ether2114x.c
index 43bae880..f71773c0 100644
--- a/os/pc/ether2114x.c
+++ b/os/pc/ether2114x.c
@@ -190,6 +190,7 @@ enum { /* Variants */
Pnic = (0x0002<<16)|0x11AD,
Pnic2 = (0xC115<<16)|0x11AD,
CentaurP = (0x0985<<16)|0x1317,
+ CentaurPcb = (0x1985<<16)|0x1317,
};
typedef struct Ctlr Ctlr;
@@ -1515,7 +1516,7 @@ srom(Ctlr* ctlr)
ctlr->srom[20+i+1] = ctlr->srom[i];
}
}
- if(ctlr->id == CentaurP){
+ if(ctlr->id == CentaurP || ctlr->id == CentaurPcb){
memmove(&ctlr->srom[20], leafpnic, sizeof(leafpnic));
for(i = 0; i < Eaddrlen; i += 2){
ctlr->srom[20+i] = ctlr->srom[8+i];
@@ -1603,7 +1604,7 @@ srom(Ctlr* ctlr)
if(phy){
x = 0;
for(k = 0; k < nelem(ctlr->phy); k++){
- if(ctlr->id == CentaurP && k != 1)
+ if((ctlr->id == CentaurP || ctlr->id == CentaurPcb) && k != 1)
continue;
if((oui = miir(ctlr, k, 2)) == -1 || oui == 0)
continue;
@@ -1655,6 +1656,7 @@ dec2114xpci(void)
case Pnic: /* PNIC */
case Pnic2: /* PNIC-II */
case CentaurP: /* ADMtek */
+ case CentaurPcb: /* ADMtek CardBus */
break;
}
@@ -1690,7 +1692,6 @@ dec2114xpci(void)
switch(ctlr->id){
default:
break;
-
case Pnic: /* PNIC */
/*
* Turn off the jabber timer.
@@ -1698,6 +1699,7 @@ dec2114xpci(void)
csr32w(ctlr, 15, 0x00000001);
break;
case CentaurP:
+ case CentaurPcb:
/*
* Nice - the register offsets change from *8 to *4
* for CSR16 and up...
@@ -1823,6 +1825,6 @@ reset(Ether* ether)
void
ether2114xlink(void)
{
- addethercard("21140", reset);
addethercard("2114x", reset);
+ addethercard("21140", reset);
}
diff --git a/os/pc/ether79c970.c b/os/pc/ether79c970.c
index 25bf4185..43924a3f 100644
--- a/os/pc/ether79c970.c
+++ b/os/pc/ether79c970.c
@@ -301,6 +301,12 @@ promiscuous(void* arg, int on)
}
static void
+multicast(void* arg, uchar*, int)
+{
+ promiscuous(arg, 1);
+}
+
+static void
txstart(Ether* ether)
{
Ctlr *ctlr;
@@ -522,7 +528,6 @@ reset(Ether* ether)
ctlr->iow = io32w;
}else{
print("#l%d: card doesn't talk right\n", ether->ctlrno);
-iprint("#l%d: card doesn't talk right\n", ether->ctlrno);
iunlock(ctlr);
return -1;
}
@@ -539,8 +544,6 @@ iprint("#l%d: card doesn't talk right\n", ether->ctlrno);
default:
print("#l%d: unknown PCnet card version %.7ux\n",
ether->ctlrno, x&0xFFFFFFF);
-iprint("#l%d: unknown PCnet card version %.7ux\n",
- ether->ctlrno, x&0xFFFFFFF);
iunlock(ctlr);
return -1;
}
@@ -629,6 +632,8 @@ iprint("#l%d: unknown PCnet card version %.7ux\n",
ether->arg = ether;
ether->promiscuous = promiscuous;
+ ether->multicast = multicast;
+// ether->shutdown = shutdown;
return 0;
}
diff --git a/os/pc/ether8139.c b/os/pc/ether8139.c
index 12deba1b..dd3653e3 100644
--- a/os/pc/ether8139.c
+++ b/os/pc/ether8139.c
@@ -234,6 +234,12 @@ rtl8139promiscuous(void* arg, int on)
iunlock(&ctlr->ilock);
}
+static void
+rtl8139multicast(void* arg, uchar*, int)
+{
+ rtl8139promiscuous(arg, 1);
+}
+
static long
rtl8139ifstat(Ether* edev, void* a, long n, ulong offset)
{
@@ -637,8 +643,10 @@ rtl8139match(Ether* edev, int id)
}
ctlr->port = port;
- if(rtl8139reset(ctlr))
+ if(rtl8139reset(ctlr)) {
+ iofree(port);
continue;
+ }
pcisetbme(p);
ctlr->active = 1;
@@ -738,6 +746,8 @@ rtl8139pnp(Ether* edev)
edev->arg = edev;
edev->promiscuous = rtl8139promiscuous;
+ edev->multicast = rtl8139multicast;
+// edev->shutdown = rtl8139shutdown;
/*
* This should be much more dynamic but will do for now.
diff --git a/os/pc/ether82543gc.c b/os/pc/ether82543gc.c
index 6277b10b..86ec7b75 100644
--- a/os/pc/ether82543gc.c
+++ b/os/pc/ether82543gc.c
@@ -1243,7 +1243,8 @@ gc82543watchdog(void* arg)
static void
gc82543pci(void)
{
- int port, cls;
+ int cls;
+ void *mem;
Pcidev *p;
Ctlr *ctlr;
@@ -1262,8 +1263,8 @@ gc82543pci(void)
break;
}
- port = upamalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0);
- if(port == 0){
+ mem = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size);
+ if(mem == 0){
print("gc82543: can't map %8.8luX\n", p->mem[0].bar);
continue;
}
@@ -1280,11 +1281,10 @@ gc82543pci(void)
cls*4);
}
ctlr = malloc(sizeof(Ctlr));
- ctlr->port = port;
+ ctlr->port = p->mem[0].bar & ~0x0F;
ctlr->pcidev = p;
ctlr->id = (p->did<<16)|p->vid;
-
- ctlr->nic = KADDR(ctlr->port);
+ ctlr->nic = mem;
if(gc82543reset(ctlr)){
free(ctlr);
diff --git a/os/pc/ether82557.c b/os/pc/ether82557.c
index b61e3e1c..4dba07bd 100644
--- a/os/pc/ether82557.c
+++ b/os/pc/ether82557.c
@@ -290,7 +290,7 @@ command(Ctlr* ctlr, int c, int v)
if(timeo >= 100){
ctlr->command = -1;
iunlock(&ctlr->rlock);
- iprint("i82557: command 0x%uX %uX timeout\n", c, v);
+ iprint("i82557: command %#ux %#ux timeout\n", c, v);
return;
}
@@ -462,7 +462,7 @@ ifstat(Ether* ether, void* a, long n, ulong offset)
for(i = 0; i < (1<<ctlr->eepromsz); i++){
if(i && ((i & 0x07) == 0))
len += snprint(p+len, READSTR-len, "\n ");
- len += snprint(p+len, READSTR-len, " %4.4uX", ctlr->eeprom[i]);
+ len += snprint(p+len, READSTR-len, " %4.4ux", ctlr->eeprom[i]);
}
if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)){
@@ -471,7 +471,7 @@ ifstat(Ether* ether, void* a, long n, ulong offset)
for(i = 0; i < 6; i++){
static int miir(Ctlr*, int, int);
- len += snprint(p+len, READSTR-len, " %4.4uX",
+ len += snprint(p+len, READSTR-len, " %4.4ux",
miir(ctlr, phyaddr, i));
}
}
@@ -523,7 +523,7 @@ txstart(Ether* ether)
ctlr->action = 0;
}
else{
- print("#l%d: action 0x%uX\n", ether->ctlrno, ctlr->action);
+ print("#l%d: action %#ux\n", ether->ctlrno, ctlr->action);
ctlr->action = 0;
break;
}
@@ -630,14 +630,14 @@ receive(Ether* ether)
pbp = nil;
count = rfd->count & 0x3FFF;
if((count < ETHERMAXTU/4) && (pbp = iallocb(count))){
- memmove(pbp->rp, bp->rp+sizeof(Rfd)-sizeof(rfd->data), count);
+ memmove(pbp->rp, bp->rp+offsetof(Rfd, data[0]), count);
pbp->wp = pbp->rp + count;
rfd->count = 0;
rfd->field = 0;
}
else if(xbp = rfdalloc(rfd->link)){
- bp->rp += sizeof(Rfd)-sizeof(rfd->data);
+ bp->rp += offsetof(Rfd, data[0]);
bp->wp = bp->rp + count;
xbp->next = bp->next;
@@ -748,7 +748,7 @@ interrupt(Ureg*, void* arg)
}
if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))
- panic("#l%d: status %uX\n", ether->ctlrno, status);
+ panic("#l%d: status %#ux\n", ether->ctlrno, status);
}
}
@@ -926,14 +926,16 @@ i82557pci(void)
continue;
case 0x1031: /* Intel 82562EM */
case 0x1050: /* Intel 82562EZ */
+ case 0x1039: /* Intel 82801BD PRO/100 VE */
+ case 0x103A: /* Intel 82562 PRO/100 VE */
+ case 0x103D: /* Intel 82562 PRO/100 VE */
+ case 0x1064: /* Intel 82562 PRO/100 VE */
case 0x2449: /* Intel 82562ET */
nop = 1;
/*FALLTHROUGH*/
case 0x1209: /* Intel 82559ER */
case 0x1229: /* Intel 8255[789] */
case 0x1030: /* Intel 82559 InBusiness 10/100 */
- case 0x1039: /* Intel 82801BD PRO/100 VE */
- case 0x103A: /* Intel 82562 PRO/100 VE */
break;
}
@@ -955,7 +957,7 @@ i82557pci(void)
*/
port = p->mem[1].bar & ~0x01;
if(ioalloc(port, p->mem[1].size, 0, "i82557") < 0){
- print("i82557: port 0x%uX in use\n", port);
+ print("i82557: port %#ux in use\n", port);
continue;
}
@@ -997,7 +999,7 @@ scanphy(Ctlr* ctlr)
oui <<= 6;
x = miir(ctlr, i, 3);
oui |= x>>10;
- //print("phy%d: oui %uX reg1 %uX\n", i, oui, miir(ctlr, i, 1));
+ //print("phy%d: oui %#ux reg1 %#ux\n", i, oui, miir(ctlr, i, 1));
ctlr->eeprom[6] = i;
if(oui == 0xAA00)
@@ -1093,7 +1095,7 @@ reset(Ether* ether)
sum += x;
}
if(sum != 0xBABA)
- print("#l%d: EEPROM checksum - 0x%4.4uX\n", ether->ctlrno, sum);
+ print("#l%d: EEPROM checksum - %#4.4ux\n", ether->ctlrno, sum);
/*
* Eeprom[6] indicates whether there is a PHY and whether
diff --git a/os/pc/ether83815.c b/os/pc/ether83815.c
index 2059bad4..3d2d9d76 100644
--- a/os/pc/ether83815.c
+++ b/os/pc/ether83815.c
@@ -79,9 +79,22 @@ enum { /* cmdsts */
Col = 1<<16, /* collision during receive */
};
-enum { /* Variants */
+enum { /* PCI vendor & device IDs */
Nat83815 = (0x0020<<16)|0x100B,
- Sis900 = (0x0630<<16)|0x1039, /* untested */
+ SiS = 0x1039,
+ SiS900 = (0x0900<<16)|SiS,
+ SiS7016 = (0x7016<<16)|SiS,
+
+ SiS630bridge = 0x0008,
+
+ /* SiS 900 PCI revision codes */
+ SiSrev630s = 0x81,
+ SiSrev630e = 0x82,
+ SiSrev630ea1 = 0x83,
+
+ SiSeenodeaddr = 8, /* short addr of SiS eeprom mac addr */
+ SiS630eenodeaddr = 9, /* likewise for the 630 */
+ Nseenodeaddr = 6, /* " for NS eeprom */
};
typedef struct Ctlr Ctlr;
@@ -456,9 +469,9 @@ txrxcfg(Ctlr *ctlr, int txdrth)
static void
interrupt(Ureg*, void* arg)
{
+ int len, status, cmdsts, n;
Ctlr *ctlr;
Ether *ether;
- int len, status, cmdsts;
Des *des;
Block *bp;
@@ -483,6 +496,15 @@ interrupt(Ureg*, void* arg)
status &= ~(Hiberr|Txrcmp|Rxrcmp|Rxsovr|Dperr|Sserr|Rmabt|Rtabt);
}
+ /* update link state */
+ if(status&Phy){
+ status &= ~Phy;
+ csr32r(ctlr, Rcfg);
+ n = csr32r(ctlr, Rcfg);
+// iprint("83815 phy %x %x\n", n, n&Lnksts);
+ ether->link = (n&Lnksts) != 0;
+ }
+
/*
* Received packets.
*/
@@ -511,11 +533,19 @@ interrupt(Ureg*, void* arg)
}
else if(bp = iallocb(Rbsz)){
len = (cmdsts&Size)-4;
- des->bp->wp = des->bp->rp+len;
- etheriq(ether, des->bp, 1);
+ if(len <= 0){
+ debug("ns83815: packet len %d <=0\n", len);
+ freeb(des->bp);
+ }else{
+ des->bp->wp = des->bp->rp+len;
+ etheriq(ether, des->bp, 1);
+ }
des->bp = bp;
des->addr = PADDR(bp->rp);
coherence();
+ }else{
+ debug("ns83815: interrupt: iallocb for input buffer failed\n");
+ des->bp->next = 0;
}
des->cmdsts = Rbsz;
@@ -607,7 +637,7 @@ ctlrinit(Ether* ether)
last = nil;
for(des = ctlr->rdr; des < &ctlr->rdr[ctlr->nrdr]; des++){
des->bp = iallocb(Rbsz);
- if (des->bp == nil)
+ if(des->bp == nil)
error(Enomem);
des->cmdsts = Rbsz;
des->addr = PADDR(des->bp->rp);
@@ -635,8 +665,10 @@ ctlrinit(Ether* ether)
txrxcfg(ctlr, Drth512);
- csr32w(ctlr, Rimr, Dperr|Sserr|Rmabt|Rtabt|Rxsovr|Hiberr|Txurn|Txerr|Txdesc|Txok|Rxorn|Rxerr|Rxdesc|Rxok); /* Phy|Pme|Mib */
- csr32r(ctlr, Risr); /* clear status */
+ csr32w(ctlr, Rimr, Dperr|Sserr|Rmabt|Rtabt|Rxsovr|Hiberr|Txurn|Txerr|
+ Txdesc|Txok|Rxorn|Rxerr|Rxdesc|Rxok); /* Phy|Pme|Mib */
+ csr32w(ctlr, Rmicr, Inten); /* enable phy interrupts */
+ csr32r(ctlr, Risr); /* clear status */
csr32w(ctlr, Rier, Ie);
}
@@ -762,7 +794,7 @@ softreset(Ctlr* ctlr, int resetphys)
if(csr16r(ctlr, Ranar) == 0 || (csr32r(ctlr, Rcfg) & Aneg_dn) == 0){
csr16w(ctlr, Rbmcr, Anena|Anrestart);
for(i=0;; i++){
- if(i > 6000){
+ if(i > 3000){
print("ns83815: auto neg timed out\n");
break;
}
@@ -791,11 +823,8 @@ media(Ether* ether)
ctlr = ether->ctlr;
cfg = csr32r(ctlr, Rcfg);
ctlr->fd = (cfg & Fdup) != 0;
- if(cfg & Speed100)
- return 100;
- if((cfg & Lnksts) == 0)
- return 100; /* no link: use 100 to ensure larger queues */
- return 10;
+ ether->link = (cfg&Lnksts) != 0;
+ return (cfg&(Lnksts|Speed100)) == Lnksts? 10: 100;
}
static char* mediatable[9] = {
@@ -810,8 +839,82 @@ static char* mediatable[9] = {
"100BASE-FXFD",
};
+static int
+is630(ulong id, Pcidev *p)
+{
+ if(id == SiS900)
+ switch (p->rid) {
+ case SiSrev630s:
+ case SiSrev630e:
+ case SiSrev630ea1:
+ return 1;
+ }
+ return 0;
+}
+
+enum {
+ MagicReg = 0x48,
+ MagicRegSz = 1,
+ Magicrden = 0x40, /* read enable, apparently */
+ Paddr= 0x70, /* address port */
+ Pdata= 0x71, /* data port */
+};
+
+/* rcmos() originally from LANL's SiS 900 driver's rcmos() */
+static int
+sisrdcmos(Ctlr *ctlr)
+{
+ int i;
+ unsigned reg;
+ ulong port;
+ Pcidev *p;
+
+ debug("ns83815: SiS 630 rev. %ux reading mac address from cmos\n", ctlr->pcidev->rid);
+ p = pcimatch(nil, SiS, SiS630bridge);
+ if(p == nil) {
+ print("ns83815: no SiS 630 rev. %ux bridge for mac addr\n",
+ ctlr->pcidev->rid);
+ return 0;
+ }
+ port = p->mem[0].bar & ~0x01;
+ debug("ns83815: SiS 630 rev. %ux reading mac addr from cmos via bridge at port 0x%lux\n", ctlr->pcidev->rid, port);
+
+ reg = pcicfgr8(p, MagicReg);
+ pcicfgw8(p, MagicReg, reg|Magicrden);
+
+ for (i = 0; i < Eaddrlen; i++) {
+ outb(port+Paddr, SiS630eenodeaddr + i);
+ ctlr->sromea[i] = inb(port+Pdata);
+ }
+
+ pcicfgw8(p, MagicReg, reg & ~Magicrden);
+ return 1;
+}
+
+/*
+ * If this is a SiS 630E chipset with an embedded SiS 900 controller,
+ * we have to read the MAC address from the APC CMOS RAM. - sez freebsd.
+ * However, CMOS *is* NVRAM normally. See devrtc.c:440, memory.c:88.
+ */
static void
-srom(Ctlr* ctlr)
+sissrom(Ctlr *ctlr)
+{
+ union {
+ uchar eaddr[Eaddrlen];
+ ushort alignment;
+ } ee;
+ int i, off = SiSeenodeaddr, cnt = sizeof ee.eaddr / sizeof(short);
+ ushort *shp = (ushort *)ee.eaddr;
+
+ if(!is630(ctlr->id, ctlr->pcidev) || !sisrdcmos(ctlr)) {
+ for (i = 0; i < cnt; i++)
+ *shp++ = eegetw(ctlr, off++);
+ memmove(ctlr->sromea, ee.eaddr, sizeof ctlr->sromea);
+ }
+}
+
+static void
+nssrom(Ctlr* ctlr)
{
int i, j;
@@ -821,8 +924,7 @@ srom(Ctlr* ctlr)
/*
* the MAC address is reversed, straddling word boundaries
*/
- memset(ctlr->sromea, 0, sizeof(ctlr->sromea));
- j = 6*16 + 15;
+ j = Nseenodeaddr*16 + 15;
for(i=0; i<48; i++){
ctlr->sromea[i>>3] |= ((ctlr->srom[j>>4] >> (15-(j&0xF))) & 1) << (i&7);
j++;
@@ -830,21 +932,42 @@ srom(Ctlr* ctlr)
}
static void
+srom(Ctlr* ctlr)
+{
+ memset(ctlr->sromea, 0, sizeof(ctlr->sromea));
+ switch (ctlr->id) {
+ case SiS900:
+ case SiS7016:
+ sissrom(ctlr);
+ break;
+ case Nat83815:
+ nssrom(ctlr);
+ break;
+ default:
+ print("ns83815: srom: unknown id 0x%ux\n", ctlr->id);
+ break;
+ }
+}
+
+static void
scanpci83815(void)
{
Ctlr *ctlr;
Pcidev *p;
+ ulong id;
p = nil;
while(p = pcimatch(p, 0, 0)){
- if(p->ccrb != 0x02 || p->ccru != 0)
+ if(p->ccrb != Pcibcnet || p->ccru != 0)
continue;
- switch((p->did<<16)|p->vid){
+ id = (p->did<<16)|p->vid;
+ switch(id){
default:
continue;
case Nat83815:
- case Sis900:
+ break;
+ case SiS900:
break;
}
@@ -855,7 +978,7 @@ scanpci83815(void)
ctlr = malloc(sizeof(Ctlr));
ctlr->port = p->mem[0].bar & ~0x01;
ctlr->pcidev = p;
- ctlr->id = (p->did<<16)|p->vid;
+ ctlr->id = id;
if(ioalloc(ctlr->port, p->mem[0].size, 0, "ns83815") < 0){
print("ns83815: port 0x%uX in use\n", ctlr->port);
@@ -885,6 +1008,7 @@ reset(Ether* ether)
{
Ctlr *ctlr;
int i, x;
+ ulong ctladdr;
uchar ea[Eaddrlen];
static int scandone;
@@ -923,7 +1047,8 @@ reset(Ether* ether)
memmove(ether->ea, ctlr->sromea, Eaddrlen);
for(i=0; i<Eaddrlen; i+=2){
x = ether->ea[i] | (ether->ea[i+1]<<8);
- csr32w(ctlr, Rrfcr, i);
+ ctladdr = (ctlr->id == Nat83815? i: i<<15);
+ csr32w(ctlr, Rrfcr, ctladdr);
csr32w(ctlr, Rrfdr, x);
}
csr32w(ctlr, Rrfcr, Rfen|Apm|Aab|Aam);
diff --git a/os/pc/ether8390.c b/os/pc/ether8390.c
index 42bde3cf..50d7ce39 100644
--- a/os/pc/ether8390.c
+++ b/os/pc/ether8390.c
@@ -400,7 +400,7 @@ receive(Ether* ether)
*/
if(hdr.next < ctlr->pstart || hdr.next >= ctlr->pstop
|| len < 60 || len > sizeof(Etherpkt)){
- print("dp8390: H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%lud\n",
+ print("dp8390: H%2.2ux+%2.2ux+%2.2ux+%2.2ux,%lud\n",
hdr.status, hdr.next, hdr.len0, hdr.len1, len);
regw(ctlr, Cr, Page0|RdABORT|Stp);
ringinit(ctlr);
@@ -588,7 +588,7 @@ interrupt(Ureg*, void* arg)
if(isr & (Txe|Ptx)){
r = regr(ctlr, Tsr);
if((isr & Txe) && (r & (Cdh|Fu|Crs|Abt))){
- print("dp8390: Tsr#%2.2ux|", r);
+ print("dp8390: Tsr %#2.2ux", r);
ether->oerrs++;
}
@@ -686,7 +686,7 @@ multicast(void* arg, uchar *addr, int on)
if(reverse[1] == 0){
for(i = 0; i < 64; i++)
reverse[i] = ((i&1)<<5) | ((i&2)<<3) | ((i&4)<<1)
- | ((i&8)>>1) | ((i&16)>>3) | ((i&32)>>5);
+ | ((i&8)>>1) | ((i&16)>>3) | ((i&32)>>5);
}
/*
diff --git a/os/pc/etherdp83820.c b/os/pc/etherdp83820.c
new file mode 100644
index 00000000..aeda3713
--- /dev/null
+++ b/os/pc/etherdp83820.c
@@ -0,0 +1,1246 @@
+/*
+ * National Semiconductor DP83820
+ * 10/100/1000 Mb/s Ethernet Network Interface Controller
+ * (Gig-NIC).
+ * Driver assumes little-endian and 32-bit host throughout.
+ */
+#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"
+#include "ethermii.h"
+
+enum { /* Registers */
+ Cr = 0x00, /* Command */
+ Cfg = 0x04, /* Configuration and Media Status */
+ Mear = 0x08, /* MII/EEPROM Access */
+ Ptscr = 0x0C, /* PCI Test Control */
+ Isr = 0x10, /* Interrupt Status */
+ Imr = 0x14, /* Interrupt Mask */
+ Ier = 0x18, /* Interrupt Enable */
+ Ihr = 0x1C, /* Interrupt Holdoff */
+ Txdp = 0x20, /* Transmit Descriptor Pointer */
+ Txdphi = 0x24, /* Transmit Descriptor Pointer Hi */
+ Txcfg = 0x28, /* Transmit Configuration */
+ Gpior = 0x2C, /* General Purpose I/O Control */
+ Rxdp = 0x30, /* Receive Descriptor Pointer */
+ Rxdphi = 0x34, /* Receive Descriptor Pointer Hi */
+ Rxcfg = 0x38, /* Receive Configuration */
+ Pqcr = 0x3C, /* Priority Queueing Control */
+ Wcsr = 0x40, /* Wake on LAN Control/Status */
+ Pcr = 0x44, /* Pause Control/Status */
+ Rfcr = 0x48, /* Receive Filter/Match Control */
+ Rfdr = 0x4C, /* Receive Filter/Match Data */
+ Brar = 0x50, /* Boot ROM Address */
+ Brdr = 0x54, /* Boot ROM Data */
+ Srr = 0x58, /* Silicon Revision */
+ Mibc = 0x5C, /* MIB Control */
+ Mibd = 0x60, /* MIB Data */
+ Txdp1 = 0xA0, /* Txdp Priority 1 */
+ Txdp2 = 0xA4, /* Txdp Priority 2 */
+ Txdp3 = 0xA8, /* Txdp Priority 3 */
+ Rxdp1 = 0xB0, /* Rxdp Priority 1 */
+ Rxdp2 = 0xB4, /* Rxdp Priority 2 */
+ Rxdp3 = 0xB8, /* Rxdp Priority 3 */
+ Vrcr = 0xBC, /* VLAN/IP Receive Control */
+ Vtcr = 0xC0, /* VLAN/IP Transmit Control */
+ Vdr = 0xC4, /* VLAN Data */
+ Ccsr = 0xCC, /* Clockrun Control/Status */
+ Tbicr = 0xE0, /* TBI Control */
+ Tbisr = 0xE4, /* TBI Status */
+ Tanar = 0xE8, /* TBI ANAR */
+ Tanlpar = 0xEC, /* TBI ANLPAR */
+ Taner = 0xF0, /* TBI ANER */
+ Tesr = 0xF4, /* TBI ESR */
+};
+
+enum { /* Cr */
+ Txe = 0x00000001, /* Transmit Enable */
+ Txd = 0x00000002, /* Transmit Disable */
+ Rxe = 0x00000004, /* Receiver Enable */
+ Rxd = 0x00000008, /* Receiver Disable */
+ Txr = 0x00000010, /* Transmitter Reset */
+ Rxr = 0x00000020, /* Receiver Reset */
+ Swien = 0x00000080, /* Software Interrupt Enable */
+ Rst = 0x00000100, /* Reset */
+ TxpriSHFT = 9, /* Tx Priority Queue Select */
+ TxpriMASK = 0x00001E00,
+ RxpriSHFT = 13, /* Rx Priority Queue Select */
+ RxpriMASK = 0x0001E000,
+};
+
+enum { /* Configuration and Media Status */
+ Bem = 0x00000001, /* Big Endian Mode */
+ Ext125 = 0x00000002, /* External 125MHz reference Select */
+ Bromdis = 0x00000004, /* Disable Boot ROM interface */
+ Pesel = 0x00000008, /* Parity Error Detection Action */
+ Exd = 0x00000010, /* Excessive Deferral Abort */
+ Pow = 0x00000020, /* Program Out of Window Timer */
+ Sb = 0x00000040, /* Single Back-off */
+ Reqalg = 0x00000080, /* PCI Bus Request Algorithm */
+ Extstsen = 0x00000100, /* Extended Status Enable */
+ Phydis = 0x00000200, /* Disable PHY */
+ Phyrst = 0x00000400, /* Reset PHY */
+ M64addren = 0x00000800, /* Master 64-bit Addressing Enable */
+ Data64en = 0x00001000, /* 64-bit Data Enable */
+ Pci64det = 0x00002000, /* PCI 64-bit Bus Detected */
+ T64addren = 0x00004000, /* Target 64-bit Addressing Enable */
+ Mwidis = 0x00008000, /* MWI Disable */
+ Mrmdis = 0x00010000, /* MRM Disable */
+ Tmrtest = 0x00020000, /* Timer Test Mode */
+ Spdstsien = 0x00040000, /* PHY Spdsts Interrupt Enable */
+ Lnkstsien = 0x00080000, /* PHY Lnksts Interrupt Enable */
+ Dupstsien = 0x00100000, /* PHY Dupsts Interrupt Enable */
+ Mode1000 = 0x00400000, /* 1000Mb/s Mode Control */
+ Tbien = 0x01000000, /* Ten-Bit Interface Enable */
+ Dupsts = 0x10000000, /* Full Duplex Status */
+ Spdsts100 = 0x20000000, /* SPEED100 Input Pin Status */
+ Spdsts1000 = 0x40000000, /* SPEED1000 Input Pin Status */
+ Lnksts = 0x80000000, /* Link Status */
+};
+
+enum { /* MII/EEPROM Access */
+ Eedi = 0x00000001, /* EEPROM Data In */
+ Eedo = 0x00000002, /* EEPROM Data Out */
+ Eeclk = 0x00000004, /* EEPROM Serial Clock */
+ Eesel = 0x00000008, /* EEPROM Chip Select */
+ Mdio = 0x00000010, /* MII Management Data */
+ Mddir = 0x00000020, /* MII Management Direction */
+ Mdc = 0x00000040, /* MII Management Clock */
+};
+
+enum { /* Interrupts */
+ Rxok = 0x00000001, /* Rx OK */
+ Rxdesc = 0x00000002, /* Rx Descriptor */
+ Rxerr = 0x00000004, /* Rx Packet Error */
+ Rxearly = 0x00000008, /* Rx Early Threshold */
+ Rxidle = 0x00000010, /* Rx Idle */
+ Rxorn = 0x00000020, /* Rx Overrun */
+ Txok = 0x00000040, /* Tx Packet OK */
+ Txdesc = 0x00000080, /* Tx Descriptor */
+ Txerr = 0x00000100, /* Tx Packet Error */
+ Txidle = 0x00000200, /* Tx Idle */
+ Txurn = 0x00000400, /* Tx Underrun */
+ Mib = 0x00000800, /* MIB Service */
+ Swi = 0x00001000, /* Software Interrupt */
+ Pme = 0x00002000, /* Power Management Event */
+ Phy = 0x00004000, /* PHY Interrupt */
+ Hibint = 0x00008000, /* High Bits Interrupt Set */
+ Rxsovr = 0x00010000, /* Rx Status FIFO Overrun */
+ Rtabt = 0x00020000, /* Received Target Abort */
+ Rmabt = 0x00040000, /* Received Master Abort */
+ Sserr = 0x00080000, /* Signalled System Error */
+ Dperr = 0x00100000, /* Detected Parity Error */
+ Rxrcmp = 0x00200000, /* Receive Reset Complete */
+ Txrcmp = 0x00400000, /* Transmit Reset Complete */
+ Rxdesc0 = 0x00800000, /* Rx Descriptor for Priority Queue 0 */
+ Rxdesc1 = 0x01000000, /* Rx Descriptor for Priority Queue 1 */
+ Rxdesc2 = 0x02000000, /* Rx Descriptor for Priority Queue 2 */
+ Rxdesc3 = 0x04000000, /* Rx Descriptor for Priority Queue 3 */
+ Txdesc0 = 0x08000000, /* Tx Descriptor for Priority Queue 0 */
+ Txdesc1 = 0x10000000, /* Tx Descriptor for Priority Queue 1 */
+ Txdesc2 = 0x20000000, /* Tx Descriptor for Priority Queue 2 */
+ Txdesc3 = 0x40000000, /* Tx Descriptor for Priority Queue 3 */
+};
+
+enum { /* Interrupt Enable */
+ Ien = 0x00000001, /* Interrupt Enable */
+};
+
+enum { /* Interrupt Holdoff */
+ IhSHFT = 0, /* Interrupt Holdoff */
+ IhMASK = 0x000000FF,
+ Ihctl = 0x00000100, /* Interrupt Holdoff Control */
+};
+
+enum { /* Transmit Configuration */
+ TxdrthSHFT = 0, /* Tx Drain Threshold */
+ TxdrthMASK = 0x000000FF,
+ FlthSHFT = 16, /* Tx Fill Threshold */
+ FlthMASK = 0x0000FF00,
+ Brstdis = 0x00080000, /* 1000Mb/s Burst Disable */
+ MxdmaSHFT = 20, /* Max Size per Tx DMA Burst */
+ MxdmaMASK = 0x00700000,
+ Ecretryen = 0x00800000, /* Excessive Collision Retry Enable */
+ Atp = 0x10000000, /* Automatic Transmit Padding */
+ Mlb = 0x20000000, /* MAC Loopback */
+ Hbi = 0x40000000, /* Heartbeat Ignore */
+ Csi = 0x80000000, /* Carrier Sense Ignore */
+};
+
+enum { /* Receive Configuration */
+ RxdrthSHFT = 1, /* Rx Drain Threshold */
+ RxdrthMASK = 0x0000003E,
+ Airl = 0x04000000, /* Accept In-Range Length Errored */
+ Alp = 0x08000000, /* Accept Long Packets */
+ Rxfd = 0x10000000, /* Receive Full Duplex */
+ Stripcrc = 0x20000000, /* Strip CRC */
+ Arp = 0x40000000, /* Accept Runt Packets */
+ Aep = 0x80000000, /* Accept Errored Packets */
+};
+
+enum { /* Priority Queueing Control */
+ Txpqen = 0x00000001, /* Transmit Priority Queuing Enable */
+ Txfairen = 0x00000002, /* Transmit Fairness Enable */
+ RxpqenSHFT = 2, /* Receive Priority Queue Enable */
+ RxpqenMASK = 0x0000000C,
+};
+
+enum { /* Pause Control/Status */
+ PscntSHFT = 0, /* Pause Counter Value */
+ PscntMASK = 0x0000FFFF,
+ Pstx = 0x00020000, /* Transmit Pause Frame */
+ PsffloSHFT = 18, /* Rx Data FIFO Lo Threshold */
+ PsffloMASK = 0x000C0000,
+ PsffhiSHFT = 20, /* Rx Data FIFO Hi Threshold */
+ PsffhiMASK = 0x00300000,
+ PsstloSHFT = 22, /* Rx Stat FIFO Hi Threshold */
+ PsstloMASK = 0x00C00000,
+ PssthiSHFT = 24, /* Rx Stat FIFO Hi Threshold */
+ PssthiMASK = 0x03000000,
+ Psrcvd = 0x08000000, /* Pause Frame Received */
+ Psact = 0x10000000, /* Pause Active */
+ Psda = 0x20000000, /* Pause on Destination Address */
+ Psmcast = 0x40000000, /* Pause on Multicast */
+ Psen = 0x80000000, /* Pause Enable */
+};
+
+enum { /* Receive Filter/Match Control */
+ RfaddrSHFT = 0, /* Extended Register Address */
+ RfaddrMASK = 0x000003FF,
+ Ulm = 0x00080000, /* U/L bit mask */
+ Uhen = 0x00100000, /* Unicast Hash Enable */
+ Mhen = 0x00200000, /* Multicast Hash Enable */
+ Aarp = 0x00400000, /* Accept ARP Packets */
+ ApatSHFT = 23, /* Accept on Pattern Match */
+ ApatMASK = 0x07800000,
+ Apm = 0x08000000, /* Accept on Perfect Match */
+ Aau = 0x10000000, /* Accept All Unicast */
+ Aam = 0x20000000, /* Accept All Multicast */
+ Aab = 0x40000000, /* Accept All Broadcast */
+ Rfen = 0x80000000, /* Rx Filter Enable */
+};
+
+enum { /* Receive Filter/Match Data */
+ RfdataSHFT = 0, /* Receive Filter Data */
+ RfdataMASK = 0x0000FFFF,
+ BmaskSHFT = 16, /* Byte Mask */
+ BmaskMASK = 0x00030000,
+};
+
+enum { /* MIB Control */
+ Wrn = 0x00000001, /* Warning Test Indicator */
+ Frz = 0x00000002, /* Freeze All Counters */
+ Aclr = 0x00000004, /* Clear All Counters */
+ Mibs = 0x00000008, /* MIB Counter Strobe */
+};
+
+enum { /* MIB Data */
+ Nmibd = 11, /* Number of MIB Data Registers */
+};
+
+enum { /* VLAN/IP Receive Control */
+ Vtden = 0x00000001, /* VLAN Tag Detection Enable */
+ Vtren = 0x00000002, /* VLAN Tag Removal Enable */
+ Dvtf = 0x00000004, /* Discard VLAN Tagged Frames */
+ Dutf = 0x00000008, /* Discard Untagged Frames */
+ Ipen = 0x00000010, /* IP Checksum Enable */
+ Ripe = 0x00000020, /* Reject IP Checksum Errors */
+ Rtcpe = 0x00000040, /* Reject TCP Checksum Errors */
+ Rudpe = 0x00000080, /* Reject UDP Checksum Errors */
+};
+
+enum { /* VLAN/IP Transmit Control */
+ Vgti = 0x00000001, /* VLAN Global Tag Insertion */
+ Vppti = 0x00000002, /* VLAN Per-Packet Tag Insertion */
+ Gchk = 0x00000004, /* Global Checksum Generation */
+ Ppchk = 0x00000008, /* Per-Packet Checksum Generation */
+};
+
+enum { /* VLAN Data */
+ VtypeSHFT = 0, /* VLAN Type Field */
+ VtypeMASK = 0x0000FFFF,
+ VtciSHFT = 16, /* VLAN Tag Control Information */
+ VtciMASK = 0xFFFF0000,
+};
+
+enum { /* Clockrun Control/Status */
+ Clkrunen = 0x00000001, /* CLKRUN Enable */
+ Pmeen = 0x00000100, /* PME Enable */
+ Pmests = 0x00008000, /* PME Status */
+};
+
+typedef struct {
+ u32int link; /* Link to the next descriptor */
+ u32int bufptr; /* pointer to data Buffer */
+ int cmdsts; /* Command/Status */
+ int extsts; /* optional Extended Status */
+
+ Block* bp; /* Block containing bufptr */
+ u32int unused; /* pad to 64-bit */
+} Desc;
+
+enum { /* Common cmdsts bits */
+ SizeMASK = 0x0000FFFF, /* Descriptor Byte Count */
+ SizeSHFT = 0,
+ Ok = 0x08000000, /* Packet OK */
+ Crc = 0x10000000, /* Suppress/Include CRC */
+ Intr = 0x20000000, /* Interrupt on ownership transfer */
+ More = 0x40000000, /* not last descriptor in a packet */
+ Own = 0x80000000, /* Descriptor Ownership */
+};
+
+enum { /* Transmit cmdsts bits */
+ CcntMASK = 0x000F0000, /* Collision Count */
+ CcntSHFT = 16,
+ Ec = 0x00100000, /* Excessive Collisions */
+ Owc = 0x00200000, /* Out of Window Collision */
+ Ed = 0x00400000, /* Excessive Deferral */
+ Td = 0x00800000, /* Transmit Deferred */
+ Crs = 0x01000000, /* Carrier Sense Lost */
+ Tfu = 0x02000000, /* Transmit FIFO Underrun */
+ Txa = 0x04000000, /* Transmit Abort */
+};
+
+enum { /* Receive cmdsts bits */
+ Irl = 0x00010000, /* In-Range Length Error */
+ Lbp = 0x00020000, /* Loopback Packet */
+ Fae = 0x00040000, /* Frame Alignment Error */
+ Crce = 0x00080000, /* CRC Error */
+ Ise = 0x00100000, /* Invalid Symbol Error */
+ Runt = 0x00200000, /* Runt Packet Received */
+ Long = 0x00400000, /* Too Long Packet Received */
+ DestMASK = 0x01800000, /* Destination Class */
+ DestSHFT = 23,
+ Rxo = 0x02000000, /* Receive Overrun */
+ Rxa = 0x04000000, /* Receive Aborted */
+};
+
+enum { /* extsts bits */
+ EvtciMASK = 0x0000FFFF, /* VLAN Tag Control Information */
+ EvtciSHFT = 0,
+ Vpkt = 0x00010000, /* VLAN Packet */
+ Ippkt = 0x00020000, /* IP Packet */
+ Iperr = 0x00040000, /* IP Checksum Error */
+ Tcppkt = 0x00080000, /* TCP Packet */
+ Tcperr = 0x00100000, /* TCP Checksum Error */
+ Udppkt = 0x00200000, /* UDP Packet */
+ Udperr = 0x00400000, /* UDP Checksum Error */
+};
+
+enum {
+ Nrd = 256,
+ Nrb = 4*Nrd,
+ Rbsz = ROUNDUP(sizeof(Etherpkt)+8, 8),
+ Ntd = 128,
+};
+
+typedef struct Ctlr Ctlr;
+typedef struct Ctlr {
+ int port;
+ Pcidev* pcidev;
+ Ctlr* next;
+ int active;
+ int id;
+
+ int eepromsz; /* address size in bits */
+ ushort* eeprom;
+
+ int* nic;
+ int cfg;
+ int imr;
+
+ QLock alock; /* attach */
+ Lock ilock; /* init */
+ void* alloc; /* base of per-Ctlr allocated data */
+
+ Mii* mii;
+
+ Lock rdlock; /* receive */
+ Desc* rd;
+ int nrd;
+ int nrb;
+ int rdx;
+ int rxcfg;
+
+ Lock tlock; /* transmit */
+ Desc* td;
+ int ntd;
+ int tdh;
+ int tdt;
+ int ntq;
+ int txcfg;
+
+ int rxidle;
+
+ uint mibd[Nmibd];
+
+ int ec;
+ int owc;
+ int ed;
+ int crs;
+ int tfu;
+ int txa;
+} Ctlr;
+
+#define csr32r(c, r) (*((c)->nic+((r)/4)))
+#define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
+
+static Ctlr* dp83820ctlrhead;
+static Ctlr* dp83820ctlrtail;
+
+static Lock dp83820rblock; /* free receive Blocks */
+static Block* dp83820rbpool;
+
+static char* dp83820mibs[Nmibd] = {
+ "RXErroredPkts",
+ "RXFCSErrors",
+ "RXMsdPktErrors",
+ "RXFAErrors",
+ "RXSymbolErrors",
+ "RXFrameToLong",
+ "RXIRLErrors",
+ "RXBadOpcodes",
+ "RXPauseFrames",
+ "TXPauseFrames",
+ "TXSQEErrors",
+};
+
+static int
+mdior(Ctlr* ctlr, int n)
+{
+ int data, i, mear, r;
+
+ mear = csr32r(ctlr, Mear);
+ r = ~(Mdc|Mddir) & mear;
+ data = 0;
+ for(i = n-1; i >= 0; i--){
+ if(csr32r(ctlr, Mear) & Mdio)
+ data |= (1<<i);
+ csr32w(ctlr, Mear, Mdc|r);
+ csr32w(ctlr, Mear, r);
+ }
+ csr32w(ctlr, Mear, mear);
+
+ return data;
+}
+
+static void
+mdiow(Ctlr* ctlr, int bits, int n)
+{
+ int i, mear, r;
+
+ mear = csr32r(ctlr, Mear);
+ r = Mddir|(~Mdc & mear);
+ for(i = n-1; i >= 0; i--){
+ if(bits & (1<<i))
+ r |= Mdio;
+ else
+ r &= ~Mdio;
+ csr32w(ctlr, Mear, r);
+ csr32w(ctlr, Mear, Mdc|r);
+ }
+ csr32w(ctlr, Mear, mear);
+}
+
+static int
+dp83820miimir(Mii* mii, int pa, int ra)
+{
+ int data;
+ Ctlr *ctlr;
+
+ ctlr = mii->ctlr;
+
+ /*
+ * MII Management Interface Read.
+ *
+ * Preamble;
+ * ST+OP+PA+RA;
+ * LT + 16 data bits.
+ */
+ mdiow(ctlr, 0xFFFFFFFF, 32);
+ mdiow(ctlr, 0x1800|(pa<<5)|ra, 14);
+ data = mdior(ctlr, 18);
+
+ if(data & 0x10000)
+ return -1;
+
+ return data & 0xFFFF;
+}
+
+static int
+dp83820miimiw(Mii* mii, int pa, int ra, int data)
+{
+ Ctlr *ctlr;
+
+ ctlr = mii->ctlr;
+
+ /*
+ * MII Management Interface Write.
+ *
+ * Preamble;
+ * ST+OP+PA+RA+LT + 16 data bits;
+ * Z.
+ */
+ mdiow(ctlr, 0xFFFFFFFF, 32);
+ data &= 0xFFFF;
+ data |= (0x05<<(5+5+2+16))|(pa<<(5+2+16))|(ra<<(2+16))|(0x02<<16);
+ mdiow(ctlr, data, 32);
+
+ return 0;
+}
+
+static Block *
+dp83820rballoc(Desc* desc)
+{
+ Block *bp;
+
+ if(desc->bp == nil){
+ ilock(&dp83820rblock);
+ if((bp = dp83820rbpool) == nil){
+ iunlock(&dp83820rblock);
+ desc->bp = nil;
+ desc->cmdsts = Own;
+ return nil;
+ }
+ dp83820rbpool = bp->next;
+ bp->next = nil;
+ iunlock(&dp83820rblock);
+
+ desc->bufptr = PCIWADDR(bp->rp);
+ desc->bp = bp;
+ }
+ else{
+ bp = desc->bp;
+ bp->rp = bp->lim - Rbsz;
+ bp->wp = bp->rp;
+ }
+
+ coherence();
+ desc->cmdsts = Intr|Rbsz;
+
+ return bp;
+}
+
+static void
+dp83820rbfree(Block *bp)
+{
+ bp->rp = bp->lim - Rbsz;
+ bp->wp = bp->rp;
+
+ ilock(&dp83820rblock);
+ bp->next = dp83820rbpool;
+ dp83820rbpool = bp;
+ iunlock(&dp83820rblock);
+}
+
+static void
+dp83820halt(Ctlr* ctlr)
+{
+ int i, timeo;
+
+ ilock(&ctlr->ilock);
+ csr32w(ctlr, Imr, 0);
+ csr32w(ctlr, Ier, 0);
+ csr32w(ctlr, Cr, Rxd|Txd);
+ for(timeo = 0; timeo < 1000; timeo++){
+ if(!(csr32r(ctlr, Cr) & (Rxe|Txe)))
+ break;
+ microdelay(1);
+ }
+ csr32w(ctlr, Mibc, Frz);
+ iunlock(&ctlr->ilock);
+
+ if(ctlr->rd != nil){
+ for(i = 0; i < ctlr->nrd; i++){
+ if(ctlr->rd[i].bp == nil)
+ continue;
+ freeb(ctlr->rd[i].bp);
+ ctlr->rd[i].bp = nil;
+ }
+ }
+ if(ctlr->td != nil){
+ for(i = 0; i < ctlr->ntd; i++){
+ if(ctlr->td[i].bp == nil)
+ continue;
+ freeb(ctlr->td[i].bp);
+ ctlr->td[i].bp = nil;
+ }
+ }
+}
+
+static void
+dp83820cfg(Ctlr* ctlr)
+{
+ int cfg;
+
+ /*
+ * Don't know how to deal with a TBI yet.
+ */
+ if(ctlr->mii == nil)
+ return;
+
+ /*
+ * The polarity of these bits is at the mercy
+ * of the board designer.
+ * The correct answer for all speed and duplex questions
+ * should be to query the phy.
+ */
+ cfg = csr32r(ctlr, Cfg);
+ if(!(cfg & Dupsts)){
+ ctlr->rxcfg |= Rxfd;
+ ctlr->txcfg |= Csi|Hbi;
+ iprint("83820: full duplex, ");
+ }
+ else{
+ ctlr->rxcfg &= ~Rxfd;
+ ctlr->txcfg &= ~(Csi|Hbi);
+ iprint("83820: half duplex, ");
+ }
+ csr32w(ctlr, Rxcfg, ctlr->rxcfg);
+ csr32w(ctlr, Txcfg, ctlr->txcfg);
+
+ switch(cfg & (Spdsts1000|Spdsts100)){
+ case Spdsts1000: /* 100Mbps */
+ default: /* 10Mbps */
+ ctlr->cfg &= ~Mode1000;
+ if((cfg & (Spdsts1000|Spdsts100)) == Spdsts1000)
+ iprint("100Mb/s\n");
+ else
+ iprint("10Mb/s\n");
+ break;
+ case Spdsts100: /* 1Gbps */
+ ctlr->cfg |= Mode1000;
+ iprint("1Gb/s\n");
+ break;
+ }
+ csr32w(ctlr, Cfg, ctlr->cfg);
+}
+
+static void
+dp83820init(Ether* edev)
+{
+ int i;
+ Ctlr *ctlr;
+ Desc *desc;
+ uchar *alloc;
+
+ ctlr = edev->ctlr;
+
+ dp83820halt(ctlr);
+
+ /*
+ * Receiver
+ */
+ alloc = (uchar*)ROUNDUP((ulong)ctlr->alloc, 8);
+ ctlr->rd = (Desc*)alloc;
+ alloc += ctlr->nrd*sizeof(Desc);
+ memset(ctlr->rd, 0, ctlr->nrd*sizeof(Desc));
+ ctlr->rdx = 0;
+ for(i = 0; i < ctlr->nrd; i++){
+ desc = &ctlr->rd[i];
+ desc->link = PCIWADDR(&ctlr->rd[NEXT(i, ctlr->nrd)]);
+ if(dp83820rballoc(desc) == nil)
+ continue;
+ }
+ csr32w(ctlr, Rxdphi, 0);
+ csr32w(ctlr, Rxdp, PCIWADDR(ctlr->rd));
+
+ for(i = 0; i < Eaddrlen; i += 2){
+ csr32w(ctlr, Rfcr, i);
+ csr32w(ctlr, Rfdr, (edev->ea[i+1]<<8)|edev->ea[i]);
+ }
+ csr32w(ctlr, Rfcr, Rfen|Aab|Aam|Apm);
+
+ ctlr->rxcfg = Stripcrc|(((2*(ETHERMINTU+4))/8)<<RxdrthSHFT);
+ ctlr->imr |= Rxorn|Rxidle|Rxearly|Rxdesc|Rxok;
+
+ /*
+ * Transmitter.
+ */
+ ctlr->td = (Desc*)alloc;
+ memset(ctlr->td, 0, ctlr->ntd*sizeof(Desc));
+ ctlr->tdh = ctlr->tdt = ctlr->ntq = 0;
+ for(i = 0; i < ctlr->ntd; i++){
+ desc = &ctlr->td[i];
+ desc->link = PCIWADDR(&ctlr->td[NEXT(i, ctlr->ntd)]);
+ }
+ csr32w(ctlr, Txdphi, 0);
+ csr32w(ctlr, Txdp, PCIWADDR(ctlr->td));
+
+ ctlr->txcfg = Atp|(((2*(ETHERMINTU+4))/32)<<FlthSHFT)|((4096/32)<<TxdrthSHFT);
+ ctlr->imr |= Txurn|Txidle|Txdesc|Txok;
+
+ ilock(&ctlr->ilock);
+
+ dp83820cfg(ctlr);
+
+ csr32w(ctlr, Mibc, Aclr);
+ ctlr->imr |= Mib;
+
+ csr32w(ctlr, Imr, ctlr->imr);
+
+ /* try coalescing adjacent interrupts; use hold-off interval of 100µs */
+ csr32w(ctlr, Ihr, Ihctl|(1<<IhSHFT));
+
+ csr32w(ctlr, Ier, Ien);
+ csr32w(ctlr, Cr, Rxe|Txe);
+
+ iunlock(&ctlr->ilock);
+}
+
+static void
+dp83820attach(Ether* edev)
+{
+ Block *bp;
+ Ctlr *ctlr;
+
+ ctlr = edev->ctlr;
+ qlock(&ctlr->alock);
+ if(ctlr->alloc != nil){
+ qunlock(&ctlr->alock);
+ return;
+ }
+
+ if(waserror()){
+ if(ctlr->mii != nil){
+ free(ctlr->mii);
+ ctlr->mii = nil;
+ }
+ if(ctlr->alloc != nil){
+ free(ctlr->alloc);
+ ctlr->alloc = nil;
+ }
+ qunlock(&ctlr->alock);
+ nexterror();
+ }
+
+ if(!(ctlr->cfg & Tbien)){
+ if((ctlr->mii = malloc(sizeof(Mii))) == nil)
+ error(Enomem);
+ ctlr->mii->ctlr = ctlr;
+ ctlr->mii->mir = dp83820miimir;
+ ctlr->mii->miw = dp83820miimiw;
+ if(mii(ctlr->mii, ~0) == 0)
+ error("no PHY");
+ ctlr->cfg |= Dupstsien|Lnkstsien|Spdstsien;
+ ctlr->imr |= Phy;
+ }
+
+ ctlr->nrd = Nrd;
+ ctlr->nrb = Nrb;
+ ctlr->ntd = Ntd;
+ ctlr->alloc = mallocz((ctlr->nrd+ctlr->ntd)*sizeof(Desc) + 7, 0);
+ if(ctlr->alloc == nil)
+ error(Enomem);
+
+ for(ctlr->nrb = 0; ctlr->nrb < Nrb; ctlr->nrb++){
+ if((bp = allocb(Rbsz)) == nil)
+ break;
+ bp->free = dp83820rbfree;
+ dp83820rbfree(bp);
+ }
+
+ dp83820init(edev);
+
+ qunlock(&ctlr->alock);
+ poperror();
+}
+
+static void
+dp83820transmit(Ether* edev)
+{
+ Block *bp;
+ Ctlr *ctlr;
+ Desc *desc;
+ int cmdsts, r, x;
+
+ ctlr = edev->ctlr;
+
+ ilock(&ctlr->tlock);
+
+ bp = nil;
+ for(x = ctlr->tdh; ctlr->ntq; x = NEXT(x, ctlr->ntd)){
+ desc = &ctlr->td[x];
+ if((cmdsts = desc->cmdsts) & Own)
+ break;
+ if(!(cmdsts & Ok)){
+ if(cmdsts & Ec)
+ ctlr->ec++;
+ if(cmdsts & Owc)
+ ctlr->owc++;
+ if(cmdsts & Ed)
+ ctlr->ed++;
+ if(cmdsts & Crs)
+ ctlr->crs++;
+ if(cmdsts & Tfu)
+ ctlr->tfu++;
+ if(cmdsts & Txa)
+ ctlr->txa++;
+ edev->oerrs++;
+ }
+ desc->bp->next = bp;
+ bp = desc->bp;
+ desc->bp = nil;
+
+ ctlr->ntq--;
+ }
+ ctlr->tdh = x;
+ if(bp != nil)
+ freeblist(bp);
+
+ x = ctlr->tdt;
+ while(ctlr->ntq < (ctlr->ntd-1)){
+ if((bp = qget(edev->oq)) == nil)
+ break;
+
+ desc = &ctlr->td[x];
+ desc->bufptr = PCIWADDR(bp->rp);
+ desc->bp = bp;
+ ctlr->ntq++;
+ coherence();
+ desc->cmdsts = Own|Intr|BLEN(bp);
+
+ x = NEXT(x, ctlr->ntd);
+ }
+ if(x != ctlr->tdt){
+ ctlr->tdt = x;
+ r = csr32r(ctlr, Cr);
+ csr32w(ctlr, Cr, Txe|r);
+ }
+
+ iunlock(&ctlr->tlock);
+}
+
+static void
+dp83820interrupt(Ureg*, void* arg)
+{
+ Block *bp;
+ Ctlr *ctlr;
+ Desc *desc;
+ Ether *edev;
+ int cmdsts, i, isr, r, x;
+
+ edev = arg;
+ ctlr = edev->ctlr;
+
+ for(isr = csr32r(ctlr, Isr); isr & ctlr->imr; isr = csr32r(ctlr, Isr)){
+ if(isr & (Rxorn|Rxidle|Rxearly|Rxerr|Rxdesc|Rxok)){
+ x = ctlr->rdx;
+ desc = &ctlr->rd[x];
+ while((cmdsts = desc->cmdsts) & Own){
+ if((cmdsts & Ok) && desc->bp != nil){
+ bp = desc->bp;
+ desc->bp = nil;
+ bp->wp += cmdsts & SizeMASK;
+ etheriq(edev, bp, 1);
+ }
+ //else if(!(cmdsts & Ok)){
+ // iprint("dp83820: rx %8.8uX:", cmdsts);
+ // bp = desc->bp;
+ // for(i = 0; i < 20; i++)
+ // iprint(" %2.2uX", bp->rp[i]);
+ // iprint("\n");
+ //}
+ dp83820rballoc(desc);
+
+ x = NEXT(x, ctlr->nrd);
+ desc = &ctlr->rd[x];
+ }
+ ctlr->rdx = x;
+
+ if(isr & Rxidle){
+ r = csr32r(ctlr, Cr);
+ csr32w(ctlr, Cr, Rxe|r);
+ ctlr->rxidle++;
+ }
+
+ isr &= ~(Rxorn|Rxidle|Rxearly|Rxerr|Rxdesc|Rxok);
+ }
+
+ if(isr & Txurn){
+ x = (ctlr->txcfg & TxdrthMASK)>>TxdrthSHFT;
+ r = (ctlr->txcfg & FlthMASK)>>FlthSHFT;
+ if(x < ((TxdrthMASK)>>TxdrthSHFT)
+ && x < (2048/32 - r)){
+ ctlr->txcfg &= ~TxdrthMASK;
+ x++;
+ ctlr->txcfg |= x<<TxdrthSHFT;
+ csr32w(ctlr, Txcfg, ctlr->txcfg);
+ }
+ }
+
+ if(isr & (Txurn|Txidle|Txdesc|Txok)){
+ dp83820transmit(edev);
+ isr &= ~(Txurn|Txidle|Txdesc|Txok);
+ }
+
+ if(isr & Mib){
+ for(i = 0; i < Nmibd; i++){
+ r = csr32r(ctlr, Mibd+(i*sizeof(int)));
+ ctlr->mibd[i] += r & 0xFFFF;
+ }
+ isr &= ~Mib;
+ }
+
+ if((isr & Phy) && ctlr->mii != nil){
+ ctlr->mii->mir(ctlr->mii, 1, Bmsr);
+ print("phy: cfg %8.8uX bmsr %4.4uX\n",
+ csr32r(ctlr, Cfg),
+ ctlr->mii->mir(ctlr->mii, 1, Bmsr));
+ dp83820cfg(ctlr);
+ isr &= ~Phy;
+ }
+ if(isr)
+ iprint("dp83820: isr %8.8uX\n", isr);
+ }
+}
+
+static long
+dp83820ifstat(Ether* edev, void* a, long n, ulong offset)
+{
+ char *p;
+ Ctlr *ctlr;
+ int i, l, r;
+
+ ctlr = edev->ctlr;
+
+ edev->crcs = ctlr->mibd[Mibd+(1*sizeof(int))];
+ edev->frames = ctlr->mibd[Mibd+(3*sizeof(int))];
+ edev->buffs = ctlr->mibd[Mibd+(5*sizeof(int))];
+ edev->overflows = ctlr->mibd[Mibd+(2*sizeof(int))];
+
+ if(n == 0)
+ return 0;
+
+ p = malloc(READSTR);
+ l = 0;
+ for(i = 0; i < Nmibd; i++){
+ r = csr32r(ctlr, Mibd+(i*sizeof(int)));
+ ctlr->mibd[i] += r & 0xFFFF;
+ if(ctlr->mibd[i] != 0 && dp83820mibs[i] != nil)
+ l += snprint(p+l, READSTR-l, "%s: %ud %ud\n",
+ dp83820mibs[i], ctlr->mibd[i], r);
+ }
+ l += snprint(p+l, READSTR-l, "rxidle %d\n", ctlr->rxidle);
+ l += snprint(p+l, READSTR-l, "ec %d\n", ctlr->ec);
+ l += snprint(p+l, READSTR-l, "owc %d\n", ctlr->owc);
+ l += snprint(p+l, READSTR-l, "ed %d\n", ctlr->ed);
+ l += snprint(p+l, READSTR-l, "crs %d\n", ctlr->crs);
+ l += snprint(p+l, READSTR-l, "tfu %d\n", ctlr->tfu);
+ l += snprint(p+l, READSTR-l, "txa %d\n", ctlr->txa);
+
+ l += snprint(p+l, READSTR, "rom:");
+ for(i = 0; i < 0x10; i++){
+ if(i && ((i & 0x07) == 0))
+ l += snprint(p+l, READSTR-l, "\n ");
+ l += snprint(p+l, READSTR-l, " %4.4uX", ctlr->eeprom[i]);
+ }
+ l += snprint(p+l, READSTR-l, "\n");
+
+ if(ctlr->mii != nil && ctlr->mii->curphy != nil){
+ l += snprint(p+l, READSTR, "phy:");
+ for(i = 0; i < NMiiPhyr; i++){
+ if(i && ((i & 0x07) == 0))
+ l += snprint(p+l, READSTR-l, "\n ");
+ r = miimir(ctlr->mii, i);
+ l += snprint(p+l, READSTR-l, " %4.4uX", r);
+ }
+ snprint(p+l, READSTR-l, "\n");
+ }
+
+ n = readstr(offset, a, n, p);
+ free(p);
+
+ return n;
+}
+
+static void
+dp83820promiscuous(void* arg, int on)
+{
+ USED(arg, on);
+}
+
+/* multicast already on, don't need to do anything */
+static void
+dp83820multicast(void*, uchar*, int)
+{
+}
+
+static int
+dp83820detach(Ctlr* ctlr)
+{
+ /*
+ * Soft reset the controller.
+ */
+ csr32w(ctlr, Cr, Rst);
+ delay(1);
+ while(csr32r(ctlr, Cr) & Rst)
+ delay(1);
+ return 0;
+}
+
+static void
+dp83820shutdown(Ether* ether)
+{
+print("dp83820shutdown\n");
+ dp83820detach(ether->ctlr);
+}
+
+static int
+atc93c46r(Ctlr* ctlr, int address)
+{
+ int data, i, mear, r, size;
+
+ /*
+ * Analog Technology, Inc. ATC93C46
+ * or equivalent serial EEPROM.
+ */
+ mear = csr32r(ctlr, Mear);
+ mear &= ~(Eesel|Eeclk|Eedo|Eedi);
+ r = Eesel|mear;
+
+reread:
+ csr32w(ctlr, Mear, r);
+ data = 0x06;
+ for(i = 3-1; i >= 0; i--){
+ if(data & (1<<i))
+ r |= Eedi;
+ else
+ r &= ~Eedi;
+ csr32w(ctlr, Mear, r);
+ csr32w(ctlr, Mear, Eeclk|r);
+ microdelay(1);
+ csr32w(ctlr, Mear, r);
+ microdelay(1);
+ }
+
+ /*
+ * First time through must work out the EEPROM size.
+ */
+ if((size = ctlr->eepromsz) == 0)
+ size = 8;
+
+ for(size = size-1; size >= 0; size--){
+ if(address & (1<<size))
+ r |= Eedi;
+ else
+ r &= ~Eedi;
+ csr32w(ctlr, Mear, r);
+ microdelay(1);
+ csr32w(ctlr, Mear, Eeclk|r);
+ microdelay(1);
+ csr32w(ctlr, Mear, r);
+ microdelay(1);
+ if(!(csr32r(ctlr, Mear) & Eedo))
+ break;
+ }
+ r &= ~Eedi;
+
+ data = 0;
+ for(i = 16-1; i >= 0; i--){
+ csr32w(ctlr, Mear, Eeclk|r);
+ microdelay(1);
+ if(csr32r(ctlr, Mear) & Eedo)
+ data |= (1<<i);
+ csr32w(ctlr, Mear, r);
+ microdelay(1);
+ }
+
+ csr32w(ctlr, Mear, mear);
+
+ if(ctlr->eepromsz == 0){
+ ctlr->eepromsz = 8-size;
+ ctlr->eeprom = malloc((1<<ctlr->eepromsz)*sizeof(ushort));
+ goto reread;
+ }
+
+ return data;
+}
+
+static int
+dp83820reset(Ctlr* ctlr)
+{
+ int i, r;
+ unsigned char sum;
+
+ /*
+ * Soft reset the controller;
+ * read the EEPROM to get the initial settings
+ * of the Cfg and Gpior bits which should be cleared by
+ * the reset.
+ */
+ dp83820detach(ctlr);
+
+ atc93c46r(ctlr, 0);
+ if(ctlr->eeprom == nil) {
+ print("dp83820reset: no eeprom\n");
+ return -1;
+ }
+ sum = 0;
+ for(i = 0; i < 0x0E; i++){
+ r = atc93c46r(ctlr, i);
+ ctlr->eeprom[i] = r;
+ sum += r;
+ sum += r>>8;
+ }
+
+ if(sum != 0){
+ print("dp83820reset: bad EEPROM checksum\n");
+ return -1;
+ }
+
+#ifdef notdef
+ csr32w(ctlr, Gpior, ctlr->eeprom[4]);
+
+ cfg = Extstsen|Exd;
+ r = csr32r(ctlr, Cfg);
+ if(ctlr->eeprom[5] & 0x0001)
+ cfg |= Ext125;
+ if(ctlr->eeprom[5] & 0x0002)
+ cfg |= M64addren;
+ if((ctlr->eeprom[5] & 0x0004) && (r & Pci64det))
+ cfg |= Data64en;
+ if(ctlr->eeprom[5] & 0x0008)
+ cfg |= T64addren;
+ if(!(pcicfgr16(ctlr->pcidev, PciPCR) & 0x10))
+ cfg |= Mwidis;
+ if(ctlr->eeprom[5] & 0x0020)
+ cfg |= Mrmdis;
+ if(ctlr->eeprom[5] & 0x0080)
+ cfg |= Mode1000;
+ if(ctlr->eeprom[5] & 0x0200)
+ cfg |= Tbien|Mode1000;
+ /*
+ * What about RO bits we might have destroyed with Rst?
+ * What about Exd, Tmrtest, Extstsen, Pintctl?
+ * Why does it think it has detected a 64-bit bus when
+ * it hasn't?
+ */
+#else
+ //r = csr32r(ctlr, Cfg);
+ //r &= ~(Mode1000|T64addren|Data64en|M64addren);
+ //csr32w(ctlr, Cfg, r);
+ //csr32w(ctlr, Cfg, 0x2000);
+#endif /* notdef */
+ ctlr->cfg = csr32r(ctlr, Cfg);
+print("cfg %8.8uX pcicfg %8.8uX\n", ctlr->cfg, pcicfgr32(ctlr->pcidev, PciPCR));
+ ctlr->cfg &= ~(T64addren|Data64en|M64addren);
+ csr32w(ctlr, Cfg, ctlr->cfg);
+ csr32w(ctlr, Mibc, Aclr|Frz);
+
+ return 0;
+}
+
+static void
+dp83820pci(void)
+{
+ void *mem;
+ Pcidev *p;
+ Ctlr *ctlr;
+
+ p = nil;
+ while(p = pcimatch(p, 0, 0)){
+ if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
+ continue;
+
+ switch((p->did<<16)|p->vid){
+ default:
+ continue;
+ case (0x0022<<16)|0x100B: /* DP83820 (Gig-NIC) */
+ break;
+ }
+
+ mem = vmap(p->mem[1].bar & ~0x0F, p->mem[1].size);
+ if(mem == 0){
+ print("DP83820: can't map %8.8luX\n", p->mem[1].bar);
+ continue;
+ }
+
+ ctlr = malloc(sizeof(Ctlr));
+ ctlr->port = p->mem[1].bar & ~0x0F;
+ ctlr->pcidev = p;
+ ctlr->id = (p->did<<16)|p->vid;
+
+ ctlr->nic = mem;
+ if(dp83820reset(ctlr)){
+ free(ctlr);
+ continue;
+ }
+ pcisetbme(p);
+
+ if(dp83820ctlrhead != nil)
+ dp83820ctlrtail->next = ctlr;
+ else
+ dp83820ctlrhead = ctlr;
+ dp83820ctlrtail = ctlr;
+ }
+}
+
+static int
+dp83820pnp(Ether* edev)
+{
+ int i;
+ Ctlr *ctlr;
+ uchar ea[Eaddrlen];
+
+ if(dp83820ctlrhead == nil)
+ dp83820pci();
+
+ /*
+ * Any adapter matches if no edev->port is supplied,
+ * otherwise the ports must match.
+ */
+ for(ctlr = dp83820ctlrhead; ctlr != nil; ctlr = ctlr->next){
+ if(ctlr->active)
+ continue;
+ if(edev->port == 0 || edev->port == ctlr->port){
+ ctlr->active = 1;
+ break;
+ }
+ }
+ if(ctlr == nil)
+ return -1;
+
+ edev->ctlr = ctlr;
+ edev->port = ctlr->port;
+ edev->irq = ctlr->pcidev->intl;
+ edev->tbdf = ctlr->pcidev->tbdf;
+ edev->mbps = 1000;
+
+ /*
+ * Check if the adapter's station address is to be overridden.
+ * If not, read it from the EEPROM and set in ether->ea prior to
+ * loading the station address in the hardware.
+ */
+ memset(ea, 0, Eaddrlen);
+ if(memcmp(ea, edev->ea, Eaddrlen) == 0)
+ for(i = 0; i < Eaddrlen/2; i++){
+ edev->ea[2*i] = ctlr->eeprom[0x0C-i];
+ edev->ea[2*i+1] = ctlr->eeprom[0x0C-i]>>8;
+ }
+
+ edev->attach = dp83820attach;
+ edev->transmit = dp83820transmit;
+ edev->interrupt = dp83820interrupt;
+ edev->ifstat = dp83820ifstat;
+
+ edev->arg = edev;
+ edev->promiscuous = dp83820promiscuous;
+ edev->multicast = dp83820multicast;
+ edev->shutdown = dp83820shutdown;
+
+ return 0;
+}
+
+void
+etherdp83820link(void)
+{
+ addethercard("DP83820", dp83820pnp);
+}
diff --git a/os/pc/etherec2t.c b/os/pc/etherec2t.c
index ffbec852..c7625060 100644
--- a/os/pc/etherec2t.c
+++ b/os/pc/etherec2t.c
@@ -31,6 +31,7 @@ static Ec2t ec2tpcmcia[] = {
{ "FA410TX", 1, }, /* Netgear FA410TX */
{ "Network Everywhere", 0, }, /* Linksys NP10T 10BaseT Card */
{ "10/100 Port Attached", 1, }, /* SMC 8040TX */
+ { "8041TX-10/100-PC-Card-V2", 0 }, /* SMC 8041TX */
{ "FA411", 0 }, /* Netgear FA411 PCMCIA */
{ nil, 0, },
};
diff --git a/os/pc/etherelnk3.c b/os/pc/etherelnk3.c
index e0be41f1..9c612b13 100644
--- a/os/pc/etherelnk3.c
+++ b/os/pc/etherelnk3.c
@@ -1485,15 +1485,15 @@ tcm59Xpci(void)
break;
case 0x5157:
ctlr->eepromcmd = EepromRead8bRegister;
- ctlr->cbfnpa = upamalloc(p->mem[2].bar, p->mem[2].size, 0);
+ ctlr->cbfnpa = p->mem[2].bar&~0x0F;
+ ctlr->cbfn = vmap(p->mem[2].bar&~0x0F, p->mem[2].size);
break;
case 0x6056:
ctlr->eepromcmd = EepromReadOffRegister;
- ctlr->cbfnpa = upamalloc(p->mem[2].bar, p->mem[2].size, 0);
+ ctlr->cbfnpa = p->mem[2].bar&~0x0F;
+ ctlr->cbfn = vmap(p->mem[2].bar&~0x0F, p->mem[2].size);
break;
}
- if(ctlr->cbfnpa != 0)
- ctlr->cbfn = KADDR(ctlr->cbfnpa);
pcisetbme(p);
}
}
@@ -1834,6 +1834,7 @@ etherelnk3reset(Ether* ether)
case 0x9055: /* 3C905B-TX */
case 0x9200: /* 3C905C-TX */
case 0x9201: /* 3C920 */
+ case 0x9805: /* 3C9805: 3C980-TX Python-T 10/100baseTX */
/*FALLTHROUGH*/
case 0x9000: /* 3C900-TPO */
case 0x9001: /* 3C900-COMBO */
@@ -1927,6 +1928,7 @@ etherelnk3reset(Ether* ether)
case 0x9055:
case 0x9200:
case 0x9201:
+ case 0x9805:
ctlr->xcvr = xcvrMii;
resetctlr(ctlr);
break;
diff --git a/os/pc/etherga620.c b/os/pc/etherga620.c
index 45e34faf..3d555be0 100644
--- a/os/pc/etherga620.c
+++ b/os/pc/etherga620.c
@@ -124,7 +124,11 @@ enum { /* Om */
enum { /* Lmw */
Lmwsz = 2*1024, /* Local Memory Window Size */
- Sr = 0x3800, /* Send Ring (accessed via Lmw) */
+ /*
+ * legal values are 0x3800 iff Nsr is 128, 0x3000 iff Nsr is 256,
+ * or 0x2000 iff Nsr is 512.
+ */
+ Sr = 0x2000, /* Send Ring (accessed via Lmw) */
};
enum { /* Link */
@@ -146,17 +150,17 @@ typedef struct Host64 {
} Host64;
typedef struct Ere { /* Event Ring Element */
- int event; /* (event<<24)|(code<<12)|index */
+ int event; /* event<<24 | code<<12 | index */
int unused;
} Ere;
-typedef int Cmd; /* (cmd<<24)|(flags<<12)|index */
+typedef int Cmd; /* cmd<<24 | flags<<12 | index */
typedef struct Rbd { /* Receive Buffer Descriptor */
Host64 addr;
- int indexlen; /* (ring-index<<16)|buffer-length */
+ int indexlen; /* ring-index<<16 | buffer-length */
int flags; /* only lower 16-bits */
- int checksum; /* (ip<<16)|tcp/udp */
+ int checksum; /* ip<<16 | tcp/udp */
int error; /* only upper 16-bits */
int reserved;
void* opaque; /* passed to receive return ring */
@@ -164,7 +168,7 @@ typedef struct Rbd { /* Receive Buffer Descriptor */
typedef struct Sbd { /* Send Buffer Descriptor */
Host64 addr;
- int lenflags; /* (len<<16)|flags */
+ int lenflags; /* len<<16 | flags */
int reserved;
} Sbd;
@@ -192,7 +196,7 @@ enum { /* Buffer Error Flags */
typedef struct Rcb { /* Ring Control Block */
Host64 addr; /* points to the Rbd ring */
- int control; /* (max_len<<16)|flags */
+ int control; /* max_len<<16 | flags */
int unused;
} Rcb;
@@ -223,13 +227,17 @@ typedef struct Gib { /* General Information Block */
Host64 rsp; /* Refresh Stats */
} Gib;
+/*
+ * these sizes are all fixed in the card,
+ * except for Nsr, which has only 3 valid sizes.
+ */
enum { /* Host/NIC Interface ring sizes */
Ner = 256, /* event ring */
Ncr = 64, /* command ring */
- Nsr = 512, /* send ring */
+ Nsr = 512, /* send ring: 128, 256 or 512 */
Nrsr = 512, /* receive standard ring */
Nrjr = 256, /* receive jumbo ring */
- Nrmr = 1024, /* receive mini ring */
+ Nrmr = 1024, /* receive mini ring, optional */
Nrrr = 2048, /* receive return ring */
};
@@ -243,7 +251,7 @@ enum {
};
typedef struct Ctlr Ctlr;
-typedef struct Ctlr {
+struct Ctlr {
int port;
Pcidev* pcidev;
Ctlr* next;
@@ -286,7 +294,7 @@ typedef struct Ctlr {
int st; /* Stat Ticks */
int smcbd; /* Send Max. Coalesced BDs */
int rmcbd; /* Receive Max. Coalesced BDs */
-} Ctlr;
+};
static Ctlr* ctlrhead;
static Ctlr* ctlrtail;
@@ -310,7 +318,7 @@ ga620command(Ctlr* ctlr, int cmd, int flags, int index)
int cpi;
cpi = csr32r(ctlr, Cpi);
- csr32w(ctlr, Cr+(cpi*4), (cmd<<24)|(flags<<12)|index);
+ csr32w(ctlr, Cr+(cpi*4), cmd<<24 | flags<<12 | index);
cpi = NEXT(cpi, Ncr);
csr32w(ctlr, Cpi, cpi);
}
@@ -508,7 +516,7 @@ _ga620transmit(Ether* edev)
sbd = &ctlr->sr[spi];
sethost64(&sbd->addr, bp->rp);
- sbd->lenflags = (BLEN(bp)<<16)|Fend;
+ sbd->lenflags = BLEN(bp)<<16 | Fend;
ctlr->srb[spi] = bp;
work++;
@@ -539,7 +547,7 @@ ga620replenish(Ctlr* ctlr)
break;
rbd = &ctlr->rsr[rspi];
sethost64(&rbd->addr, bp->rp);
- rbd->indexlen = (rspi<<16)|(ETHERMAXTU+4);
+ rbd->indexlen = rspi<<16 | (ETHERMAXTU+4);
rbd->flags = 0;
rbd->opaque = bp;
@@ -550,27 +558,49 @@ ga620replenish(Ctlr* ctlr)
}
static void
-ga620event(Ctlr* ctlr, int eci, int epi)
+ga620event(Ether *edev, int eci, int epi)
{
- int event;
+ unsigned event, code;
+ Ctlr *ctlr;
+ ctlr = edev->ctlr;
while(eci != epi){
event = ctlr->er[eci].event;
+ code = (event >> 12) & ((1<<12)-1);
switch(event>>24){
case 0x01: /* firmware operational */
+ /* host stack (us) is up. 3rd arg of 2 means down. */
ga620command(ctlr, 0x01, 0x01, 0x00);
+ /*
+ * link negotiation: any speed is okay.
+ * 3rd arg of 1 selects gigabit only; 2 10/100 only.
+ */
ga620command(ctlr, 0x0B, 0x00, 0x00);
-print("%8.8uX: %8.8uX\n", ctlr->port, event);
+ print("#l%d: ga620: port %8.8uX: firmware is up\n",
+ edev->ctlrno, ctlr->port);
break;
case 0x04: /* statistics updated */
break;
case 0x06: /* link state changed */
-print("%8.8uX: %8.8uX %8.8uX %8.8uX\n",
- ctlr->port, event, csr32r(ctlr, Gls), csr32r(ctlr, Fls));
+ switch (code) {
+ case 1:
+ edev->mbps = 1000;
+ break;
+ case 2:
+ print("#l%d: link down\n", edev->ctlrno);
+ break;
+ case 3:
+ edev->mbps = 100; /* it's 10 or 100 */
+ break;
+ }
+ if (code != 2)
+ print("#l%d: %dMbps link up\n",
+ edev->ctlrno, edev->mbps);
break;
case 0x07: /* event error */
default:
- print("er[%d] = %8.8uX\n", eci, event);
+ print("#l%d: ga620: er[%d] = %8.8uX\n", edev->ctlrno,
+ eci, event);
break;
}
eci = NEXT(eci, Ner);
@@ -645,7 +675,7 @@ ga620interrupt(Ureg*, void* arg)
csr = csr32r(ctlr, Eci);
if(csr != ctlr->epi[0]){
- ga620event(ctlr, csr, ctlr->epi[0]);
+ ga620event(edev, csr, ctlr->epi[0]);
work = 1;
}
@@ -714,9 +744,9 @@ ga620init(Ether* edev)
/*
* Load the MAC address.
*/
- ea = (edev->ea[0]<<8)|edev->ea[1];
+ ea = edev->ea[0]<<8 | edev->ea[1];
csr32w(ctlr, Mac, ea);
- ea = (edev->ea[2]<<24)|(edev->ea[3]<<16)|(edev->ea[4]<<8)|edev->ea[5];
+ ea = edev->ea[2]<<24 | edev->ea[3]<<16 | edev->ea[4]<<8 | edev->ea[5];
csr32w(ctlr, Mac+4, ea);
/*
@@ -758,7 +788,7 @@ ga620init(Ether* edev)
* memory it is accessed via the Local Memory Window; with a send
* ring size of 128 the window covers the whole ring and then need
* only be set once:
- * ctlr->sr = KADDR(ctlr->port+Lmw);
+ * ctlr->sr = (uchar*)ctlr->nic+Lmw;
* ga620lmw(ctlr, Sr, nil, sizeof(Sbd)*Nsr);
* ctlr->gib->srcb.addr.lo = Sr;
* There is nowhere in the Sbd to hold the Block* associated
@@ -772,7 +802,7 @@ ga620init(Ether* edev)
flags = HostRing;
if(ctlr->coalupdateonly)
flags |= CoalUpdateOnly;
- ctlr->gib->srcb.control = (Nsr<<16)|flags;
+ ctlr->gib->srcb.control = Nsr<<16 | flags;
sethost64(&ctlr->gib->scp, ctlr->sci);
csr32w(ctlr, Spi, 0);
ctlr->srb = malloc(sizeof(Block*)*Nsr);
@@ -786,7 +816,7 @@ ga620init(Ether* edev)
flags = TcpUdpCksum|NoPseudoHdrCksum;
else
flags = 0;
- ctlr->gib->rsrcb.control = ((ETHERMAXTU+4)<<16)|flags;
+ ctlr->gib->rsrcb.control = (ETHERMAXTU+4)<<16 | flags;
csr32w(ctlr, Rspi, 0);
/*
@@ -802,7 +832,7 @@ ga620init(Ether* edev)
*/
ctlr->rrr = malign(sizeof(Rbd)*Nrrr);
sethost64(&ctlr->gib->rrrcb.addr, ctlr->rrr);
- ctlr->gib->rrrcb.control = (Nrrr<<16)|0;
+ ctlr->gib->rrrcb.control = Nrrr<<16 | 0;
sethost64(&ctlr->gib->rrrpp, ctlr->rrrpi);
ctlr->rrrci = 0;
@@ -1024,8 +1054,8 @@ ga620detach(Ctlr* ctlr)
* wait for code to be loaded from serial EEPROM or flash;
* make sure CPU A is halted.
*/
- csr32w(ctlr, Mhc, (Hr<<24)|Hr);
- csr32w(ctlr, Mhc, ((Eews|Ci)<<24)|(Eews|Ci));
+ csr32w(ctlr, Mhc, Hr<<24 | Hr);
+ csr32w(ctlr, Mhc, (Eews|Ci)<<24 | Eews|Ci);
microdelay(1);
for(timeo = 0; timeo < 500000; timeo++){
@@ -1056,7 +1086,7 @@ print("ga620shutdown\n");
static int
ga620reset(Ctlr* ctlr)
{
- int cls, csr, i;
+ int cls, csr, i, r;
if(ga620detach(ctlr) < 0)
return -1;
@@ -1095,8 +1125,9 @@ ga620reset(Ctlr* ctlr)
* Snarf the MAC address from the serial EEPROM.
*/
for(i = 0; i < Eaddrlen; i++){
- if((ctlr->ea[i] = at24c32r(ctlr, 0x8E+i)) == -1)
+ if((r = at24c32r(ctlr, 0x8E+i)) == -1)
return -1;
+ ctlr->ea[i] = r;
}
/*
@@ -1114,7 +1145,7 @@ ga620reset(Ctlr* ctlr)
static void
ga620pci(void)
{
- int port;
+ void *mem;
Pcidev *p;
Ctlr *ctlr;
@@ -1123,30 +1154,30 @@ ga620pci(void)
if(p->ccrb != 0x02 || p->ccru != 0)
continue;
- switch((p->did<<16)|p->vid){
+ switch(p->did<<16 | p->vid){
default:
continue;
- case (0x620A<<16)|0x1385: /* Netgear GA620 */
- case (0x630A<<16)|0x1385: /* Netgear GA620T */
- case (0x0001<<16)|0x12AE: /* Alteon Acenic fiber
+ case 0x620A<<16 | 0x1385: /* Netgear GA620 fiber */
+ case 0x630A<<16 | 0x1385: /* Netgear GA620T copper */
+ case 0x0001<<16 | 0x12AE: /* Alteon Acenic fiber
* and DEC DEGPA-SA */
- case (0x0002<<16)|0x12AE: /* Alteon Acenic copper */
- case (0x0009<<16)|0x10A9: /* SGI Acenic */
+ case 0x0002<<16 | 0x12AE: /* Alteon Acenic copper */
+ case 0x0009<<16 | 0x10A9: /* SGI Acenic */
break;
}
- port = upamalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0);
- if(port == 0){
+ mem = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size);
+ if(mem == 0){
print("ga620: can't map %8.8luX\n", p->mem[0].bar);
continue;
}
ctlr = malloc(sizeof(Ctlr));
- ctlr->port = port;
+ ctlr->port = p->mem[0].bar & ~0x0F;
ctlr->pcidev = p;
- ctlr->id = (p->did<<16)|p->vid;
+ ctlr->id = p->did<<16 | p->vid;
- ctlr->nic = KADDR(ctlr->port);
+ ctlr->nic = mem;
if(ga620reset(ctlr)){
free(ctlr);
continue;
@@ -1160,6 +1191,25 @@ ga620pci(void)
}
}
+static void
+ga620promiscuous(void *arg, int on)
+{
+ Ether *ether = arg;
+
+ /* 3rd arg: 1 enables, 2 disables */
+ ga620command(ether->ctlr, 0xa, (on? 1: 2), 0);
+}
+
+static void
+ga620multicast(void *arg, uchar *addr, int on)
+{
+ Ether *ether = arg;
+
+ USED(addr);
+ /* 3rd arg: 1 enables, 2 disables */
+ ga620command(ether->ctlr, 0xe, (on? 1: 2), 0);
+}
+
static int
ga620pnp(Ether* edev)
{
@@ -1188,7 +1238,7 @@ ga620pnp(Ether* edev)
edev->port = ctlr->port;
edev->irq = ctlr->pcidev->intl;
edev->tbdf = ctlr->pcidev->tbdf;
- edev->mbps = 1000;
+ edev->mbps = 1000; /* placeholder */
/*
* Check if the adapter's station address is to be overridden.
@@ -1209,10 +1259,11 @@ ga620pnp(Ether* edev)
edev->interrupt = ga620interrupt;
edev->ifstat = ga620ifstat;
edev->ctl = ga620ctl;
- edev->shutdown = ga620shutdown;
edev->arg = edev;
- edev->promiscuous = nil;
+ edev->promiscuous = ga620promiscuous;
+ edev->multicast = ga620multicast;
+ edev->shutdown = ga620shutdown;
return 0;
}
diff --git a/os/pc/etherigbe.c b/os/pc/etherigbe.c
index a8c54267..10515097 100644
--- a/os/pc/etherigbe.c
+++ b/os/pc/etherigbe.c
@@ -29,16 +29,17 @@
#include "ethermii.h"
enum {
- i82542 = (0x1000<<16)|0x8086,
- i82543gc = (0x1004<<16)|0x8086,
- i82544ei = (0x1008<<16)|0x8086,
- i82547ei = (0x1019<<16)|0x8086,
- i82540em = (0x100E<<16)|0x8086,
- i82540eplp = (0x101E<<16)|0x8086,
+ i82542 = (0x1000<<16)|0x8086,
+ i82543gc = (0x1004<<16)|0x8086,
+ i82544ei = (0x1008<<16)|0x8086,
+ i82547ei = (0x1019<<16)|0x8086,
+ i82540em = (0x100E<<16)|0x8086,
+ i82540eplp = (0x101E<<16)|0x8086,
i82545gmc = (0x1026<<16)|0x8086,
- i82547gi = (0x1075<<16)|0x8086,
- i82541gi = (0x1076<<16)|0x8086,
- i82546gb = (0x1079<<16)|0x8086,
+ i82547gi = (0x1075<<16)|0x8086,
+ i82541gi = (0x1076<<16)|0x8086,
+ i82541gi2 = (0x1077<<16)|0x8086,
+ i82546gb = (0x1079<<16)|0x8086,
i82541pi = (0x107c<<16)|0x8086,
i82546eb = (0x1010<<16)|0x8086,
};
@@ -172,7 +173,9 @@ enum { /* Eecd */
Do = 0x00000008, /* Data Output from the EEPROM */
Areq = 0x00000040, /* EEPROM Access Request */
Agnt = 0x00000080, /* EEPROM Access Grant */
+ Eepresent = 0x00000100, /* EEPROM Present */
Eesz256 = 0x00000200, /* EEPROM is 256 words not 64 */
+ Eeszaddr = 0x00000400, /* EEPROM size for 8254[17] */
Spi = 0x00002000, /* EEPROM is SPI not Microwire */
};
@@ -442,6 +445,7 @@ typedef struct Ctlr {
int port;
Pcidev* pcidev;
Ctlr* next;
+ Ether* edev;
int active;
int started;
int id;
@@ -508,7 +512,7 @@ static Ctlr* igbectlrhead;
static Ctlr* igbectlrtail;
static Lock igberblock; /* free receive Blocks */
-static Block* igberbpool;
+static Block* igberbpool; /* receive Blocks for all igbe controllers */
static char* statistics[Nstatistics] = {
"CRC Error",
@@ -671,13 +675,13 @@ igbectl(Ether* edev, void* buf, long n)
{
int v;
char *p;
- Ctlr *ctlr;
+ Ctlr *ctlr;
Cmdbuf *cb;
Cmdtab *ct;
if((ctlr = edev->ctlr) == nil)
error(Enonexist);
-
+
cb = parsecmd(buf, n);
if(waserror()){
free(cb);
@@ -736,7 +740,7 @@ igbemulticast(void* arg, uchar* addr, int on)
ctlr->mta[x] |= 1<<bit;
else
ctlr->mta[x] &= ~(1<<bit);
-
+
csr32w(ctlr, Mta+x*4, ctlr->mta[x]);
}
@@ -831,6 +835,7 @@ igbelproc(void* arg)
case i82540eplp:
case i82547gi:
case i82541gi:
+ case i82541gi2:
case i82541pi:
break;
}
@@ -881,6 +886,7 @@ igbetxinit(Ctlr* ctlr)
case i82540em:
case i82540eplp:
case i82541gi:
+ case i82541gi2:
case i82541pi:
case i82545gmc:
case i82546gb:
@@ -923,6 +929,7 @@ igbetxinit(Ctlr* ctlr)
case i82546gb:
case i82546eb:
case i82541gi:
+ case i82541gi2:
case i82541pi:
r = csr32r(ctlr, Txdctl);
r &= ~WthreshMASK;
@@ -1006,7 +1013,8 @@ igbereplenish(Ctlr* ctlr)
if(ctlr->rb[rdt] == nil){
bp = igberballoc();
if(bp == nil){
- iprint("no available buffers\n");
+ iprint("#l%d: igbereplenish: no available buffers\n",
+ ctlr->edev->ctlrno);
break;
}
ctlr->rb[rdt] = bp;
@@ -1052,6 +1060,7 @@ igberxinit(Ctlr* ctlr)
case i82540em:
case i82540eplp:
case i82541gi:
+ case i82541gi2:
case i82541pi:
case i82545gmc:
case i82546gb:
@@ -1100,10 +1109,10 @@ igberproc(void* arg)
rdh = ctlr->rdh;
for(;;){
rd = &ctlr->rdba[rdh];
-
+
if(!(rd->status & Rdd))
break;
-
+
/*
* Accept eop packets with no errors.
* With no errors and the Ixsm bit set,
@@ -1150,7 +1159,7 @@ igberproc(void* arg)
rdh = NEXT(rdh, ctlr->nrd);
}
ctlr->rdh = rdh;
-
+
if(ctlr->rdfree < ctlr->nrd/2 || (ctlr->rim & Rxdmt0))
igbereplenish(ctlr);
}
@@ -1164,6 +1173,7 @@ igbeattach(Ether* edev)
char name[KNAMELEN];
ctlr = edev->ctlr;
+ ctlr->edev = edev; /* point back to Ether* */
qlock(&ctlr->alock);
if(ctlr->alloc != nil){
qunlock(&ctlr->alock);
@@ -1177,7 +1187,7 @@ igbeattach(Ether* edev)
qunlock(&ctlr->alock);
return;
}
- ctlr->rdba = (Rd*)ROUNDUP((ulong)ctlr->alloc, 128);
+ ctlr->rdba = (Rd*)ROUNDUP((uintptr)ctlr->alloc, 128);
ctlr->tdba = (Td*)(ctlr->rdba+ctlr->nrd);
ctlr->rb = malloc(ctlr->nrd*sizeof(Block*));
@@ -1448,6 +1458,7 @@ igbemii(Ctlr* ctlr)
case i82540eplp:
case i82547gi:
case i82541gi:
+ case i82541gi2:
case i82541pi:
case i82545gmc:
case i82546gb:
@@ -1468,7 +1479,8 @@ igbemii(Ctlr* ctlr)
ctlr->mii = nil;
return -1;
}
- print("oui %X phyno %d\n", phy->oui, phy->phyno);
+ USED(phy);
+ // print("oui %X phyno %d\n", phy->oui, phy->phyno);
/*
* 8254X-specific PHY registers not in 802.3:
@@ -1480,6 +1492,7 @@ igbemii(Ctlr* ctlr)
switch(ctlr->id){
case i82547gi:
case i82541gi:
+ case i82541gi2:
case i82541pi:
case i82545gmc:
case i82546gb:
@@ -1491,13 +1504,13 @@ igbemii(Ctlr* ctlr)
r |= 0x0060; /* auto-crossover all speeds */
r |= 0x0002; /* polarity reversal enabled */
miimiw(ctlr->mii, 16, r);
-
+
r = miimir(ctlr->mii, 20);
r |= 0x0070; /* +25MHz clock */
r &= ~0x0F00;
r |= 0x0100; /* 1x downshift */
miimiw(ctlr->mii, 20, r);
-
+
miireset(ctlr->mii);
p = 0;
if(ctlr->txcw & TxcwPs)
@@ -1578,7 +1591,7 @@ at93c46io(Ctlr* ctlr, char* op, int data)
break;
}
csr32w(ctlr, Eecd, eecd);
- microdelay(1);
+ microdelay(50);
}
if(loop >= 0)
return -1;
@@ -1597,11 +1610,10 @@ at93c46r(Ctlr* ctlr)
print("igbe: SPI EEPROM access not implemented\n");
return 0;
}
- if(eecd & Eesz256)
+ if(eecd & (Eeszaddr|Eesz256))
bits = 8;
else
bits = 6;
- snprint(rop, sizeof(rop), "S :%dDCc;", bits+3);
sum = 0;
@@ -1609,11 +1621,12 @@ at93c46r(Ctlr* ctlr)
default:
areq = 0;
break;
+ case i82541gi:
+ case i82547gi:
case i82540em:
case i82540eplp:
- case i82541gi:
case i82541pi:
- case i82547gi:
+ case i82541gi2:
case i82545gmc:
case i82546gb:
case i82546eb:
@@ -1630,6 +1643,7 @@ at93c46r(Ctlr* ctlr)
}
break;
}
+ snprint(rop, sizeof(rop), "S :%dDCc;", bits+3);
for(addr = 0; addr < 0x40; addr++){
/*
@@ -1698,6 +1712,7 @@ igbedetach(Ctlr* ctlr)
case i82541gi:
case i82541pi:
case i82547gi:
+ case i82541gi2:
case i82545gmc:
case i82546gb:
case i82546eb:
@@ -1751,6 +1766,8 @@ igbereset(Ctlr* ctlr)
if ((ctlr->id == i82546gb || ctlr->id == i82546eb) && BUSFNO(ctlr->pcidev->tbdf) == 1)
ctlr->eeprom[Ea+2] += 0x100; // second interface
for(i = Ea; i < Eaddrlen/2; i++){
+if(i == Ea && ctlr->id == i82541gi && ctlr->eeprom[i] == 0xFFFF)
+ ctlr->eeprom[i] = 0xD000;
ctlr->ra[2*i] = ctlr->eeprom[i];
ctlr->ra[2*i+1] = ctlr->eeprom[i]>>8;
}
@@ -1773,14 +1790,14 @@ igbereset(Ctlr* ctlr)
/*
* Just in case the Eerst didn't load the defaults
- * (doesn't appear to fully on the 8243GC), do it manually.
+ * (doesn't appear to fully on the 82543GC), do it manually.
*/
- if (ctlr->id == i82543gc) { // 82543
+ if (ctlr->id == i82543gc) {
txcw = csr32r(ctlr, Txcw);
txcw &= ~(TxcwAne|TxcwPauseMASK|TxcwFd);
ctrl = csr32r(ctlr, Ctrl);
ctrl &= ~(SwdpioloMASK|Frcspd|Ilos|Lrst|Fd);
-
+
if(ctlr->eeprom[Icw1] & 0x0400){
ctrl |= Fd;
txcw |= TxcwFd;
@@ -1794,7 +1811,7 @@ igbereset(Ctlr* ctlr)
swdpio = (ctlr->eeprom[Icw1] & 0x01E0)>>5;
ctrl |= swdpio<<SwdpioloSHIFT;
csr32w(ctlr, Ctrl, ctrl);
-
+
ctrl = csr32r(ctlr, Ctrlext);
ctrl &= ~(Ips|SwdpiohiMASK);
swdpio = (ctlr->eeprom[Icw2] & 0x00F0)>>4;
@@ -1802,7 +1819,7 @@ igbereset(Ctlr* ctlr)
ctrl |= Ips;
ctrl |= swdpio<<SwdpiohiSHIFT;
csr32w(ctlr, Ctrlext, ctrl);
-
+
if(ctlr->eeprom[Icw2] & 0x0800)
txcw |= TxcwAne;
pause = (ctlr->eeprom[Icw2] & 0x3000)>>12;
@@ -1827,7 +1844,7 @@ igbereset(Ctlr* ctlr)
csr32w(ctlr, Txcw, txcw);
}
-
+
/*
* Flow control - values from the datasheet.
*/
@@ -1848,9 +1865,10 @@ igbereset(Ctlr* ctlr)
static void
igbepci(void)
{
- int port, cls;
+ int cls;
Pcidev *p;
Ctlr *ctlr;
+ void *mem;
p = nil;
while(p = pcimatch(p, 0, 0)){
@@ -1865,8 +1883,9 @@ igbepci(void)
case i82547ei:
case i82540em:
case i82540eplp:
- case i82547gi:
case i82541gi:
+ case i82547gi:
+ case i82541gi2:
case i82541pi:
case i82545gmc:
case i82546gb:
@@ -1874,8 +1893,8 @@ igbepci(void)
break;
}
- port = upamalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0);
- if(port == 0){
+ mem = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size);
+ if(mem == nil){
print("igbe: can't map %8.8luX\n", p->mem[0].bar);
continue;
}
@@ -1893,14 +1912,15 @@ igbepci(void)
break;
}
ctlr = malloc(sizeof(Ctlr));
- ctlr->port = port;
+ ctlr->port = p->mem[0].bar & ~0x0F;
ctlr->pcidev = p;
ctlr->id = (p->did<<16)|p->vid;
ctlr->cls = cls*4;
- ctlr->nic = KADDR(ctlr->port);
+ ctlr->nic = mem;
if(igbereset(ctlr)){
free(ctlr);
+ vunmap(mem, p->mem[0].size);
continue;
}
pcisetbme(p);
@@ -1966,3 +1986,4 @@ etherigbelink(void)
addethercard("i82543", igbepnp);
addethercard("igbe", igbepnp);
}
+
diff --git a/os/pc/ethersmc.c b/os/pc/ethersmc.c
index ddd3f729..65ebffca 100644
--- a/os/pc/ethersmc.c
+++ b/os/pc/ethersmc.c
@@ -713,6 +713,7 @@ reset(Ether* ether)
if (ctlr == 0) {
iofree(ether->port);
pcmspecialclose(slot);
+ return -1;
}
ilock(ctlr);
diff --git a/os/pc/ethervt6102.c b/os/pc/ethervt6102.c
new file mode 100644
index 00000000..20d43a4e
--- /dev/null
+++ b/os/pc/ethervt6102.c
@@ -0,0 +1,1025 @@
+/*
+ * VIA VT6102 Fast Ethernet Controller (Rhine II).
+ * To do:
+ * cache-line size alignments - done
+ * reduce tx interrupts
+ * use 2 descriptors on tx for alignment - done
+ * reorganise initialisation/shutdown/reset
+ * adjust Tx FIFO threshold on underflow - untested
+ * why does the link status never cause an interrupt?
+ * use the lproc as a periodic timer for stalls, etc.
+ */
+#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"
+#include "ethermii.h"
+
+enum {
+ Par0 = 0x00, /* Ethernet Address */
+ Rcr = 0x06, /* Receive Configuration */
+ Tcr = 0x07, /* Transmit Configuration */
+ Cr = 0x08, /* Control */
+ Isr = 0x0C, /* Interrupt Status */
+ Imr = 0x0E, /* Interrupt Mask */
+ Rxdaddr = 0x18, /* Current Rx Descriptor Address */
+ Txdaddr = 0x1C, /* Current Tx Descriptor Address */
+ Phyadr = 0x6C, /* Phy Address */
+ Miisr = 0x6D, /* MII Status */
+ Bcr0 = 0x6E, /* Bus Control */
+ Bcr1 = 0x6F,
+ Miicr = 0x70, /* MII Control */
+ Miiadr = 0x71, /* MII Address */
+ Miidata = 0x72, /* MII Data */
+ Eecsr = 0x74, /* EEPROM Control and Status */
+};
+
+enum { /* Rcr */
+ Sep = 0x01, /* Accept Error Packets */
+ Ar = 0x02, /* Accept Small Packets */
+ Am = 0x04, /* Accept Multicast */
+ Ab = 0x08, /* Accept Broadcast */
+ Prom = 0x10, /* Accept Physical Address Packets */
+ RrftMASK = 0xE0, /* Receive FIFO Threshold */
+ RrftSHIFT = 5,
+ Rrft64 = 0<<RrftSHIFT,
+ Rrft32 = 1<<RrftSHIFT,
+ Rrft128 = 2<<RrftSHIFT,
+ Rrft256 = 3<<RrftSHIFT,
+ Rrft512 = 4<<RrftSHIFT,
+ Rrft768 = 5<<RrftSHIFT,
+ Rrft1024 = 6<<RrftSHIFT,
+ RrftSAF = 7<<RrftSHIFT,
+};
+
+enum { /* Tcr */
+ Lb0 = 0x02, /* Loopback Mode */
+ Lb1 = 0x04,
+ Ofset = 0x08, /* Back-off Priority Selection */
+ RtsfMASK = 0xE0, /* Transmit FIFO Threshold */
+ RtsfSHIFT = 5,
+ Rtsf128 = 0<<RtsfSHIFT,
+ Rtsf256 = 1<<RtsfSHIFT,
+ Rtsf512 = 2<<RtsfSHIFT,
+ Rtsf1024 = 3<<RtsfSHIFT,
+ RtsfSAF = 7<<RtsfSHIFT,
+};
+
+enum { /* Cr */
+ Init = 0x0001, /* INIT Process Begin */
+ Strt = 0x0002, /* Start NIC */
+ Stop = 0x0004, /* Stop NIC */
+ Rxon = 0x0008, /* Turn on Receive Process */
+ Txon = 0x0010, /* Turn on Transmit Process */
+ Tdmd = 0x0020, /* Transmit Poll Demand */
+ Rdmd = 0x0040, /* Receive Poll Demand */
+ Eren = 0x0100, /* Early Receive Enable */
+ Fdx = 0x0400, /* Set MAC to Full Duplex Mode */
+ Dpoll = 0x0800, /* Disable Td/Rd Auto Polling */
+ Tdmd1 = 0x2000, /* Transmit Poll Demand 1 */
+ Rdmd1 = 0x4000, /* Receive Poll Demand 1 */
+ Sfrst = 0x8000, /* Software Reset */
+};
+
+enum { /* Isr/Imr */
+ Prx = 0x0001, /* Received Packet Successfully */
+ Ptx = 0x0002, /* Transmitted Packet Successfully */
+ Rxe = 0x0004, /* Receive Error */
+ Txe = 0x0008, /* Transmit Error */
+ Tu = 0x0010, /* Transmit Buffer Underflow */
+ Ru = 0x0020, /* Receive Buffer Link Error */
+ Be = 0x0040, /* PCI Bus Error */
+ Cnt = 0x0080, /* Counter Overflow */
+ Eri = 0x0100, /* Early Receive Interrupt */
+ Udfi = 0x0200, /* Tx FIFO Underflow */
+ Ovfi = 0x0400, /* Receive FIFO Overflow */
+ Pktrace = 0x0800, /* Hmmm... */
+ Norbf = 0x1000, /* No Receive Buffers */
+ Abti = 0x2000, /* Transmission Abort */
+ Srci = 0x4000, /* Port State Change */
+ Geni = 0x8000, /* General Purpose Interrupt */
+};
+
+enum { /* Phyadr */
+ PhyadMASK = 0x1F, /* PHY Address */
+ PhyadSHIFT = 0,
+ Mfdc = 0x20, /* Accelerate MDC Speed */
+ Mpo0 = 0x40, /* MII Polling Timer Interval */
+ Mpo1 = 0x80,
+};
+
+enum { /* Bcr0 */
+ DmaMASK = 0x07, /* DMA Length */
+ DmaSHIFT = 0,
+ Dma32 = 0<<DmaSHIFT,
+ Dma64 = 1<<DmaSHIFT,
+ Dma128 = 2<<DmaSHIFT,
+ Dma256 = 3<<DmaSHIFT,
+ Dma512 = 4<<DmaSHIFT,
+ Dma1024 = 5<<DmaSHIFT,
+ DmaSAF = 7<<DmaSHIFT,
+ CrftMASK = 0x38, /* Rx FIFO Threshold */
+ CrftSHIFT = 3,
+ Crft64 = 1<<CrftSHIFT,
+ Crft128 = 2<<CrftSHIFT,
+ Crft256 = 3<<CrftSHIFT,
+ Crft512 = 4<<CrftSHIFT,
+ Crft1024 = 5<<CrftSHIFT,
+ CrftSAF = 7<<CrftSHIFT,
+ Extled = 0x40, /* Extra LED Support Control */
+ Med2 = 0x80, /* Medium Select Control */
+};
+
+enum { /* Bcr1 */
+ PotMASK = 0x07, /* Polling Timer Interval */
+ PotSHIFT = 0,
+ CtftMASK = 0x38, /* Tx FIFO Threshold */
+ CtftSHIFT = 3,
+ Ctft64 = 1<<CtftSHIFT,
+ Ctft128 = 2<<CtftSHIFT,
+ Ctft256 = 3<<CtftSHIFT,
+ Ctft512 = 4<<CtftSHIFT,
+ Ctft1024 = 5<<CtftSHIFT,
+ CtftSAF = 7<<CtftSHIFT,
+};
+
+enum { /* Miicr */
+ Mdc = 0x01, /* Clock */
+ Mdi = 0x02, /* Data In */
+ Mdo = 0x04, /* Data Out */
+ Mout = 0x08, /* Output Enable */
+ Mdpm = 0x10, /* Direct Program Mode Enable */
+ Wcmd = 0x20, /* Write Enable */
+ Rcmd = 0x40, /* Read Enable */
+ Mauto = 0x80, /* Auto Polling Enable */
+};
+
+enum { /* Miiadr */
+ MadMASK = 0x1F, /* MII Port Address */
+ MadSHIFT = 0,
+ Mdone = 0x20, /* Accelerate MDC Speed */
+ Msrcen = 0x40, /* MII Polling Timer Interval */
+ Midle = 0x80,
+};
+
+enum { /* Eecsr */
+ Edo = 0x01, /* Data Out */
+ Edi = 0x02, /* Data In */
+ Eck = 0x04, /* Clock */
+ Ecs = 0x08, /* Chip Select */
+ Dpm = 0x10, /* Direct Program Mode Enable */
+ Autold = 0x20, /* Dynamic Reload */
+ Embp = 0x40, /* Embedded Program Enable */
+ Eepr = 0x80, /* Programmed */
+};
+
+/*
+ * Ring descriptor. The space allocated for each
+ * of these will be rounded up to a cache-line boundary.
+ * The first 4 elements are known to the hardware.
+ */
+typedef struct Ds Ds;
+typedef struct Ds {
+ uint status;
+ uint control;
+ uint addr;
+ uint branch;
+
+ Block* bp;
+ void* bounce;
+ Ds* next;
+ Ds* prev;
+} Ds;
+
+enum { /* Rx Ds status */
+ Rerr = 0x00000001, /* Receiver Error */
+ Crc = 0x00000002, /* CRC Error */
+ Fae = 0x00000004, /* Frame Alignment Error */
+ Fov = 0x00000008, /* FIFO Overflow */
+ Long = 0x00000010, /* A Long Packet */
+ Runt = 0x00000020, /* A Runt Packet */
+ Rxserr = 0x00000040, /* System Error */
+ Buff = 0x00000080, /* Buffer Underflow Error */
+ Rxedp = 0x00000100, /* End of Packet Buffer */
+ Rxstp = 0x00000200, /* Packet Start */
+ Chn = 0x00000400, /* Chain Buffer */
+ Phy = 0x00000800, /* Physical Address Packet */
+ Bar = 0x00001000, /* Broadcast Packet */
+ Mar = 0x00002000, /* Multicast Packet */
+ Rxok = 0x00008000, /* Packet Received Successfully */
+ LengthMASK = 0x07FF0000, /* Received Packet Length */
+ LengthSHIFT = 16,
+
+ Own = 0x80000000, /* Descriptor Owned by NIC */
+};
+
+enum { /* Tx Ds status */
+ NcrMASK = 0x0000000F, /* Collision Retry Count */
+ NcrSHIFT = 0,
+ Cols = 0x00000010, /* Experienced Collisions */
+ Cdh = 0x00000080, /* CD Heartbeat */
+ Abt = 0x00000100, /* Aborted after Excessive Collisions */
+ Owc = 0x00000200, /* Out of Window Collision Seen */
+ Crs = 0x00000400, /* Carrier Sense Lost */
+ Udf = 0x00000800, /* FIFO Underflow */
+ Tbuff = 0x00001000, /* Invalid Td */
+ Txserr = 0x00002000, /* System Error */
+ Terr = 0x00008000, /* Excessive Collisions */
+};
+
+enum { /* Tx Ds control */
+ TbsMASK = 0x000007FF, /* Tx Buffer Size */
+ TbsSHIFT = 0,
+ Chain = 0x00008000, /* Chain Buffer */
+ Crcdisable = 0x00010000, /* Disable CRC generation */
+ Stp = 0x00200000, /* Start of Packet */
+ Edp = 0x00400000, /* End of Packet */
+ Ic = 0x00800000, /* Assert Interrupt Immediately */
+};
+
+enum {
+ Nrd = 64,
+ Ntd = 64,
+ Rdbsz = ROUNDUP(ETHERMAXTU+4, 4),
+
+ Nrxstats = 8,
+ Ntxstats = 9,
+
+ Txcopy = 128,
+};
+
+typedef struct Ctlr Ctlr;
+typedef struct Ctlr {
+ int port;
+ Pcidev* pcidev;
+ Ctlr* next;
+ int active;
+ int id;
+ uchar par[Eaddrlen];
+
+ QLock alock; /* attach */
+ void* alloc; /* receive/transmit descriptors */
+ int cls; /* alignment */
+ int nrd;
+ int ntd;
+
+ Ds* rd;
+ Ds* rdh;
+
+ Lock tlock;
+ Ds* td;
+ Ds* tdh;
+ Ds* tdt;
+ int tdused;
+
+ Lock clock; /* */
+ int cr;
+ int imr;
+ int tft; /* Tx threshold */
+
+ Mii* mii;
+ Rendez lrendez;
+ int lwakeup;
+
+ uint rxstats[Nrxstats]; /* statistics */
+ uint txstats[Ntxstats];
+ uint intr;
+ uint lintr;
+ uint lsleep;
+ uint rintr;
+ uint tintr;
+ uint taligned;
+ uint tsplit;
+ uint tcopied;
+ uint txdw;
+} Ctlr;
+
+static Ctlr* vt6102ctlrhead;
+static Ctlr* vt6102ctlrtail;
+
+#define csr8r(c, r) (inb((c)->port+(r)))
+#define csr16r(c, r) (ins((c)->port+(r)))
+#define csr32r(c, r) (inl((c)->port+(r)))
+#define csr8w(c, r, b) (outb((c)->port+(r), (int)(b)))
+#define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))
+#define csr32w(c, r, w) (outl((c)->port+(r), (ulong)(w)))
+
+static char* rxstats[Nrxstats] = {
+ "Receiver Error",
+ "CRC Error",
+ "Frame Alignment Error",
+ "FIFO Overflow",
+ "Long Packet",
+ "Runt Packet",
+ "System Error",
+ "Buffer Underflow Error",
+};
+static char* txstats[Ntxstats] = {
+ "Aborted after Excessive Collisions",
+ "Out of Window Collision Seen",
+ "Carrier Sense Lost",
+ "FIFO Underflow",
+ "Invalid Td",
+ "System Error",
+ nil,
+ "Excessive Collisions",
+};
+
+static long
+vt6102ifstat(Ether* edev, void* a, long n, ulong offset)
+{
+ char *p;
+ Ctlr *ctlr;
+ int i, l, r;
+
+ ctlr = edev->ctlr;
+
+ p = malloc(2*READSTR);
+ l = 0;
+ for(i = 0; i < Nrxstats; i++){
+ l += snprint(p+l, 2*READSTR-l, "%s: %ud\n",
+ rxstats[i], ctlr->rxstats[i]);
+ }
+ for(i = 0; i < Ntxstats; i++){
+ if(txstats[i] == nil)
+ continue;
+ l += snprint(p+l, 2*READSTR-l, "%s: %ud\n",
+ txstats[i], ctlr->txstats[i]);
+ }
+ l += snprint(p+l, 2*READSTR-l, "cls: %ud\n", ctlr->cls);
+ l += snprint(p+l, 2*READSTR-l, "intr: %ud\n", ctlr->intr);
+ l += snprint(p+l, 2*READSTR-l, "lintr: %ud\n", ctlr->lintr);
+ l += snprint(p+l, 2*READSTR-l, "lsleep: %ud\n", ctlr->lsleep);
+ l += snprint(p+l, 2*READSTR-l, "rintr: %ud\n", ctlr->rintr);
+ l += snprint(p+l, 2*READSTR-l, "tintr: %ud\n", ctlr->tintr);
+ l += snprint(p+l, 2*READSTR-l, "taligned: %ud\n", ctlr->taligned);
+ l += snprint(p+l, 2*READSTR-l, "tsplit: %ud\n", ctlr->tsplit);
+ l += snprint(p+l, 2*READSTR-l, "tcopied: %ud\n", ctlr->tcopied);
+ l += snprint(p+l, 2*READSTR-l, "txdw: %ud\n", ctlr->txdw);
+ l += snprint(p+l, 2*READSTR-l, "tft: %ud\n", ctlr->tft);
+
+ if(ctlr->mii != nil && ctlr->mii->curphy != nil){
+ l += snprint(p+l, 2*READSTR, "phy: ");
+ for(i = 0; i < NMiiPhyr; i++){
+ if(i && ((i & 0x07) == 0))
+ l += snprint(p+l, 2*READSTR-l, "\n ");
+ r = miimir(ctlr->mii, i);
+ l += snprint(p+l, 2*READSTR-l, " %4.4uX", r);
+ }
+ snprint(p+l, 2*READSTR-l, "\n");
+ }
+ snprint(p+l, 2*READSTR-l, "\n");
+
+ n = readstr(offset, a, n, p);
+ free(p);
+
+ return n;
+}
+
+static void
+vt6102promiscuous(void* arg, int on)
+{
+ int rcr;
+ Ctlr *ctlr;
+ Ether *edev;
+
+ edev = arg;
+ ctlr = edev->ctlr;
+ rcr = csr8r(ctlr, Rcr);
+ if(on)
+ rcr |= Prom;
+ else
+ rcr &= ~Prom;
+ csr8w(ctlr, Rcr, rcr);
+}
+
+static void
+vt6102multicast(void* arg, uchar* addr, int on)
+{
+ /*
+ * For now Am is set in Rcr.
+ * Will need to interlock with promiscuous
+ * when this gets filled in.
+ */
+ USED(arg, addr, on);
+}
+
+static int
+vt6102wakeup(void* v)
+{
+ return *((int*)v) != 0;
+}
+
+static void
+vt6102imr(Ctlr* ctlr, int imr)
+{
+ ilock(&ctlr->clock);
+ ctlr->imr |= imr;
+ csr16w(ctlr, Imr, ctlr->imr);
+ iunlock(&ctlr->clock);
+}
+
+static void
+vt6102lproc(void* arg)
+{
+ Ctlr *ctlr;
+ Ether *edev;
+ MiiPhy *phy;
+
+ edev = arg;
+ ctlr = edev->ctlr;
+ for(;;){
+ if(ctlr->mii == nil || ctlr->mii->curphy == nil)
+ break;
+ if(miistatus(ctlr->mii) < 0)
+ goto enable;
+
+ phy = ctlr->mii->curphy;
+ ilock(&ctlr->clock);
+ if(phy->fd)
+ ctlr->cr |= Fdx;
+ else
+ ctlr->cr &= ~Fdx;
+ csr16w(ctlr, Cr, ctlr->cr);
+ iunlock(&ctlr->clock);
+enable:
+ ctlr->lwakeup = 0;
+ vt6102imr(ctlr, Srci);
+
+ ctlr->lsleep++;
+ sleep(&ctlr->lrendez, vt6102wakeup, &ctlr->lwakeup);
+
+ }
+ pexit("vt6102lproc: done", 1);
+}
+
+static void
+vt6102attach(Ether* edev)
+{
+ int i;
+ Ctlr *ctlr;
+ Ds *ds, *prev;
+ uchar *alloc, *bounce;
+ char name[KNAMELEN];
+
+ ctlr = edev->ctlr;
+ qlock(&ctlr->alock);
+ if(ctlr->alloc != nil){
+ qunlock(&ctlr->alock);
+ return;
+ }
+
+ /*
+ * Descriptor and bounce-buffer space.
+ * Must all be aligned on a 4-byte boundary,
+ * but try to align on cache-lines.
+ */
+ ctlr->nrd = Nrd;
+ ctlr->ntd = Ntd;
+ alloc = malloc((ctlr->nrd+ctlr->ntd)*ctlr->cls + ctlr->ntd*Txcopy + ctlr->cls-1);
+ if(alloc == nil){
+ qunlock(&ctlr->alock);
+ return;
+ }
+ ctlr->alloc = alloc;
+ alloc = (uchar*)ROUNDUP((ulong)alloc, ctlr->cls);
+
+ ctlr->rd = (Ds*)alloc;
+
+ if(waserror()){
+ ds = ctlr->rd;
+ for(i = 0; i < ctlr->nrd; i++){
+ if(ds->bp != nil){
+ freeb(ds->bp);
+ ds->bp = nil;
+ }
+ if((ds = ds->next) == nil)
+ break;
+ }
+ free(ctlr->alloc);
+ ctlr->alloc = nil;
+ qunlock(&ctlr->alock);
+ nexterror();
+ }
+
+ prev = ctlr->rd + ctlr->nrd-1;
+ for(i = 0; i < ctlr->nrd; i++){
+ ds = (Ds*)alloc;
+ alloc += ctlr->cls;
+
+ ds->control = Rdbsz;
+ ds->branch = PCIWADDR(alloc);
+
+ ds->bp = iallocb(Rdbsz+3);
+ if(ds->bp == nil)
+ error("vt6102: can't allocate receive ring\n");
+ ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4);
+ ds->addr = PCIWADDR(ds->bp->rp);
+
+ ds->next = (Ds*)alloc;
+ ds->prev = prev;
+ prev = ds;
+
+ ds->status = Own;
+ }
+ prev->branch = 0;
+ prev->next = ctlr->rd;
+ prev->status = 0;
+ ctlr->rdh = ctlr->rd;
+
+ ctlr->td = (Ds*)alloc;
+ prev = ctlr->td + ctlr->ntd-1;
+ bounce = alloc + ctlr->ntd*ctlr->cls;
+ for(i = 0; i < ctlr->ntd; i++){
+ ds = (Ds*)alloc;
+ alloc += ctlr->cls;
+
+ ds->bounce = bounce;
+ bounce += Txcopy;
+ ds->next = (Ds*)alloc;
+ ds->prev = prev;
+ prev = ds;
+ }
+ prev->next = ctlr->td;
+ ctlr->tdh = ctlr->tdt = ctlr->td;
+ ctlr->tdused = 0;
+
+ ctlr->cr = Dpoll|Rdmd|Txon|Rxon|Strt;
+ /*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/
+ ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx;
+
+ ilock(&ctlr->clock);
+ csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd));
+ csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td));
+ csr16w(ctlr, Isr, ~0);
+ csr16w(ctlr, Imr, ctlr->imr);
+ csr16w(ctlr, Cr, ctlr->cr);
+ iunlock(&ctlr->clock);
+
+ snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
+ kproc(name, vt6102lproc, edev, 0);
+
+ qunlock(&ctlr->alock);
+ poperror();
+}
+
+static void
+vt6102transmit(Ether* edev)
+{
+ Block *bp;
+ Ctlr *ctlr;
+ Ds *ds, *next;
+ int control, i, o, prefix, size, tdused, timeo;
+
+ ctlr = edev->ctlr;
+
+ ilock(&ctlr->tlock);
+
+ /*
+ * Free any completed packets
+ */
+ ds = ctlr->tdh;
+ for(tdused = ctlr->tdused; tdused > 0; tdused--){
+ /*
+ * For some errors the chip will turn the Tx engine
+ * off. Wait for that to happen.
+ * Could reset and re-init the chip here if it doesn't
+ * play fair.
+ * To do: adjust Tx FIFO threshold on underflow.
+ */
+ if(ds->status & (Abt|Tbuff|Udf)){
+ for(timeo = 0; timeo < 1000; timeo++){
+ if(!(csr16r(ctlr, Cr) & Txon))
+ break;
+ microdelay(1);
+ }
+ ds->status = Own;
+ csr32w(ctlr, Txdaddr, PCIWADDR(ds));
+ }
+
+ if(ds->status & Own)
+ break;
+ ds->addr = 0;
+ ds->branch = 0;
+
+ if(ds->bp != nil){
+ freeb(ds->bp);
+ ds->bp = nil;
+ }
+ for(i = 0; i < Ntxstats-1; i++){
+ if(ds->status & (1<<i))
+ ctlr->txstats[i]++;
+ }
+ ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
+
+ ds = ds->next;
+ }
+ ctlr->tdh = ds;
+
+ /*
+ * Try to fill the ring back up.
+ */
+ ds = ctlr->tdt;
+ while(tdused < ctlr->ntd-2){
+ if((bp = qget(edev->oq)) == nil)
+ break;
+ tdused++;
+
+ size = BLEN(bp);
+ prefix = 0;
+
+ if(o = (((int)bp->rp) & 0x03)){
+ prefix = Txcopy-o;
+ if(prefix > size)
+ prefix = size;
+ memmove(ds->bounce, bp->rp, prefix);
+ ds->addr = PCIWADDR(ds->bounce);
+ bp->rp += prefix;
+ size -= prefix;
+ }
+
+ next = ds->next;
+ ds->branch = PCIWADDR(ds->next);
+
+ if(size){
+ if(prefix){
+ next->bp = bp;
+ next->addr = PCIWADDR(bp->rp);
+ next->branch = PCIWADDR(next->next);
+ next->control = Edp|Chain|((size<<TbsSHIFT) & TbsMASK);
+
+ control = Stp|Chain|((prefix<<TbsSHIFT) & TbsMASK);
+
+ next = next->next;
+ tdused++;
+ ctlr->tsplit++;
+ }
+ else{
+ ds->bp = bp;
+ ds->addr = PCIWADDR(bp->rp);
+ control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
+ ctlr->taligned++;
+ }
+ }
+ else{
+ freeb(bp);
+ control = Edp|Stp|((prefix<<TbsSHIFT) & TbsMASK);
+ ctlr->tcopied++;
+ }
+
+ ds->control = control;
+ if(tdused >= ctlr->ntd-2){
+ ds->control |= Ic;
+ ctlr->txdw++;
+ }
+ coherence();
+ ds->status = Own;
+
+ ds = next;
+ }
+ ctlr->tdt = ds;
+ ctlr->tdused = tdused;
+ if(ctlr->tdused)
+ csr16w(ctlr, Cr, Tdmd|ctlr->cr);
+
+ iunlock(&ctlr->tlock);
+}
+
+static void
+vt6102receive(Ether* edev)
+{
+ Ds *ds;
+ Block *bp;
+ Ctlr *ctlr;
+ int i, len;
+
+ ctlr = edev->ctlr;
+
+ ds = ctlr->rdh;
+ while(!(ds->status & Own) && ds->status != 0){
+ if(ds->status & Rerr){
+ for(i = 0; i < Nrxstats; i++){
+ if(ds->status & (1<<i))
+ ctlr->rxstats[i]++;
+ }
+ }
+ else if(bp = iallocb(Rdbsz+3)){
+ len = ((ds->status & LengthMASK)>>LengthSHIFT)-4;
+ ds->bp->wp = ds->bp->rp+len;
+ etheriq(edev, ds->bp, 1);
+ bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4);
+ ds->addr = PCIWADDR(bp->rp);
+ ds->bp = bp;
+ }
+ ds->control = Rdbsz;
+ ds->branch = 0;
+ ds->status = 0;
+
+ ds->prev->branch = PCIWADDR(ds);
+ coherence();
+ ds->prev->status = Own;
+
+ ds = ds->next;
+ }
+ ctlr->rdh = ds;
+
+ csr16w(ctlr, Cr, ctlr->cr);
+}
+
+static void
+vt6102interrupt(Ureg*, void* arg)
+{
+ Ctlr *ctlr;
+ Ether *edev;
+ int imr, isr, r, timeo;
+
+ edev = arg;
+ ctlr = edev->ctlr;
+
+ ilock(&ctlr->clock);
+ csr16w(ctlr, Imr, 0);
+ imr = ctlr->imr;
+ ctlr->intr++;
+ for(;;){
+ if((isr = csr16r(ctlr, Isr)) != 0)
+ csr16w(ctlr, Isr, isr);
+ if((isr & ctlr->imr) == 0)
+ break;
+
+ if(isr & Srci){
+ imr &= ~Srci;
+ ctlr->lwakeup = isr & Srci;
+ wakeup(&ctlr->lrendez);
+ isr &= ~Srci;
+ ctlr->lintr++;
+ }
+ if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
+ vt6102receive(edev);
+ isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
+ ctlr->rintr++;
+ }
+ if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
+ if(isr & (Abti|Udfi|Tu)){
+ for(timeo = 0; timeo < 1000; timeo++){
+ if(!(csr16r(ctlr, Cr) & Txon))
+ break;
+ microdelay(1);
+ }
+
+ if((isr & Udfi) && ctlr->tft < CtftSAF){
+ ctlr->tft += 1<<CtftSHIFT;
+ r = csr8r(ctlr, Bcr1) & ~CtftMASK;
+ csr8w(ctlr, Bcr1, r|ctlr->tft);
+ }
+ }
+ vt6102transmit(edev);
+ isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
+ ctlr->tintr++;
+ }
+ if(isr)
+ panic("vt6102: isr %4.4uX\n", isr);
+ }
+ ctlr->imr = imr;
+ csr16w(ctlr, Imr, ctlr->imr);
+ iunlock(&ctlr->clock);
+}
+
+static int
+vt6102miimicmd(Mii* mii, int pa, int ra, int cmd, int data)
+{
+ Ctlr *ctlr;
+ int r, timeo;
+
+ ctlr = mii->ctlr;
+
+ csr8w(ctlr, Miicr, 0);
+ r = csr8r(ctlr, Phyadr);
+ csr8w(ctlr, Phyadr, (r & ~PhyadMASK)|pa);
+ csr8w(ctlr, Phyadr, pa);
+ csr8w(ctlr, Miiadr, ra);
+ if(cmd == Wcmd)
+ csr16w(ctlr, Miidata, data);
+ csr8w(ctlr, Miicr, cmd);
+
+ for(timeo = 0; timeo < 10000; timeo++){
+ if(!(csr8r(ctlr, Miicr) & cmd))
+ break;
+ microdelay(1);
+ }
+ if(timeo >= 10000)
+ return -1;
+
+ if(cmd == Wcmd)
+ return 0;
+ return csr16r(ctlr, Miidata);
+}
+
+static int
+vt6102miimir(Mii* mii, int pa, int ra)
+{
+ return vt6102miimicmd(mii, pa, ra, Rcmd, 0);
+}
+
+static int
+vt6102miimiw(Mii* mii, int pa, int ra, int data)
+{
+ return vt6102miimicmd(mii, pa, ra, Wcmd, data);
+}
+
+static int
+vt6102detach(Ctlr* ctlr)
+{
+ int timeo;
+
+ /*
+ * Soft reset the controller.
+ */
+ csr16w(ctlr, Cr, Sfrst);
+ for(timeo = 0; timeo < 10000; timeo++){
+ if(!(csr16r(ctlr, Cr) & Sfrst))
+ break;
+ microdelay(1);
+ }
+ if(timeo >= 1000)
+ return -1;
+
+ return 0;
+}
+
+static int
+vt6102reset(Ctlr* ctlr)
+{
+ MiiPhy *phy;
+ int i, r, timeo;
+
+ if(vt6102detach(ctlr) < 0)
+ return -1;
+
+ /*
+ * Load the MAC address into the PAR[01]
+ * registers.
+ */
+ r = csr8r(ctlr, Eecsr);
+ csr8w(ctlr, Eecsr, Autold|r);
+ for(timeo = 0; timeo < 100; timeo++){
+ if(!(csr8r(ctlr, Cr) & Autold))
+ break;
+ microdelay(1);
+ }
+ if(timeo >= 100)
+ return -1;
+
+ for(i = 0; i < Eaddrlen; i++)
+ ctlr->par[i] = csr8r(ctlr, Par0+i);
+
+ /*
+ * Configure DMA and Rx/Tx thresholds.
+ * If the Rx/Tx threshold bits in Bcr[01] are 0 then
+ * the thresholds are determined by Rcr/Tcr.
+ */
+ r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
+ csr8w(ctlr, Bcr0, r|Crft64|Dma64);
+ r = csr8r(ctlr, Bcr1) & ~CtftMASK;
+ csr8w(ctlr, Bcr1, r|ctlr->tft);
+
+ r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
+ csr8w(ctlr, Rcr, r|Ab|Am);
+
+ r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
+ csr8w(ctlr, Tcr, r);
+
+ /*
+ * Link management.
+ */
+ if((ctlr->mii = malloc(sizeof(Mii))) == nil)
+ return -1;
+ ctlr->mii->mir = vt6102miimir;
+ ctlr->mii->miw = vt6102miimiw;
+ ctlr->mii->ctlr = ctlr;
+
+ if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
+ free(ctlr->mii);
+ ctlr->mii = nil;
+ return -1;
+ }
+ // print("oui %X phyno %d\n", phy->oui, phy->phyno);
+ USED(phy);
+
+ //miiane(ctlr->mii, ~0, ~0, ~0);
+
+ return 0;
+}
+
+static void
+vt6102pci(void)
+{
+ Pcidev *p;
+ Ctlr *ctlr;
+ int cls, port;
+
+ p = nil;
+ while(p = pcimatch(p, 0, 0)){
+ if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
+ continue;
+
+ switch((p->did<<16)|p->vid){
+ default:
+ continue;
+ case (0x3065<<16)|0x1106: /* Rhine II */
+ case (0x3106<<16)|0x1106: /* Rhine III */
+ break;
+ }
+
+ port = p->mem[0].bar & ~0x01;
+ if(ioalloc(port, p->mem[0].size, 0, "vt6102") < 0){
+ print("vt6102: port 0x%uX in use\n", port);
+ continue;
+ }
+ ctlr = malloc(sizeof(Ctlr));
+ ctlr->port = port;
+ ctlr->pcidev = p;
+ ctlr->id = (p->did<<16)|p->vid;
+ if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
+ cls = 0x10;
+ ctlr->cls = cls*4;
+ if(ctlr->cls < sizeof(Ds)){
+ print("vt6102: cls %d < sizeof(Ds)\n", ctlr->cls);
+ iofree(port);
+ free(ctlr);
+ continue;
+ }
+ ctlr->tft = Ctft64;
+
+ if(vt6102reset(ctlr)){
+ iofree(port);
+ free(ctlr);
+ continue;
+ }
+ pcisetbme(p);
+
+ if(vt6102ctlrhead != nil)
+ vt6102ctlrtail->next = ctlr;
+ else
+ vt6102ctlrhead = ctlr;
+ vt6102ctlrtail = ctlr;
+ }
+}
+
+static int
+vt6102pnp(Ether* edev)
+{
+ Ctlr *ctlr;
+
+ if(vt6102ctlrhead == nil)
+ vt6102pci();
+
+ /*
+ * Any adapter matches if no edev->port is supplied,
+ * otherwise the ports must match.
+ */
+ for(ctlr = vt6102ctlrhead; ctlr != nil; ctlr = ctlr->next){
+ if(ctlr->active)
+ continue;
+ if(edev->port == 0 || edev->port == ctlr->port){
+ ctlr->active = 1;
+ break;
+ }
+ }
+ if(ctlr == nil)
+ return -1;
+
+ edev->ctlr = ctlr;
+ edev->port = ctlr->port;
+ edev->irq = ctlr->pcidev->intl;
+ edev->tbdf = ctlr->pcidev->tbdf;
+ edev->mbps = 100;
+ memmove(edev->ea, ctlr->par, Eaddrlen);
+
+ /*
+ * Linkage to the generic ethernet driver.
+ */
+ edev->attach = vt6102attach;
+ edev->transmit = vt6102transmit;
+ edev->interrupt = vt6102interrupt;
+ edev->ifstat = vt6102ifstat;
+ edev->ctl = nil;
+
+ edev->arg = edev;
+ edev->promiscuous = vt6102promiscuous;
+ edev->multicast = vt6102multicast;
+
+ return 0;
+}
+
+void
+ethervt6102link(void)
+{
+ addethercard("vt6102", vt6102pnp);
+ addethercard("rhine", vt6102pnp);
+}
diff --git a/os/pc/etherwavelan.c b/os/pc/etherwavelan.c
index 6fa9f250..e76905b5 100644
--- a/os/pc/etherwavelan.c
+++ b/os/pc/etherwavelan.c
@@ -87,6 +87,7 @@ static struct {
int did;
} wavelanpci[] = {
0x1260, 0x3873, /* Intersil Prism2.5 */
+ 0x1737, 0x0019, /* Linksys WPC-11 untested */
};
static Ctlr *ctlrhead, *ctlrtail;
@@ -95,7 +96,7 @@ static void
wavelanpciscan(void)
{
int i;
- ulong pa;
+ void *mem;
Pcidev *p;
Ctlr *ctlr;
@@ -117,13 +118,13 @@ wavelanpciscan(void)
ctlr = malloc(sizeof(Ctlr));
ctlr->pcidev = p;
- pa = upamalloc(p->mem[0].bar&~0xF, p->mem[0].size, 0);
- if(pa == 0){
- print("wavelanpci: %.4ux %.4ux: upamalloc 0x%.8lux %d failed\n", p->vid, p->did, p->mem[0].bar&~0xF, p->mem[0].size);
+ mem = vmap(p->mem[0].bar&~0xF, p->mem[0].size);
+ if(mem == nil){
+ print("wavelanpci: %.4ux %.4ux: vmap 0x%.8lux %d failed\n", p->vid, p->did, p->mem[0].bar&~0xF, p->mem[0].size);
free(ctlr);
continue;
}
- ctlr->mmb = (ushort*)KADDR(pa);
+ ctlr->mmb = mem;
if(ctlrhead != nil)
ctlrtail->next = ctlr;
else
diff --git a/os/pc/fns.h b/os/pc/fns.h
index 028162ac..d4b61034 100644
--- a/os/pc/fns.h
+++ b/os/pc/fns.h
@@ -104,6 +104,7 @@ void pcicfgw16(Pcidev*, int, int);
void pcicfgw32(Pcidev*, int, int);
void pciclrbme(Pcidev*);
void pciclrioe(Pcidev*);
+void pciclrmwi(Pcidev*);
int pcigetpms(Pcidev*);
void pcihinv(Pcidev*);
uchar pciipin(Pcidev*, uchar);
@@ -144,7 +145,10 @@ ulong umbrwmalloc(ulong, int, int);
void umbrwfree(ulong, int);
ulong upamalloc(ulong, int, int);
void upafree(ulong, int);
+void upareserve(ulong, int);
void vectortable(void);
+void* vmap(ulong, int);
+void vunmap(void*, int);
void wrmsr(ulong, ulong);
int xchgw(ushort*, int);
ulong kzeromap(ulong, ulong, int);
diff --git a/os/pc/i8253.c b/os/pc/i8253.c
index d7cff39e..0759088f 100644
--- a/os/pc/i8253.c
+++ b/os/pc/i8253.c
@@ -201,7 +201,7 @@ i8253timerset(uvlong next)
period = want - now;
if(period < MinPeriod)
period = MinPeriod;
- else if(period > (4*MaxPeriod)/5) /* strong attraction to MaxPeriod */
+ else if(period > MaxPeriod)
period = MaxPeriod;
}
diff --git a/os/pc/io.h b/os/pc/io.h
index cd35265e..2a89edee 100644
--- a/os/pc/io.h
+++ b/os/pc/io.h
@@ -95,7 +95,7 @@ enum {
/*
* PCI support code.
*/
-enum { /* type 0 and type 1 pre-defined header */
+enum { /* type 0 & type 1 pre-defined header */
PciVID = 0x00, /* vendor ID */
PciDID = 0x02, /* device ID */
PciPCR = 0x04, /* command */
@@ -116,6 +116,54 @@ enum { /* type 0 and type 1 pre-defined header */
PciINTP = 0x3D, /* interrupt pin */
};
+/* ccrb (base class code) values; controller types */
+enum {
+ Pcibcpci1 = 0, /* pci 1.0; no class codes defined */
+ Pcibcstore = 1, /* mass storage */
+ Pcibcnet = 2, /* network */
+ Pcibcdisp = 3, /* display */
+ Pcibcmmedia = 4, /* multimedia */
+ Pcibcmem = 5, /* memory */
+ Pcibcbridge = 6, /* bridge */
+ Pcibccomm = 7, /* simple comms (e.g., serial) */
+ Pcibcbasesys = 8, /* base system */
+ Pcibcinput = 9, /* input */
+ Pcibcdock = 0xa, /* docking stations */
+ Pcibcproc = 0xb, /* processors */
+ Pcibcserial = 0xc, /* serial bus (e.g., USB) */
+ Pcibcwireless = 0xd, /* wireless */
+ Pcibcintell = 0xe, /* intelligent i/o */
+ Pcibcsatcom = 0xf, /* satellite comms */
+ Pcibccrypto = 0x10, /* encryption/decryption */
+ Pcibcdacq = 0x11, /* data acquisition & signal proc. */
+};
+
+/* ccru (sub-class code) values; common cases only */
+enum {
+ /* mass storage */
+ Pciscscsi = 0, /* SCSI */
+ Pciscide = 1, /* IDE (ATA) */
+
+ /* network */
+ Pciscether = 0, /* Ethernet */
+
+ /* display */
+ Pciscvga = 0, /* VGA */
+ Pciscxga = 1, /* XGA */
+ Pcisc3d = 2, /* 3D */
+
+ /* bridges */
+ Pcischostpci = 0, /* host/pci */
+ Pciscpcicpci = 1, /* pci/pci */
+
+ /* simple comms */
+ Pciscserial = 0, /* 16450, etc. */
+ Pciscmultiser = 1, /* multiport serial */
+
+ /* serial bus */
+ Pciscusb = 3, /* USB */
+};
+
enum { /* type 0 pre-defined header */
PciCIS = 0x28, /* cardbus CIS pointer */
PciSVID = 0x2C, /* subsystem vendor ID */
diff --git a/os/pc/memory.c b/os/pc/memory.c
index a58119c6..85658248 100644
--- a/os/pc/memory.c
+++ b/os/pc/memory.c
@@ -568,3 +568,21 @@ upafree(ulong pa, int size)
{
mapfree(&xrmapupa, pa, size);
}
+
+void
+upareserve(ulong pa, int size)
+{
+ ulong a;
+
+ a = mapalloc(&rmapupa, pa, size, 0);
+ if(a != pa){
+ /*
+ * This can happen when we're using the E820
+ * map, which might have already reserved some
+ * of the regions claimed by the pci devices.
+ */
+ // print("upareserve: cannot reserve pa=%#.8lux size=%d\n", pa, size);
+ if(a != 0)
+ mapfree(&rmapupa, a, size);
+ }
+}
diff --git a/os/pc/mmu.c b/os/pc/mmu.c
index 6bd4ddfb..6a9e8089 100644
--- a/os/pc/mmu.c
+++ b/os/pc/mmu.c
@@ -319,3 +319,19 @@ mmukmap(ulong pa, ulong va, int size)
return pa;
}
+
+void*
+vmap(ulong pa, int size)
+{
+ pa = upamalloc(pa, size, 0);
+ if(pa == 0)
+ return nil;
+ return KADDR(pa);
+}
+
+void
+vunmap(void *va, int size)
+{
+ if(va != nil)
+ upafree(PADDR(va), size);
+}
diff --git a/os/pc/pci.c b/os/pc/pci.c
index 4f7e79b6..d35a306a 100644
--- a/os/pc/pci.c
+++ b/os/pc/pci.c
@@ -176,7 +176,6 @@ pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
int ntb, i, size, rno, hole;
ulong v, mema, ioa, sioa, smema, base, limit;
Pcisiz *table, *tptr, *mtb, *itb;
- extern void qsort(void*, long, long, int (*)(void*, void*));
if(!nobios)
return;
diff --git a/os/port/chan.c b/os/port/chan.c
index a5d213aa..c3a56b04 100644
--- a/os/port/chan.c
+++ b/os/port/chan.c
@@ -1297,25 +1297,25 @@ if(c->umh != nil){
c = cnew;
c->name = addelem(c->name, e.elems[e.nelems-1]);
break;
- }else{ /* create failed */
- cclose(cnew);
- if(m)
- putmhead(m);
- if(omode & OEXCL)
- nexterror();
- /* save error */
- createerr = up->env->errstr;
- up->env->errstr = tmperrbuf;
- /* note: we depend that walk does not error */
- if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){
- up->env->errstr = createerr;
- error(createerr); /* report true error */
- }
+ }
+
+ /* create failed */
+ cclose(cnew);
+ if(m)
+ putmhead(m);
+ if(omode & OEXCL)
+ nexterror();
+ /* save error */
+ createerr = up->env->errstr;
+ up->env->errstr = tmperrbuf;
+ /* note: we depend that walk does not error */
+ if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){
up->env->errstr = createerr;
- omode |= OTRUNC;
- goto Open;
+ error(createerr); /* report true error */
}
- panic("namec: not reached");
+ up->env->errstr = createerr;
+ omode |= OTRUNC;
+ goto Open;
default:
panic("unknown namec access %d\n", amode);
diff --git a/os/port/dev.c b/os/port/dev.c
index 4e91b8d0..d874ea14 100644
--- a/os/port/dev.c
+++ b/os/port/dev.c
@@ -258,8 +258,6 @@ devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen)
}
break;
}
- error(Egreg); /* not reached? */
- return -1;
}
long
diff --git a/os/port/ethermii.c b/os/port/ethermii.c
index 584cdf08..3a1e2368 100644
--- a/os/port/ethermii.c
+++ b/os/port/ethermii.c
@@ -177,13 +177,13 @@ miistatus(Mii* mii)
bmsr = mii->mir(mii, phyno, Bmsr);
if(!(bmsr & (BmsrAnc|BmsrAna)))
{
-print("miistatus 1\n");
+print("miistatus: auto-neg incomplete\n");
return -1;
}
bmsr = mii->mir(mii, phyno, Bmsr);
if(!(bmsr & BmsrLs)){
-print("miistatus 2\n");
+print("miistatus: link down\n");
phy->link = 0;
return -1;
}
@@ -217,7 +217,7 @@ print("miistatus 2\n");
}
if(phy->speed == 0)
{
-print("miistatus 3\n");
+print("miistatus: phy speed 0\n");
return -1;
}
diff --git a/os/port/lib.h b/os/port/lib.h
index c9414b5a..e50fd8cb 100644
--- a/os/port/lib.h
+++ b/os/port/lib.h
@@ -2,9 +2,9 @@
/*
* functions (possibly) linked in, complete, from libc.
*/
-#define nelem(n) (sizeof(n)/sizeof(n[0]))
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
#define offsetof(s, m) (ulong)(&(((s*)0)->m))
-#define assert(x) if(x){}else _assert("x")
+#define assert(x) if(x){}else _assert("x")
/*
* mem routines
@@ -123,6 +123,7 @@ extern char end[];
extern int getfields(char*, char**, int, int, char*);
extern int tokenize(char*, char**, int);
extern int dec64(uchar*, int, char*, int);
+extern void qsort(void*, long, long, int (*)(void*, void*));
extern int toupper(int);
extern char* netmkaddr(char*, char*, char*);