#include "all.h"
#include "io.h"
#include "mem.h"
#include "../ip/ip.h"
#include "etherif.h"
#define dprint(...) /* print(__VA_ARGS__) */
extern int etherga620reset(Ether*);
extern int ether21140reset(Ether*);
extern int etherelnk3reset(Ether*);
extern int etheri82557reset(Ether*);
extern int igbepnp(Ether *);
extern int i82563reset(Ether *);
extern int dp83815reset(Ether*);
extern int dp83820pnp(Ether*);
extern int rtl8139pnp(Ether*);
extern int rtl8169pnp(Ether*);
extern int ether79c970reset(Ether*);
static struct
{
char* type;
int (*reset)(Ether*);
} etherctlr[] =
{
{ "21140", ether21140reset, },
{ "2114x", ether21140reset, },
{ "3C509", etherelnk3reset, },
{ "83815", dp83815reset, },
{ "dp83820", dp83820pnp, },
{ "elnk3", etherelnk3reset, },
{ "ga620", etherga620reset, },
{ "i82557", etheri82557reset, },
{ "igbe", igbepnp, },
{ "i82563", i82563reset, },
{ "rtl8139", rtl8139pnp, },
{ "rtl8169", rtl8169pnp, },
{ "AMD79C970", ether79c970reset, },
{ 0, },
};
static Ether etherif[MaxEther];
void
etheriq(Ether* ether, Msgbuf* mb)
{
ilock(ðer->rqlock);
if(ether->rqhead)
ether->rqtail->next = mb;
else
ether->rqhead = mb;
ether->rqtail = mb;
mb->next = 0;
iunlock(ðer->rqlock);
wakeup(ðer->rqr);
}
static int
isinput(void* arg)
{
return ((Ether*)arg)->rqhead != 0;
}
#include "compat.h"
static void
etheri(void)
{
Ether *ether;
Ifc *ifc;
Msgbuf *mb;
Enpkt *p;
ether = getarg();
ifc = ðer->ifc;
print("ether%di: %E %I\n", ether->ctlrno, ether->ifc.ea, ether->ifc.ipa);
(*ether->attach)(ether);
for(;;) {
while(!isinput(ether))
sleep(ðer->rqr, isinput, ether);
ilock(ðer->rqlock);
if(ether->rqhead == 0) {
iunlock(ðer->rqlock);
continue;
}
mb = ether->rqhead;
ether->rqhead = mb->next;
iunlock(ðer->rqlock);
p = (Enpkt*)mb->data;
switch(nhgets(p->type)){
case Arptype:
arpreceive(p, mb->count, ifc);
break;
case Iptype:
ipreceive(p, mb->count, ifc);
ifc->rxpkt++;
ifc->work[0].count++;
ifc->work[1].count++;
ifc->work[2].count++;
ifc->rate[0].count += mb->count;
ifc->rate[1].count += mb->count;
ifc->rate[2].count += mb->count;
break;
}
mbfree(mb);
}
}
static void
ethero(void)
{
Ether *ether;
Ifc *ifc;
Msgbuf *mb;
int len;
ether = getarg();
ifc = ðer->ifc;
print("ether%do: %E %I\n", ether->ctlrno, ifc->ea, ifc->ipa);
for(;;) {
for(;;) {
mb = recv(ifc->reply, 0);
if(mb != nil)
break;
}
if(mb->data == 0) {
print("ether%do: pkt nil cat=%d free=%d\n",
ether->ctlrno, mb->category, mb->flags&FREE);
if(!(mb->flags & FREE))
mbfree(mb);
continue;
}
len = mb->count;
if(len > ETHERMAXTU) {
print("ether%do: pkt too big - %d\n", ether->ctlrno, len);
mbfree(mb);
continue;
}
if(len < ETHERMINTU) {
memset(mb->data+len, 0, ETHERMINTU-len);
mb->count = len = ETHERMINTU;
}
memmove(((Enpkt*)(mb->data))->s, ifc->ea, sizeof(ifc->ea));
ilock(ðer->tqlock);
if(ether->tqhead)
ether->tqtail->next = mb;
else
ether->tqhead = mb;
ether->tqtail = mb;
mb->next = 0;
iunlock(ðer->tqlock);
(*ether->transmit)(ether);
ifc->work[0].count++;
ifc->work[1].count++;
ifc->work[2].count++;
ifc->rate[0].count += len;
ifc->rate[1].count += len;
ifc->rate[2].count += len;
ifc->txpkt++;
}
}
Msgbuf*
etheroq(Ether* ether)
{
Msgbuf *mb;
mb = nil;
ilock(ðer->tqlock);
if(ether->tqhead){
mb = ether->tqhead;
ether->tqhead = mb->next;
}
iunlock(ðer->tqlock);
return mb;
}
static void
cmd_state(int, char*[])
{
Ether *ether;
Ifc *ifc;
for(ether = ðerif[0]; ether < ðerif[MaxEther]; ether++){
if(ether->mbps == 0)
continue;
ifc = ðer->ifc;
if(!isvalidip(ifc->ipa))
continue;
print("ether stats %d\n", ether->ctlrno);
print(" work =%7W%7W%7W pkts\n", ifc->work+0, ifc->work+1, ifc->work+2);
print(" rate =%7W%7W%7W tBps\n", ifc->rate+0, ifc->rate+1, ifc->rate+2);
print(" err = %3ld rc %3ld sum\n", ifc->rcverr, ifc->sumerr);
}
}
void
etherstart(void)
{
Ether *ether;
Ifc *ifc;
int anystarted;
char buf[100], *p;
anystarted = 0;
for(ether = ðerif[0]; ether < ðerif[MaxEther]; ether++){
if(ether->mbps == 0)
continue;
ifc = ðer->ifc;
lock(ifc);
getipa(ifc, ether->ctlrno);
if(!isvalidip(ifc->ipa)){
unlock(ifc);
ether->mbps = 0;
continue;
}
if(ifc->reply == 0){
dofilter(ifc->work+0, C0a, C0b, 1);
dofilter(ifc->work+1, C1a, C1b, 1);
dofilter(ifc->work+2, C2a, C2b, 1);
dofilter(ifc->rate+0, C0a, C0b, 1000);
dofilter(ifc->rate+1, C1a, C1b, 1000);
dofilter(ifc->rate+2, C2a, C2b, 1000);
ifc->reply = newqueue(Nqueue);
}
unlock(ifc);
sprint(ether->oname, "ether%do", ether->ctlrno);
userinit(ethero, ether, ether->oname);
sprint(ether->iname, "ether%di", ether->ctlrno);
userinit(etheri, ether, ether->iname);
ifc->next = enets;
enets = ifc;
anystarted++;
}
if(anystarted){
cmd_install("state", "-- ether stats", cmd_state);
arpstart();
if((p = getconf("route")) && strlen(p) < sizeof(buf)-7){
sprint(buf, "route %s", p);
cmd_exec(buf);
}
}
}
static int
parseether(uchar *to, char *from)
{
char nip[4];
char *p;
int i;
p = from;
while(*p == ' ')
++p;
for(i = 0; i < 6; i++){
if(*p == 0)
return -1;
nip[0] = *p++;
if(*p == 0)
return -1;
nip[1] = *p++;
nip[2] = 0;
to[i] = strtoul(nip, 0, 16);
if(*p == ':')
p++;
}
return 0;
}
void
etherinit(void)
{
Ether *ether;
int i, n, ctlrno;
for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
ether = ðerif[ctlrno];
memset(ether, 0, sizeof(Ether));
if(!isaconfig("ether", ctlrno, ether))
continue;
for(n = 0; etherctlr[n].type; n++){
if(cistrcmp(etherctlr[n].type, ether->type))
continue;
dprint("FOUND ether %s\n", etherctlr[n].type);
ether->ctlrno = ctlrno;
ether->tbdf = BUSUNKNOWN;
for(i = 0; i < ether->nopt; i++){
if(strncmp(ether->opt[i], "ea=", 3))
continue;
if(parseether(ether->ea, ðer->opt[i][3]) == -1)
memset(ether->ea, 0, Easize);
}
dprint(" reset ... ");
if((*etherctlr[n].reset)(ether)){
dprint("fail\n");
break;
}
dprint("okay\n");
if(ether->irq == 2)
ether->irq = 9;
setvec(Int0vec + ether->irq, ether->interrupt, ether);
memmove(ether->ifc.ea, ether->ea, sizeof(ether->ea));
print("ether%d: %s: %dMbps port 0x%lux irq %ld",
ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
if(ether->mem)
print(" addr 0x%lux", ether->mem & ~KZERO);
if(ether->size)
print(" size 0x%lux", ether->size);
print(": ");
for(i = 0; i < sizeof(ether->ea); i++)
print("%2.2ux", ether->ea[i]);
print("\n");
break;
}
}
}
|