xref: /plan9/sys/src/9/ppc/ethersaturn.c (revision 5d9de2d38d2503efca29e12e0e32036368a7a75f)
1458db832SDavid du Colombier #include "u.h"
2458db832SDavid du Colombier #include "../port/lib.h"
3458db832SDavid du Colombier #include "mem.h"
4458db832SDavid du Colombier #include "dat.h"
5458db832SDavid du Colombier #include "fns.h"
6458db832SDavid du Colombier #include "io.h"
7458db832SDavid du Colombier #include "../port/error.h"
8458db832SDavid du Colombier #include "../port/netif.h"
9458db832SDavid du Colombier #include "msaturn.h"
10458db832SDavid du Colombier 
11458db832SDavid du Colombier #include "etherif.h"
12458db832SDavid du Colombier 
13458db832SDavid du Colombier enum{
14458db832SDavid du Colombier 	Etcr = Saturn + 0x0c00,
15458db832SDavid du Colombier 	Etsr = Saturn + 0x0c02,
16458db832SDavid du Colombier 	Ercr = Saturn + 0x0c04,
17458db832SDavid du Colombier 	Ersr = Saturn + 0x0c06,
18458db832SDavid du Colombier 	Eisr = Saturn + 0x0d04,
19458db832SDavid du Colombier 	Eimr = Saturn + 0x0d06,
20458db832SDavid du Colombier 	Emacaddr0 = Saturn + 0x0e02,
21458db832SDavid du Colombier 	Miicr = Saturn + 0x0f02,
22458db832SDavid du Colombier 	Miiwdr = Saturn + 0x0f04,
23458db832SDavid du Colombier 	Miirdr = Saturn + 0x0f06,
24458db832SDavid du Colombier 
25458db832SDavid du Colombier 	Ethermem = 0xf2c00000,
26458db832SDavid du Colombier 	Etherfsize = 0x2000,
27458db832SDavid du Colombier 	Nrx = 14,
28458db832SDavid du Colombier 	Ntx = 2,		// Nrx + Ntx must be 16
29458db832SDavid du Colombier 
30458db832SDavid du Colombier 	Ersr_rxfpmask = 0xf,
31458db832SDavid du Colombier 	Ersr_rxevent = RBIT(0, ushort),
32458db832SDavid du Colombier 	Etcr_txfpmask = 0xf,
33458db832SDavid du Colombier 	Ercr_rxenab = RBIT(0, ushort),
34458db832SDavid du Colombier 	Ercr_auienab = RBIT(2, ushort),
35458db832SDavid du Colombier 	Etcr_txstart = RBIT(1, ushort),
36458db832SDavid du Colombier 	Etcr_retries = 0xf<<8,
37458db832SDavid du Colombier 	Ei_txecall = RBIT(0, ushort),
38458db832SDavid du Colombier 	Ei_txretry = RBIT(2, ushort),
39458db832SDavid du Colombier 	Ei_txdefer = RBIT(3, ushort),
40458db832SDavid du Colombier 	Ei_txcrs = RBIT(4, ushort),
41458db832SDavid du Colombier 	Ei_txdone = RBIT(5, ushort),
42458db832SDavid du Colombier 	Ei_rxcrcerr = RBIT(8, ushort),
43458db832SDavid du Colombier 	Ei_rxdrib = RBIT(9, ushort),
44458db832SDavid du Colombier 	Ei_rxdone = RBIT(10, ushort),
45458db832SDavid du Colombier 	Ei_rxshort = RBIT(11, ushort),
46458db832SDavid du Colombier 	Ei_rxlong = RBIT(12, ushort),
47458db832SDavid du Colombier 
48458db832SDavid du Colombier 	Miicr_regshift = 6,
49458db832SDavid du Colombier 	Miicr_read = RBIT(10, ushort),
50458db832SDavid du Colombier 	Miicr_preambledis = RBIT(12, ushort),
51458db832SDavid du Colombier 	Miicr_accack = RBIT(14, ushort),
52458db832SDavid du Colombier 	Miicr_accbsy = RBIT(15, ushort),
53458db832SDavid du Colombier };
54458db832SDavid du Colombier 
55458db832SDavid du Colombier typedef struct {
56458db832SDavid du Colombier 	Lock;
57458db832SDavid du Colombier 	int		txbusy;
58458db832SDavid du Colombier 	int		txempty;
59458db832SDavid du Colombier 	int		txfull;
60458db832SDavid du Colombier 	int		ntx;			/* number of entries in transmit ring */
61458db832SDavid du Colombier 	int		rxlast;
62458db832SDavid du Colombier 
63458db832SDavid du Colombier 	int		active;
64458db832SDavid du Colombier 	ulong	interrupts;	/* statistics */
65458db832SDavid du Colombier 	ulong	overflows;
66458db832SDavid du Colombier } Ctlr;
67458db832SDavid du Colombier 
68*5d9de2d3SDavid du Colombier uchar etheraddr[6] = { 0x90, 0x85, 0x82, 0x32, 0x83, 0x00};
69458db832SDavid du Colombier static ushort*etcr=(ushort*)Etcr;
70458db832SDavid du Colombier static ushort*etsr=(ushort*)Etsr;
71458db832SDavid du Colombier static ushort*ercr=(ushort*)Ercr;
72458db832SDavid du Colombier static ushort*ersr=(ushort*)Ersr;
73458db832SDavid du Colombier static ushort*eimr=(ushort*)Eimr;
74458db832SDavid du Colombier static ushort*eisr=(ushort*)Eisr;
75458db832SDavid du Colombier static ushort*miicr=(ushort*)Miicr;
76458db832SDavid du Colombier static ushort*miirdr=(ushort*)Miirdr;
77458db832SDavid du Colombier 
78458db832SDavid du Colombier static void
txfill(Ether * ether,Ctlr * ctlr)79458db832SDavid du Colombier txfill(Ether*ether, Ctlr*ctlr)
80458db832SDavid du Colombier {
81458db832SDavid du Colombier 	int len;
82458db832SDavid du Colombier 	Block *b;
83458db832SDavid du Colombier 	ushort*dst;
84458db832SDavid du Colombier 
85458db832SDavid du Colombier 	while(ctlr->ntx<Ntx){
86458db832SDavid du Colombier 		if((b=qget(ether->oq)) == nil)
87458db832SDavid du Colombier 			break;
88458db832SDavid du Colombier 
89458db832SDavid du Colombier 		len = BLEN(b);
90458db832SDavid du Colombier 		dst = (ushort*)(Ethermem+(ctlr->txempty+Nrx)*Etherfsize);
91458db832SDavid du Colombier 		*dst = len;
92458db832SDavid du Colombier 		memmove(&dst[1], b->rp, len);
93458db832SDavid du Colombier 		ctlr->ntx++;
94458db832SDavid du Colombier 		ctlr->txempty++;
95458db832SDavid du Colombier 		if(ctlr->txempty==Ntx)
96458db832SDavid du Colombier 			ctlr->txempty = 0;
97458db832SDavid du Colombier 		freeb(b);
98458db832SDavid du Colombier 	}
99458db832SDavid du Colombier }
100458db832SDavid du Colombier 
101458db832SDavid du Colombier static void
txrestart(Ctlr * ctlr)102458db832SDavid du Colombier txrestart(Ctlr*ctlr)
103458db832SDavid du Colombier {
104458db832SDavid du Colombier 	if(ctlr->ntx==0 || ctlr->txbusy)
105458db832SDavid du Colombier 		return;
106458db832SDavid du Colombier 	ctlr->txbusy = 1;
107458db832SDavid du Colombier 	*etcr = Etcr_txstart|Etcr_retries|(ctlr->txfull+Nrx);
108458db832SDavid du Colombier }
109458db832SDavid du Colombier 
110458db832SDavid du Colombier static void interrupt(Ureg*, void*);
111458db832SDavid du Colombier 
112458db832SDavid du Colombier static void
transmit(Ether * ether)113458db832SDavid du Colombier transmit(Ether*ether)
114458db832SDavid du Colombier {
115458db832SDavid du Colombier 	Ctlr *ctlr;
116458db832SDavid du Colombier 
117458db832SDavid du Colombier 	ctlr = ether->ctlr;
118458db832SDavid du Colombier 	ilock(ctlr);
119458db832SDavid du Colombier 	txfill(ether, ctlr);
120458db832SDavid du Colombier 	txrestart(ctlr);
121458db832SDavid du Colombier 	iunlock(ctlr);
122458db832SDavid du Colombier 
123458db832SDavid du Colombier }
124458db832SDavid du Colombier 
125458db832SDavid du Colombier static void
interrupt(Ureg *,void * arg)126458db832SDavid du Colombier interrupt(Ureg*, void*arg)
127458db832SDavid du Colombier {
128458db832SDavid du Colombier 	Ctlr*ctlr;
129458db832SDavid du Colombier 	Ether*ether = arg;
130458db832SDavid du Colombier 	Etherpkt*pkt;
131458db832SDavid du Colombier 	ushort ie;
132458db832SDavid du Colombier 	int rx, len;
133458db832SDavid du Colombier 	Block *b;
134458db832SDavid du Colombier 
135458db832SDavid du Colombier 	ctlr = ether->ctlr;
136458db832SDavid du Colombier 	if(!ctlr->active)
137458db832SDavid du Colombier 		return;	/* not ours */
138458db832SDavid du Colombier 	ctlr->interrupts++;
139458db832SDavid du Colombier 
140458db832SDavid du Colombier 	ilock(ctlr);
141458db832SDavid du Colombier 	ie = *eisr;
142458db832SDavid du Colombier 	*eisr = ie;
143458db832SDavid du Colombier 	intack();
144458db832SDavid du Colombier 
145458db832SDavid du Colombier 	if(ie==0)
146458db832SDavid du Colombier 		iprint("interrupt: no interrupt source?\n");
147458db832SDavid du Colombier 
148458db832SDavid du Colombier 	if(ie&Ei_txdone){
149458db832SDavid du Colombier 		if((*etcr&Etcr_txstart)==0){
150458db832SDavid du Colombier 			if(ctlr->txbusy){
151458db832SDavid du Colombier 				ctlr->txbusy = 0;
152458db832SDavid du Colombier 				ctlr->ntx--;
153458db832SDavid du Colombier 				ctlr->txfull++;
154458db832SDavid du Colombier 				if(ctlr->txfull==Ntx)
155458db832SDavid du Colombier 					ctlr->txfull = 0;
156458db832SDavid du Colombier 			}
157458db832SDavid du Colombier 			txrestart(ctlr);
158458db832SDavid du Colombier 			txfill(ether, ctlr);
159458db832SDavid du Colombier 			txrestart(ctlr);
160458db832SDavid du Colombier 		}
161458db832SDavid du Colombier 		else
162458db832SDavid du Colombier 			iprint("interrupt: bogus tx interrupt\n");
163458db832SDavid du Colombier 		ie &= ~Ei_txdone;
164458db832SDavid du Colombier 	}
165458db832SDavid du Colombier 
166458db832SDavid du Colombier 	if(ie&Ei_rxdone){
167458db832SDavid du Colombier 		rx=*ersr&Ersr_rxfpmask;
168458db832SDavid du Colombier 		while(ctlr->rxlast!=rx){
169458db832SDavid du Colombier 
170458db832SDavid du Colombier 			ctlr->rxlast++;
171458db832SDavid du Colombier 			if(ctlr->rxlast >= Nrx)
172458db832SDavid du Colombier 				ctlr->rxlast = 0;
173458db832SDavid du Colombier 
174458db832SDavid du Colombier 			pkt = (Etherpkt*)(Ethermem+ctlr->rxlast*Etherfsize);
175458db832SDavid du Colombier 			len = *(ushort*)pkt;
176458db832SDavid du Colombier 			if((b = iallocb(len+sizeof(ushort))) != nil){
177458db832SDavid du Colombier 				memmove(b->wp, pkt, len+sizeof(ushort));
178458db832SDavid du Colombier 				b->rp += sizeof(ushort);
179458db832SDavid du Colombier 				b->wp = b->rp + len;
180458db832SDavid du Colombier 				etheriq(ether, b, 1);
181458db832SDavid du Colombier 			}else
182458db832SDavid du Colombier 				ether->soverflows++;
183458db832SDavid du Colombier 			rx=*ersr&Ersr_rxfpmask;
184458db832SDavid du Colombier 		}
185458db832SDavid du Colombier 		ie &= ~Ei_rxdone;
186458db832SDavid du Colombier 	}
187458db832SDavid du Colombier 
188458db832SDavid du Colombier 	if(ie&Ei_txretry){
189458db832SDavid du Colombier 		iprint("ethersaturn: txretry!\n");
190458db832SDavid du Colombier 		ie &= ~Ei_txretry;
191458db832SDavid du Colombier 		ctlr->txbusy = 0;
192458db832SDavid du Colombier 		txrestart(ctlr);
193458db832SDavid du Colombier 	}
194458db832SDavid du Colombier 
195458db832SDavid du Colombier 	ie &= ~Ei_txcrs;
196458db832SDavid du Colombier 	if(ie)
197458db832SDavid du Colombier 		iprint("interrupt: unhandled interrupts %.4uX\n", ie);
198458db832SDavid du Colombier 	iunlock(ctlr);
199458db832SDavid du Colombier }
200458db832SDavid du Colombier 
201458db832SDavid du Colombier static int
reset(Ether * ether)202458db832SDavid du Colombier reset(Ether* ether)
203458db832SDavid du Colombier {
204458db832SDavid du Colombier 	Ctlr*ctlr;
205458db832SDavid du Colombier 
206458db832SDavid du Colombier 	*ercr = 0;
207458db832SDavid du Colombier 	ctlr = malloc(sizeof(*ctlr));
208458db832SDavid du Colombier 	memset(ctlr, 0, sizeof(*ctlr));
209458db832SDavid du Colombier 	ctlr->active = 1;
210458db832SDavid du Colombier 
211458db832SDavid du Colombier 	ether->ctlr = ctlr;
212458db832SDavid du Colombier 	ether->transmit = transmit;
213458db832SDavid du Colombier 	ether->interrupt = interrupt;
214458db832SDavid du Colombier 	ether->irq = Vecether;
215458db832SDavid du Colombier 	ether->arg = ether;
216458db832SDavid du Colombier 	memmove(ether->ea, (ushort*)Emacaddr0, Eaddrlen);
217458db832SDavid du Colombier 
218458db832SDavid du Colombier 	*ercr = Ercr_rxenab|Ercr_auienab|(Nrx-1);
219458db832SDavid du Colombier 	*eimr = Ei_rxdone|Ei_txretry|Ei_txdone;
220458db832SDavid du Colombier 
221458db832SDavid du Colombier 	iprint("reset: ercr %.4uX\n", *ercr);
222458db832SDavid du Colombier 	return 0;
223458db832SDavid du Colombier }
224458db832SDavid du Colombier 
225458db832SDavid du Colombier void
ethersaturnlink(void)226458db832SDavid du Colombier ethersaturnlink(void)
227458db832SDavid du Colombier {
228458db832SDavid du Colombier 	addethercard("saturn", reset);
229458db832SDavid du Colombier }
230458db832SDavid du Colombier 
231