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