1 /*
2 * SMSC LAN95XX
3 */
4
5 #include <u.h>
6 #include <libc.h>
7 #include <fcall.h>
8 #include <thread.h>
9 #include "usb.h"
10 #include "usbfs.h"
11 #include "ether.h"
12
13 enum {
14 Doburst = 1,
15 Resettime = 1000,
16 E2pbusytime = 1000,
17 Afcdefault = 0xF830A1,
18 Hsburst = 24,
19 Fsburst = 129,
20 Defbulkdly = 1000,
21
22 Ethp8021q = 0x8100,
23 MACoffset = 1,
24 PHYinternal = 1,
25 Rxerror = 0x8000,
26 Txfirst = 0x2000,
27 Txlast = 0x1000,
28
29 /* USB vendor requests */
30 Writereg = 0xA0,
31 Readreg = 0xA1,
32
33 /* device registers */
34 Intsts = 0x08,
35 Txcfg = 0x10,
36 Txon = 1<<2,
37 Hwcfg = 0x14,
38 Bir = 1<<12,
39 Rxdoff = 3<<9,
40 Mef = 1<<5,
41 Lrst = 1<<3,
42 Bce = 1<<1,
43 Pmctrl = 0x20,
44 Phyrst = 1<<4,
45 Ledgpio = 0x24,
46 Ledspd = 1<<24,
47 Ledlnk = 1<<20,
48 Ledfdx = 1<<16,
49 Afccfg = 0x2C,
50 E2pcmd = 0x30,
51 Busy = 1<<31,
52 Timeout = 1<<10,
53 Read = 0,
54 E2pdata = 0x34,
55 Burstcap = 0x38,
56 Intepctl = 0x68,
57 Phyint = 1<<15,
58 Bulkdelay = 0x6C,
59 Maccr = 0x100,
60 Mcpas = 1<<19,
61 Prms = 1<<18,
62 Hpfilt = 1<<13,
63 Txen = 1<<3,
64 Rxen = 1<<2,
65 Addrh = 0x104,
66 Addrl = 0x108,
67 Hashh = 0x10C,
68 Hashl = 0x110,
69 MIIaddr = 0x114,
70 MIIwrite= 1<<1,
71 MIIread = 0<<1,
72 MIIbusy = 1<<0,
73 MIIdata = 0x118,
74 Flow = 0x11C,
75 Vlan1 = 0x120,
76 Coecr = 0x130,
77 Txcoe = 1<<16,
78 Rxcoemd = 1<<1,
79 Rxcoe = 1<<0,
80
81 /* MII registers */
82 Bmcr = 0,
83 Bmcrreset= 1<<15,
84 Speed100= 1<<13,
85 Anenable= 1<<12,
86 Anrestart= 1<<9,
87 Fulldpx = 1<<8,
88 Bmsr = 1,
89 Advertise = 4,
90 Adcsma = 0x0001,
91 Ad10h = 0x0020,
92 Ad10f = 0x0040,
93 Ad100h = 0x0080,
94 Ad100f = 0x0100,
95 Adpause = 0x0400,
96 Adpauseasym= 0x0800,
97 Adall = Ad10h|Ad10f|Ad100h|Ad100f,
98 Phyintsrc = 29,
99 Phyintmask = 30,
100 Anegcomp= 1<<6,
101 Linkdown= 1<<4,
102 };
103
104 static int burstcap = Hsburst, bulkdelay = Defbulkdly;
105
106 static int
wr(Dev * d,int reg,int val)107 wr(Dev *d, int reg, int val)
108 {
109 int ret;
110
111 ret = usbcmd(d, Rh2d|Rvendor|Rdev, Writereg, 0, reg,
112 (uchar*)&val, sizeof(val));
113 if(ret < 0)
114 deprint(2, "%s: wr(%x, %x): %r", argv0, reg, val);
115 return ret;
116 }
117
118 static int
rr(Dev * d,int reg)119 rr(Dev *d, int reg)
120 {
121 int ret, rval;
122
123 ret = usbcmd(d, Rd2h|Rvendor|Rdev, Readreg, 0, reg,
124 (uchar*)&rval, sizeof(rval));
125 if(ret < 0){
126 fprint(2, "%s: rr(%x): %r", argv0, reg);
127 return 0;
128 }
129 return rval;
130 }
131
132 static int
miird(Dev * d,int idx)133 miird(Dev *d, int idx)
134 {
135 while(rr(d, MIIaddr) & MIIbusy)
136 ;
137 wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIread);
138 while(rr(d, MIIaddr) & MIIbusy)
139 ;
140 return rr(d, MIIdata);
141 }
142
143 static void
miiwr(Dev * d,int idx,int val)144 miiwr(Dev *d, int idx, int val)
145 {
146 while(rr(d, MIIaddr) & MIIbusy)
147 ;
148 wr(d, MIIdata, val);
149 wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIwrite);
150 while(rr(d, MIIaddr) & MIIbusy)
151 ;
152 }
153
154 static int
eepromr(Dev * d,int off,uchar * buf,int len)155 eepromr(Dev *d, int off, uchar *buf, int len)
156 {
157 int i, v;
158
159 for(i = 0; i < E2pbusytime; i++)
160 if((rr(d, E2pcmd) & Busy) == 0)
161 break;
162 if(i == E2pbusytime)
163 return -1;
164 for(i = 0; i < len; i++){
165 wr(d, E2pcmd, Busy|Read|(i+off));
166 while((v = rr(d, E2pcmd) & (Busy|Timeout)) == Busy)
167 ;
168 if(v & Timeout)
169 return -1;
170 buf[i] = rr(d, E2pdata);
171 }
172 return 0;
173 }
174
175 static void
phyinit(Dev * d)176 phyinit(Dev *d)
177 {
178 int i;
179
180 miiwr(d, Bmcr, Bmcrreset|Anenable);
181 for(i = 0; i < Resettime/10; i++){
182 if((miird(d, Bmcr) & Bmcrreset) == 0)
183 break;
184 sleep(10);
185 }
186 miiwr(d, Advertise, Adcsma|Adall|Adpause|Adpauseasym);
187 // miiwr(d, Advertise, Adcsma|Ad10f|Ad10h|Adpause|Adpauseasym);
188 miird(d, Phyintsrc);
189 miiwr(d, Phyintmask, Anegcomp|Linkdown);
190 miiwr(d, Bmcr, miird(d, Bmcr)|Anenable|Anrestart);
191 }
192
193
194 static int
doreset(Dev * d,int reg,int bit)195 doreset(Dev *d, int reg, int bit)
196 {
197 int i;
198
199 if(wr(d, reg, bit) < 0)
200 return -1;
201 for(i = 0; i < Resettime/10; i++){
202 if((rr(d, reg) & bit) == 0)
203 return 1;
204 sleep(10);
205 }
206 return 0;
207 }
208
209 static int
getmac(Dev * d,uchar buf[])210 getmac(Dev *d, uchar buf[])
211 {
212 int i;
213 uchar ea[Eaddrlen];
214
215 if(eepromr(d, MACoffset, ea, Eaddrlen) < 0)
216 return -1;
217 for(i = 0; i < Eaddrlen; i++)
218 if(ea[i] != 0 && ea[i] != 0xFF){
219 memmove(buf, ea, Eaddrlen);
220 break;
221 }
222 return Eaddrlen;
223 }
224
225 static int
smscinit(Ether * ether)226 smscinit(Ether *ether)
227 {
228 Dev *d;
229
230 if(ether->cid != S95xx)
231 return -1;
232 d = ether->dev;
233 deprint(2, "%s: setting up SMSC95XX\n", argv0);
234 if(!doreset(d, Hwcfg, Lrst) || !doreset(d, Pmctrl, Phyrst))
235 return -1;
236 if(getmac(d, ether->addr) < 0)
237 return -1;
238 wr(d, Addrl, GET4(ether->addr));
239 wr(d, Addrh, GET2(ether->addr+4));
240 if(Doburst){
241 wr(d, Hwcfg, (rr(d,Hwcfg)&~Rxdoff)|Bir|Mef|Bce);
242 wr(d, Burstcap, burstcap);
243 wr(d, Bulkdelay, bulkdelay);
244 }else{
245 wr(d, Hwcfg, (rr(d,Hwcfg)&~(Rxdoff|Mef|Bce))|Bir);
246 wr(d, Burstcap, 0);
247 wr(d, Bulkdelay, 0);
248 }
249 wr(d, Intsts, ~0);
250 wr(d, Ledgpio, Ledspd|Ledlnk|Ledfdx);
251 wr(d, Flow, 0);
252 wr(d, Afccfg, Afcdefault);
253 wr(d, Vlan1, Ethp8021q);
254 wr(d, Coecr, rr(d,Coecr)&~(Txcoe|Rxcoe)); /* TODO could offload checksums? */
255
256 wr(d, Hashh, 0);
257 wr(d, Hashl, 0);
258 wr(d, Maccr, rr(d,Maccr)&~(Prms|Mcpas|Hpfilt));
259
260 phyinit(d);
261
262 wr(d, Intepctl, rr(d, Intepctl)|Phyint);
263 wr(d, Maccr, rr(d, Maccr)|Txen|Rxen);
264 wr(d, Txcfg, Txon);
265
266 return 0;
267 }
268
269 static long
smscbread(Ether * e,Buf * bp)270 smscbread(Ether *e, Buf *bp)
271 {
272 uint hd;
273 int n, m;
274 Buf *rbp;
275
276 rbp = e->aux;
277 if(rbp->ndata < 4){
278 rbp->rp = rbp->data;
279 rbp->ndata = read(e->epin->dfd, rbp->rp, Doburst? burstcap*512:
280 Maxpkt);
281 if(rbp->ndata < 0)
282 return -1;
283 }
284 if(rbp->ndata < 4){
285 werrstr("short frame");
286 fprint(2, "smsc short frame %d bytes\n", rbp->ndata);
287 return 0;
288 }
289 hd = GET4(rbp->rp);
290 rbp->rp += 4;
291 rbp->ndata -= 4;
292 n = hd >> 16;
293 if(n < 6 || n > rbp->ndata){
294 werrstr("frame length");
295 fprint(2, "smsc length error packet %d buf %d\n", n, rbp->ndata);
296 rbp->ndata = 0;
297 return 0;
298 }
299 m = n;
300 if(rbp->ndata - m < 4)
301 m = rbp->ndata;
302 if(hd & Rxerror){
303 fprint(2, "smsc rx error %8.8ux\n", hd);
304 n = 0;
305 }else{
306 bp->rp = bp->data + Hdrsize;
307 memmove(bp->rp, rbp->rp, n);
308 }
309 bp->ndata = n;
310 rbp->rp += m;
311 rbp->ndata -= m;
312 return n;
313 }
314
315 static long
smscbwrite(Ether * e,Buf * bp)316 smscbwrite(Ether *e, Buf *bp)
317 {
318 int n;
319
320 n = bp->ndata & 0x7FF;
321 bp->rp -= 8;
322 bp->ndata += 8;
323 PUT4(bp->rp, n | Txfirst | Txlast);
324 PUT4(bp->rp+4, n);
325 n = write(e->epout->dfd, bp->rp, bp->ndata);
326 return n;
327 }
328
329 static int
smscpromiscuous(Ether * e,int on)330 smscpromiscuous(Ether *e, int on)
331 {
332 Dev *d;
333 int rxctl;
334
335 d = e->dev;
336 rxctl = rr(d, Maccr);
337 if(on)
338 rxctl |= Prms;
339 else
340 rxctl &= ~Prms;
341 return wr(d, Maccr, rxctl);
342 }
343
344 static int
smscmulticast(Ether * e,uchar * addr,int on)345 smscmulticast(Ether *e, uchar *addr, int on)
346 {
347 int rxctl;
348 Dev *d;
349
350 USED(addr, on);
351 /* BUG: should write multicast filter */
352 d = e->dev;
353 rxctl = rr(d, Maccr);
354 if(e->nmcasts != 0)
355 rxctl |= Mcpas;
356 else
357 rxctl &= ~Mcpas;
358 deprint(2, "%s: smscmulticast %d\n", argv0, e->nmcasts);
359 return wr(d, Maccr, rxctl);
360 }
361
362 static void
smscfree(Ether * ether)363 smscfree(Ether *ether)
364 {
365 free(ether->aux);
366 ether->aux = nil;
367 }
368
369 int
smscreset(Ether * ether)370 smscreset(Ether *ether)
371 {
372 Cinfo *ip;
373 Dev *dev;
374
375 dev = ether->dev;
376 for(ip = cinfo; ip->vid != 0; ip++)
377 if(ip->vid == dev->usb->vid && ip->did == dev->usb->did){
378 ether->cid = ip->cid;
379 if(smscinit(ether) < 0){
380 deprint(2, "%s: smsc init failed: %r\n", argv0);
381 return -1;
382 }
383 deprint(2, "%s: smsc reset done\n", argv0);
384 ether->name = "smsc";
385 if(Doburst){
386 ether->bufsize = burstcap*512;
387 ether->aux = emallocz(sizeof(Buf) +
388 ether->bufsize - Maxpkt, 1);
389 }else{
390 ether->bufsize = Maxpkt;
391 ether->aux = emallocz(sizeof(Buf), 1);
392 }
393 ether->free = smscfree;
394 ether->bread = smscbread;
395 ether->bwrite = smscbwrite;
396 ether->promiscuous = smscpromiscuous;
397 ether->multicast = smscmulticast;
398 ether->mbps = 100; /* BUG */
399 return 0;
400 }
401 return -1;
402 }
403