Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/src/cmd/usb/ether/smsc.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
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
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
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
361
smscfree(Ether *ether)
362
{
363
	free(ether->aux);
364
	ether->aux = nil;
365
}
366
 
367
int
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
}