xref: /plan9-contrib/sys/src/cmd/usb/ether/smsc.c (revision e1c0af539adcc53c770ef6e067291d1d2730e221)
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