1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8 #include "../port/netif.h"
9 #include "msaturn.h"
10
11 #include "etherif.h"
12
13 enum{
14 Etcr = Saturn + 0x0c00,
15 Etsr = Saturn + 0x0c02,
16 Ercr = Saturn + 0x0c04,
17 Ersr = Saturn + 0x0c06,
18 Eisr = Saturn + 0x0d04,
19 Eimr = Saturn + 0x0d06,
20 Emacaddr0 = Saturn + 0x0e02,
21 Miicr = Saturn + 0x0f02,
22 Miiwdr = Saturn + 0x0f04,
23 Miirdr = Saturn + 0x0f06,
24
25 Ethermem = 0xf2c00000,
26 Etherfsize = 0x2000,
27 Nrx = 14,
28 Ntx = 2, // Nrx + Ntx must be 16
29
30 Ersr_rxfpmask = 0xf,
31 Ersr_rxevent = RBIT(0, ushort),
32 Etcr_txfpmask = 0xf,
33 Ercr_rxenab = RBIT(0, ushort),
34 Ercr_auienab = RBIT(2, ushort),
35 Etcr_txstart = RBIT(1, ushort),
36 Etcr_retries = 0xf<<8,
37 Ei_txecall = RBIT(0, ushort),
38 Ei_txretry = RBIT(2, ushort),
39 Ei_txdefer = RBIT(3, ushort),
40 Ei_txcrs = RBIT(4, ushort),
41 Ei_txdone = RBIT(5, ushort),
42 Ei_rxcrcerr = RBIT(8, ushort),
43 Ei_rxdrib = RBIT(9, ushort),
44 Ei_rxdone = RBIT(10, ushort),
45 Ei_rxshort = RBIT(11, ushort),
46 Ei_rxlong = RBIT(12, ushort),
47
48 Miicr_regshift = 6,
49 Miicr_read = RBIT(10, ushort),
50 Miicr_preambledis = RBIT(12, ushort),
51 Miicr_accack = RBIT(14, ushort),
52 Miicr_accbsy = RBIT(15, ushort),
53 };
54
55 typedef struct {
56 Lock;
57 int txbusy;
58 int txempty;
59 int txfull;
60 int ntx; /* number of entries in transmit ring */
61 int rxlast;
62
63 int active;
64 ulong interrupts; /* statistics */
65 ulong overflows;
66 } Ctlr;
67
68 uchar etheraddr[6] = { 0x90, 0x85, 0x82, 0x32, 0x83, 0x00};
69 static ushort*etcr=(ushort*)Etcr;
70 static ushort*etsr=(ushort*)Etsr;
71 static ushort*ercr=(ushort*)Ercr;
72 static ushort*ersr=(ushort*)Ersr;
73 static ushort*eimr=(ushort*)Eimr;
74 static ushort*eisr=(ushort*)Eisr;
75 static ushort*miicr=(ushort*)Miicr;
76 static ushort*miirdr=(ushort*)Miirdr;
77
78 static void
txfill(Ether * ether,Ctlr * ctlr)79 txfill(Ether*ether, Ctlr*ctlr)
80 {
81 int len;
82 Block *b;
83 ushort*dst;
84
85 while(ctlr->ntx<Ntx){
86 if((b=qget(ether->oq)) == nil)
87 break;
88
89 len = BLEN(b);
90 dst = (ushort*)(Ethermem+(ctlr->txempty+Nrx)*Etherfsize);
91 *dst = len;
92 memmove(&dst[1], b->rp, len);
93 ctlr->ntx++;
94 ctlr->txempty++;
95 if(ctlr->txempty==Ntx)
96 ctlr->txempty = 0;
97 freeb(b);
98 }
99 }
100
101 static void
txrestart(Ctlr * ctlr)102 txrestart(Ctlr*ctlr)
103 {
104 if(ctlr->ntx==0 || ctlr->txbusy)
105 return;
106 ctlr->txbusy = 1;
107 *etcr = Etcr_txstart|Etcr_retries|(ctlr->txfull+Nrx);
108 }
109
110 static void interrupt(Ureg*, void*);
111
112 static void
transmit(Ether * ether)113 transmit(Ether*ether)
114 {
115 Ctlr *ctlr;
116
117 ctlr = ether->ctlr;
118 ilock(ctlr);
119 txfill(ether, ctlr);
120 txrestart(ctlr);
121 iunlock(ctlr);
122
123 }
124
125 static void
interrupt(Ureg *,void * arg)126 interrupt(Ureg*, void*arg)
127 {
128 Ctlr*ctlr;
129 Ether*ether = arg;
130 Etherpkt*pkt;
131 ushort ie;
132 int rx, len;
133 Block *b;
134
135 ctlr = ether->ctlr;
136 if(!ctlr->active)
137 return; /* not ours */
138 ctlr->interrupts++;
139
140 ilock(ctlr);
141 ie = *eisr;
142 *eisr = ie;
143 intack();
144
145 if(ie==0)
146 iprint("interrupt: no interrupt source?\n");
147
148 if(ie&Ei_txdone){
149 if((*etcr&Etcr_txstart)==0){
150 if(ctlr->txbusy){
151 ctlr->txbusy = 0;
152 ctlr->ntx--;
153 ctlr->txfull++;
154 if(ctlr->txfull==Ntx)
155 ctlr->txfull = 0;
156 }
157 txrestart(ctlr);
158 txfill(ether, ctlr);
159 txrestart(ctlr);
160 }
161 else
162 iprint("interrupt: bogus tx interrupt\n");
163 ie &= ~Ei_txdone;
164 }
165
166 if(ie&Ei_rxdone){
167 rx=*ersr&Ersr_rxfpmask;
168 while(ctlr->rxlast!=rx){
169
170 ctlr->rxlast++;
171 if(ctlr->rxlast >= Nrx)
172 ctlr->rxlast = 0;
173
174 pkt = (Etherpkt*)(Ethermem+ctlr->rxlast*Etherfsize);
175 len = *(ushort*)pkt;
176 if((b = iallocb(len+sizeof(ushort))) != nil){
177 memmove(b->wp, pkt, len+sizeof(ushort));
178 b->rp += sizeof(ushort);
179 b->wp = b->rp + len;
180 etheriq(ether, b, 1);
181 }else
182 ether->soverflows++;
183 rx=*ersr&Ersr_rxfpmask;
184 }
185 ie &= ~Ei_rxdone;
186 }
187
188 if(ie&Ei_txretry){
189 iprint("ethersaturn: txretry!\n");
190 ie &= ~Ei_txretry;
191 ctlr->txbusy = 0;
192 txrestart(ctlr);
193 }
194
195 ie &= ~Ei_txcrs;
196 if(ie)
197 iprint("interrupt: unhandled interrupts %.4uX\n", ie);
198 iunlock(ctlr);
199 }
200
201 static int
reset(Ether * ether)202 reset(Ether* ether)
203 {
204 Ctlr*ctlr;
205
206 *ercr = 0;
207 ctlr = malloc(sizeof(*ctlr));
208 memset(ctlr, 0, sizeof(*ctlr));
209 ctlr->active = 1;
210
211 ether->ctlr = ctlr;
212 ether->transmit = transmit;
213 ether->interrupt = interrupt;
214 ether->irq = Vecether;
215 ether->arg = ether;
216 memmove(ether->ea, (ushort*)Emacaddr0, Eaddrlen);
217
218 *ercr = Ercr_rxenab|Ercr_auienab|(Nrx-1);
219 *eimr = Ei_rxdone|Ei_txretry|Ei_txdone;
220
221 iprint("reset: ercr %.4uX\n", *ercr);
222 return 0;
223 }
224
225 void
ethersaturnlink(void)226 ethersaturnlink(void)
227 {
228 addethercard("saturn", reset);
229 }
230
231