xref: /inferno-os/os/boot/pc/ether.c (revision 8a8c2d742b51525f66c2210e3c8a251de10022ff)
174a4d8c2SCharles.Forsyth #include "u.h"
274a4d8c2SCharles.Forsyth #include "lib.h"
374a4d8c2SCharles.Forsyth #include "mem.h"
474a4d8c2SCharles.Forsyth #include "dat.h"
574a4d8c2SCharles.Forsyth #include "fns.h"
674a4d8c2SCharles.Forsyth #include "io.h"
774a4d8c2SCharles.Forsyth #include "ip.h"
874a4d8c2SCharles.Forsyth 
974a4d8c2SCharles.Forsyth #include "etherif.h"
1074a4d8c2SCharles.Forsyth 
1174a4d8c2SCharles.Forsyth static Ether ether[MaxEther];
1274a4d8c2SCharles.Forsyth 
1374a4d8c2SCharles.Forsyth extern int ether2114xreset(Ether*);
1474a4d8c2SCharles.Forsyth extern int elnk3reset(Ether*);
1574a4d8c2SCharles.Forsyth extern int i82557reset(Ether*);
1674a4d8c2SCharles.Forsyth extern int igbepnp(Ether *);
17*8a8c2d74SCharles.Forsyth extern int i82563pnp(Ether *);
1874a4d8c2SCharles.Forsyth extern int elnk3reset(Ether*);
1974a4d8c2SCharles.Forsyth extern int ether589reset(Ether*);
2074a4d8c2SCharles.Forsyth extern int ne2000reset(Ether*);
2174a4d8c2SCharles.Forsyth extern int wd8003reset(Ether*);
2274a4d8c2SCharles.Forsyth extern int ec2treset(Ether*);
2374a4d8c2SCharles.Forsyth extern int amd79c970reset(Ether*);
2474a4d8c2SCharles.Forsyth extern int rtl8139pnp(Ether*);
2574a4d8c2SCharles.Forsyth extern int rtl8169pnp(Ether*);
2674a4d8c2SCharles.Forsyth extern int ether83815reset(Ether*);
2774a4d8c2SCharles.Forsyth extern int rhinepnp(Ether*);
28*8a8c2d74SCharles.Forsyth extern int ga620pnp(Ether*);
29*8a8c2d74SCharles.Forsyth extern int dp83820pnp(Ether*);
3074a4d8c2SCharles.Forsyth 
3174a4d8c2SCharles.Forsyth struct {
3274a4d8c2SCharles.Forsyth 	char	*type;
3374a4d8c2SCharles.Forsyth 	int	(*reset)(Ether*);
3474a4d8c2SCharles.Forsyth 	int	noprobe;
3574a4d8c2SCharles.Forsyth } ethercards[] = {
3674a4d8c2SCharles.Forsyth 	{ "21140", ether2114xreset, 0, },
3774a4d8c2SCharles.Forsyth 	{ "2114x", ether2114xreset, 0, },
3874a4d8c2SCharles.Forsyth 	{ "i82557", i82557reset, 0, },
3974a4d8c2SCharles.Forsyth 	{ "igbe",  igbepnp, 0, },
40*8a8c2d74SCharles.Forsyth 	{ "i82563",i82563pnp, 0, },
41*8a8c2d74SCharles.Forsyth 	{ "igbepcie",i82563pnp, 0, },
4274a4d8c2SCharles.Forsyth 	{ "elnk3", elnk3reset, 0, },
4374a4d8c2SCharles.Forsyth 	{ "3C509", elnk3reset, 0, },
4474a4d8c2SCharles.Forsyth 	{ "3C575", elnk3reset, 0, },
4574a4d8c2SCharles.Forsyth 	{ "3C589", ether589reset, 1, },
4674a4d8c2SCharles.Forsyth 	{ "3C562", ether589reset, 1, },
4774a4d8c2SCharles.Forsyth 	{ "589E", ether589reset, 1, },
4874a4d8c2SCharles.Forsyth 	{ "NE2000", ne2000reset, 0, },
4974a4d8c2SCharles.Forsyth 	{ "WD8003", wd8003reset, 1, },
5074a4d8c2SCharles.Forsyth 	{ "EC2T", ec2treset, 0, },
5174a4d8c2SCharles.Forsyth 	{ "AMD79C970", amd79c970reset, 0, },
5274a4d8c2SCharles.Forsyth 	{ "RTL8139", rtl8139pnp, 0, },
5374a4d8c2SCharles.Forsyth 	{ "RTL8169", rtl8169pnp, 0, },
5474a4d8c2SCharles.Forsyth 	{ "83815", ether83815reset, 0, },
5574a4d8c2SCharles.Forsyth 	{ "rhine", rhinepnp, 0, },
56*8a8c2d74SCharles.Forsyth 	{ "vt6102", rhinepnp, 0, },
57*8a8c2d74SCharles.Forsyth 	{ "GA620", ga620pnp, 0, },
58*8a8c2d74SCharles.Forsyth 	{ "83820",   dp83820pnp, 0, },
59*8a8c2d74SCharles.Forsyth 	{ "dp83820", dp83820pnp, 0, },
6074a4d8c2SCharles.Forsyth 
6174a4d8c2SCharles.Forsyth 	{ 0, }
6274a4d8c2SCharles.Forsyth };
6374a4d8c2SCharles.Forsyth 
6474a4d8c2SCharles.Forsyth static void xetherdetach(void);
6574a4d8c2SCharles.Forsyth 
6674a4d8c2SCharles.Forsyth int
etherinit(void)6774a4d8c2SCharles.Forsyth etherinit(void)
6874a4d8c2SCharles.Forsyth {
6974a4d8c2SCharles.Forsyth 	Ether *ctlr;
7074a4d8c2SCharles.Forsyth 	int ctlrno, i, mask, n, x;
7174a4d8c2SCharles.Forsyth 
7274a4d8c2SCharles.Forsyth 	fmtinstall('E', eipfmt);
7374a4d8c2SCharles.Forsyth 
7474a4d8c2SCharles.Forsyth 	etherdetach = xetherdetach;
7574a4d8c2SCharles.Forsyth 	mask = 0;
7674a4d8c2SCharles.Forsyth 	for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
7774a4d8c2SCharles.Forsyth 		ctlr = &ether[ctlrno];
7874a4d8c2SCharles.Forsyth 		memset(ctlr, 0, sizeof(Ether));
7974a4d8c2SCharles.Forsyth 		if(iniread && isaconfig("ether", ctlrno, ctlr) == 0)
8074a4d8c2SCharles.Forsyth 			continue;
8174a4d8c2SCharles.Forsyth 
8274a4d8c2SCharles.Forsyth 		for(n = 0; ethercards[n].type; n++){
8374a4d8c2SCharles.Forsyth 			if(!iniread){
8474a4d8c2SCharles.Forsyth 				if(ethercards[n].noprobe)
8574a4d8c2SCharles.Forsyth 					continue;
8674a4d8c2SCharles.Forsyth 				memset(ctlr, 0, sizeof(Ether));
8774a4d8c2SCharles.Forsyth 				strcpy(ctlr->type, ethercards[n].type);
8874a4d8c2SCharles.Forsyth 			}
8974a4d8c2SCharles.Forsyth 			else if(cistrcmp(ethercards[n].type, ctlr->type))
9074a4d8c2SCharles.Forsyth 				continue;
9174a4d8c2SCharles.Forsyth 			ctlr->ctlrno = ctlrno;
9274a4d8c2SCharles.Forsyth 
9374a4d8c2SCharles.Forsyth 			x = splhi();
9474a4d8c2SCharles.Forsyth 			if((*ethercards[n].reset)(ctlr)){
9574a4d8c2SCharles.Forsyth 				splx(x);
9674a4d8c2SCharles.Forsyth 				if(iniread)
9774a4d8c2SCharles.Forsyth 					break;
9874a4d8c2SCharles.Forsyth 				else
9974a4d8c2SCharles.Forsyth 					continue;
10074a4d8c2SCharles.Forsyth 			}
10174a4d8c2SCharles.Forsyth 
102*8a8c2d74SCharles.Forsyth 			ctlr->state = 1;		/* card found */
10374a4d8c2SCharles.Forsyth 			mask |= 1<<ctlrno;
10474a4d8c2SCharles.Forsyth 			if(ctlr->irq == 2)
10574a4d8c2SCharles.Forsyth 				ctlr->irq = 9;
10674a4d8c2SCharles.Forsyth 			setvec(VectorPIC + ctlr->irq, ctlr->interrupt, ctlr);
10774a4d8c2SCharles.Forsyth 
10874a4d8c2SCharles.Forsyth 			print("ether#%d: %s: port 0x%luX irq %lud",
10974a4d8c2SCharles.Forsyth 				ctlr->ctlrno, ctlr->type, ctlr->port, ctlr->irq);
11074a4d8c2SCharles.Forsyth 			if(ctlr->mem)
11174a4d8c2SCharles.Forsyth 				print(" addr 0x%luX", ctlr->mem & ~KZERO);
11274a4d8c2SCharles.Forsyth 			if(ctlr->size)
11374a4d8c2SCharles.Forsyth 				print(" size 0x%luX", ctlr->size);
11474a4d8c2SCharles.Forsyth 			print(": %E\n", ctlr->ea);
11574a4d8c2SCharles.Forsyth 
11674a4d8c2SCharles.Forsyth 			if(ctlr->nrb == 0)
11774a4d8c2SCharles.Forsyth 				ctlr->nrb = Nrb;
11874a4d8c2SCharles.Forsyth 			ctlr->rb = ialloc(sizeof(RingBuf)*ctlr->nrb, 0);
11974a4d8c2SCharles.Forsyth 			if(ctlr->ntb == 0)
12074a4d8c2SCharles.Forsyth 				ctlr->ntb = Ntb;
12174a4d8c2SCharles.Forsyth 			ctlr->tb = ialloc(sizeof(RingBuf)*ctlr->ntb, 0);
12274a4d8c2SCharles.Forsyth 
12374a4d8c2SCharles.Forsyth 			ctlr->rh = 0;
12474a4d8c2SCharles.Forsyth 			ctlr->ri = 0;
12574a4d8c2SCharles.Forsyth 			for(i = 0; i < ctlr->nrb; i++)
12674a4d8c2SCharles.Forsyth 				ctlr->rb[i].owner = Interface;
12774a4d8c2SCharles.Forsyth 
12874a4d8c2SCharles.Forsyth 			ctlr->th = 0;
12974a4d8c2SCharles.Forsyth 			ctlr->ti = 0;
13074a4d8c2SCharles.Forsyth 			for(i = 0; i < ctlr->ntb; i++)
13174a4d8c2SCharles.Forsyth 				ctlr->tb[i].owner = Host;
13274a4d8c2SCharles.Forsyth 
13374a4d8c2SCharles.Forsyth 			splx(x);
13474a4d8c2SCharles.Forsyth 			break;
13574a4d8c2SCharles.Forsyth 		}
13674a4d8c2SCharles.Forsyth 	}
13774a4d8c2SCharles.Forsyth 
13874a4d8c2SCharles.Forsyth 	return mask;
13974a4d8c2SCharles.Forsyth }
14074a4d8c2SCharles.Forsyth 
14174a4d8c2SCharles.Forsyth void
etherinitdev(int i,char * s)14274a4d8c2SCharles.Forsyth etherinitdev(int i, char *s)
14374a4d8c2SCharles.Forsyth {
14474a4d8c2SCharles.Forsyth 	sprint(s, "ether%d", i);
14574a4d8c2SCharles.Forsyth }
14674a4d8c2SCharles.Forsyth 
14774a4d8c2SCharles.Forsyth void
etherprintdevs(int i)14874a4d8c2SCharles.Forsyth etherprintdevs(int i)
14974a4d8c2SCharles.Forsyth {
15074a4d8c2SCharles.Forsyth 	print(" ether%d", i);
15174a4d8c2SCharles.Forsyth }
15274a4d8c2SCharles.Forsyth 
15374a4d8c2SCharles.Forsyth static Ether*
attach(int ctlrno)15474a4d8c2SCharles.Forsyth attach(int ctlrno)
15574a4d8c2SCharles.Forsyth {
15674a4d8c2SCharles.Forsyth 	Ether *ctlr;
15774a4d8c2SCharles.Forsyth 
15874a4d8c2SCharles.Forsyth 	if(ctlrno >= MaxEther || ether[ctlrno].state == 0)
15974a4d8c2SCharles.Forsyth 		return 0;
16074a4d8c2SCharles.Forsyth 
16174a4d8c2SCharles.Forsyth 	ctlr = &ether[ctlrno];
162*8a8c2d74SCharles.Forsyth 	if(ctlr->state == 1){		/* card found? */
163*8a8c2d74SCharles.Forsyth 		ctlr->state = 2;	/* attaching */
16474a4d8c2SCharles.Forsyth 		(*ctlr->attach)(ctlr);
16574a4d8c2SCharles.Forsyth 	}
16674a4d8c2SCharles.Forsyth 
16774a4d8c2SCharles.Forsyth 	return ctlr;
16874a4d8c2SCharles.Forsyth }
16974a4d8c2SCharles.Forsyth 
17074a4d8c2SCharles.Forsyth static void
xetherdetach(void)17174a4d8c2SCharles.Forsyth xetherdetach(void)
17274a4d8c2SCharles.Forsyth {
17374a4d8c2SCharles.Forsyth 	Ether *ctlr;
17474a4d8c2SCharles.Forsyth 	int ctlrno, x;
17574a4d8c2SCharles.Forsyth 
17674a4d8c2SCharles.Forsyth 	x = splhi();
17774a4d8c2SCharles.Forsyth 	for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
17874a4d8c2SCharles.Forsyth 		ctlr = &ether[ctlrno];
179*8a8c2d74SCharles.Forsyth 		if(ctlr->detach && ctlr->state != 0)	/* found | attaching? */
18074a4d8c2SCharles.Forsyth 			ctlr->detach(ctlr);
18174a4d8c2SCharles.Forsyth 	}
18274a4d8c2SCharles.Forsyth 	splx(x);
18374a4d8c2SCharles.Forsyth }
18474a4d8c2SCharles.Forsyth 
18574a4d8c2SCharles.Forsyth uchar*
etheraddr(int ctlrno)18674a4d8c2SCharles.Forsyth etheraddr(int ctlrno)
18774a4d8c2SCharles.Forsyth {
18874a4d8c2SCharles.Forsyth 	Ether *ctlr;
18974a4d8c2SCharles.Forsyth 
19074a4d8c2SCharles.Forsyth 	if((ctlr = attach(ctlrno)) == 0)
19174a4d8c2SCharles.Forsyth 		return 0;
19274a4d8c2SCharles.Forsyth 
19374a4d8c2SCharles.Forsyth 	return ctlr->ea;
19474a4d8c2SCharles.Forsyth }
19574a4d8c2SCharles.Forsyth 
19674a4d8c2SCharles.Forsyth static int
wait(RingBuf * ring,uchar owner,int timo)19774a4d8c2SCharles.Forsyth wait(RingBuf* ring, uchar owner, int timo)
19874a4d8c2SCharles.Forsyth {
19974a4d8c2SCharles.Forsyth 	ulong start;
20074a4d8c2SCharles.Forsyth 
20174a4d8c2SCharles.Forsyth 	start = m->ticks;
20274a4d8c2SCharles.Forsyth 	while(TK2MS(m->ticks - start) < timo){
20374a4d8c2SCharles.Forsyth 		if(ring->owner != owner)
20474a4d8c2SCharles.Forsyth 			return 1;
20574a4d8c2SCharles.Forsyth 	}
20674a4d8c2SCharles.Forsyth 
20774a4d8c2SCharles.Forsyth 	return 0;
20874a4d8c2SCharles.Forsyth }
20974a4d8c2SCharles.Forsyth 
21074a4d8c2SCharles.Forsyth int
etherrxpkt(int ctlrno,Etherpkt * pkt,int timo)21174a4d8c2SCharles.Forsyth etherrxpkt(int ctlrno, Etherpkt* pkt, int timo)
21274a4d8c2SCharles.Forsyth {
21374a4d8c2SCharles.Forsyth 	int n;
21474a4d8c2SCharles.Forsyth 	Ether *ctlr;
21574a4d8c2SCharles.Forsyth 	RingBuf *ring;
21674a4d8c2SCharles.Forsyth 
21774a4d8c2SCharles.Forsyth 	if((ctlr = attach(ctlrno)) == 0)
21874a4d8c2SCharles.Forsyth 		return 0;
21974a4d8c2SCharles.Forsyth 
22074a4d8c2SCharles.Forsyth 	ring = &ctlr->rb[ctlr->rh];
22174a4d8c2SCharles.Forsyth 	if(wait(ring, Interface, timo) == 0){
22274a4d8c2SCharles.Forsyth 		if(debug)
22374a4d8c2SCharles.Forsyth 			print("ether%d: rx timeout\n", ctlrno);
22474a4d8c2SCharles.Forsyth 		return 0;
22574a4d8c2SCharles.Forsyth 	}
22674a4d8c2SCharles.Forsyth 
22774a4d8c2SCharles.Forsyth 	n = ring->len;
22874a4d8c2SCharles.Forsyth 	memmove(pkt, ring->pkt, n);
22974a4d8c2SCharles.Forsyth 	ring->owner = Interface;
23074a4d8c2SCharles.Forsyth 	ctlr->rh = NEXT(ctlr->rh, ctlr->nrb);
23174a4d8c2SCharles.Forsyth 
23274a4d8c2SCharles.Forsyth 	return n;
23374a4d8c2SCharles.Forsyth }
23474a4d8c2SCharles.Forsyth 
23574a4d8c2SCharles.Forsyth int
etherrxflush(int ctlrno)23674a4d8c2SCharles.Forsyth etherrxflush(int ctlrno)
23774a4d8c2SCharles.Forsyth {
23874a4d8c2SCharles.Forsyth 	int n;
23974a4d8c2SCharles.Forsyth 	Ether *ctlr;
24074a4d8c2SCharles.Forsyth 	RingBuf *ring;
24174a4d8c2SCharles.Forsyth 
24274a4d8c2SCharles.Forsyth 	if((ctlr = attach(ctlrno)) == 0)
24374a4d8c2SCharles.Forsyth 		return 0;
24474a4d8c2SCharles.Forsyth 
24574a4d8c2SCharles.Forsyth 	n = 0;
24674a4d8c2SCharles.Forsyth 	for(;;){
24774a4d8c2SCharles.Forsyth 		ring = &ctlr->rb[ctlr->rh];
24874a4d8c2SCharles.Forsyth 		if(wait(ring, Interface, 100) == 0)
24974a4d8c2SCharles.Forsyth 			break;
25074a4d8c2SCharles.Forsyth 
25174a4d8c2SCharles.Forsyth 		ring->owner = Interface;
25274a4d8c2SCharles.Forsyth 		ctlr->rh = NEXT(ctlr->rh, ctlr->nrb);
25374a4d8c2SCharles.Forsyth 		n++;
25474a4d8c2SCharles.Forsyth 	}
25574a4d8c2SCharles.Forsyth 
25674a4d8c2SCharles.Forsyth 	return n;
25774a4d8c2SCharles.Forsyth }
25874a4d8c2SCharles.Forsyth 
25974a4d8c2SCharles.Forsyth int
ethertxpkt(int ctlrno,Etherpkt * pkt,int len,int)26074a4d8c2SCharles.Forsyth ethertxpkt(int ctlrno, Etherpkt* pkt, int len, int)
26174a4d8c2SCharles.Forsyth {
26274a4d8c2SCharles.Forsyth 	Ether *ctlr;
26374a4d8c2SCharles.Forsyth 	RingBuf *ring;
26474a4d8c2SCharles.Forsyth 	int s;
26574a4d8c2SCharles.Forsyth 
26674a4d8c2SCharles.Forsyth 	if((ctlr = attach(ctlrno)) == 0)
26774a4d8c2SCharles.Forsyth 		return 0;
26874a4d8c2SCharles.Forsyth 
26974a4d8c2SCharles.Forsyth 	ring = &ctlr->tb[ctlr->th];
27074a4d8c2SCharles.Forsyth 	if(wait(ring, Interface, 1000) == 0){
27174a4d8c2SCharles.Forsyth 		print("ether%d: tx buffer timeout\n", ctlrno);
27274a4d8c2SCharles.Forsyth 		return 0;
27374a4d8c2SCharles.Forsyth 	}
27474a4d8c2SCharles.Forsyth 
27574a4d8c2SCharles.Forsyth 	memmove(pkt->s, ctlr->ea, Eaddrlen);
27674a4d8c2SCharles.Forsyth 	if(debug)
27774a4d8c2SCharles.Forsyth 		print("%E to %E...\n", pkt->s, pkt->d);
27874a4d8c2SCharles.Forsyth 	memmove(ring->pkt, pkt, len);
27974a4d8c2SCharles.Forsyth 	if(len < ETHERMINTU){
28074a4d8c2SCharles.Forsyth 		memset(ring->pkt+len, 0, ETHERMINTU-len);
28174a4d8c2SCharles.Forsyth 		len = ETHERMINTU;
28274a4d8c2SCharles.Forsyth 	}
28374a4d8c2SCharles.Forsyth 	ring->len = len;
28474a4d8c2SCharles.Forsyth 	ring->owner = Interface;
28574a4d8c2SCharles.Forsyth 	ctlr->th = NEXT(ctlr->th, ctlr->ntb);
28674a4d8c2SCharles.Forsyth 	s = splhi();
28774a4d8c2SCharles.Forsyth 	(*ctlr->transmit)(ctlr);
28874a4d8c2SCharles.Forsyth 	splx(s);
28974a4d8c2SCharles.Forsyth 
29074a4d8c2SCharles.Forsyth 	return 1;
29174a4d8c2SCharles.Forsyth }
292