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