Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * AMD79C970
3
 * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus
4
 * To do:
5
 *	finish this rewrite
6
 */
7
#include "u.h"
8
#include "../port/lib.h"
9
#include "mem.h"
10
#include "dat.h"
11
#include "fns.h"
12
#include "io.h"
13
#include "../port/error.h"
14
#include "../port/netif.h"
15
 
16
#include "etherif.h"
17
 
18
enum {
19
	Lognrdre	= 6,
20
	Nrdre		= (1<<Lognrdre),/* receive descriptor ring entries */
21
	Logntdre	= 4,
22
	Ntdre		= (1<<Logntdre),/* transmit descriptor ring entries */
23
 
24
	Rbsize		= ETHERMAXTU+4,	/* ring buffer size (+4 for CRC) */
25
};
26
 
27
enum {					/* DWIO I/O resource map */
28
	Aprom		= 0x0000,	/* physical address */
29
	Rdp		= 0x0010,	/* register data port */
30
	Rap		= 0x0014,	/* register address port */
31
	Sreset		= 0x0018,	/* software reset */
32
	Bdp		= 0x001C,	/* bus configuration register data port */
33
};
34
 
35
enum {					/* CSR0 */
36
	Init		= 0x0001,	/* begin initialisation */
37
	Strt		= 0x0002,	/* enable chip */
38
	Stop		= 0x0004,	/* disable chip */
39
	Tdmd		= 0x0008,	/* transmit demand */
40
	Txon		= 0x0010,	/* transmitter on */
41
	Rxon		= 0x0020,	/* receiver on */
42
	Iena		= 0x0040,	/* interrupt enable */
43
	Intr		= 0x0080,	/* interrupt flag */
44
	Idon		= 0x0100,	/* initialisation done */
45
	Tint		= 0x0200,	/* transmit interrupt */
46
	Rint		= 0x0400,	/* receive interrupt */
47
	Merr		= 0x0800,	/* memory error */
48
	Miss		= 0x1000,	/* missed frame */
49
	Cerr		= 0x2000,	/* collision */
50
	Babl		= 0x4000,	/* transmitter timeout */
51
	Err		= 0x8000,	/* Babl|Cerr|Miss|Merr */
52
};
53
 
54
enum {					/* CSR3 */
55
	Bswp		= 0x0004,	/* byte swap */
56
	Emba		= 0x0008,	/* enable modified back-off algorithm */
57
	Dxmt2pd		= 0x0010,	/* disable transmit two part deferral */
58
	Lappen		= 0x0020,	/* look-ahead packet processing enable */
59
};
60
 
61
enum {					/* CSR4 */
62
	ApadXmt		= 0x0800,	/* auto pad transmit */
63
};
64
 
65
enum {					/* CSR15 */
66
	Prom		= 0x8000,	/* promiscuous mode */
67
};
68
 
69
typedef struct Iblock Iblock;
70
struct Iblock {			/* Initialisation Block */
71
	ushort	mode;
72
	uchar	rlen;			/* upper 4 bits */
73
	uchar	tlen;			/* upper 4 bits */
74
	uchar	padr[6];
75
	uchar	res[2];
76
	uchar	ladr[8];
77
	ulong	rdra;
78
	ulong	tdra;
79
};
80
 
81
typedef struct Dre Dre;
82
struct Dre {			/* descriptor ring entry */
83
	ulong	addr;
84
	ulong	md1;			/* status|bcnt */
85
	ulong	md2;			/* rcc|rpc|mcnt */
86
	Block*	bp;
87
};
88
 
89
enum {					/* md1 */
90
	Enp		= 0x01000000,	/* end of packet */
91
	Stp		= 0x02000000,	/* start of packet */
92
	RxBuff		= 0x04000000,	/* buffer error */
93
	Def		= 0x04000000,	/* deferred */
94
	Crc		= 0x08000000,	/* CRC error */
95
	One		= 0x08000000,	/* one retry needed */
96
	Oflo		= 0x10000000,	/* overflow error */
97
	More		= 0x10000000,	/* more than one retry needed */
98
	Fram		= 0x20000000,	/* framing error */
99
	RxErr		= 0x40000000,	/* Fram|Oflo|Crc|RxBuff */
100
	TxErr		= 0x40000000,	/* Uflo|Lcol|Lcar|Rtry */
101
	Own		= 0x80000000,
102
};
103
 
104
enum {					/* md2 */
105
	Rtry		= 0x04000000,	/* failed after repeated retries */
106
	Lcar		= 0x08000000,	/* loss of carrier */
107
	Lcol		= 0x10000000,	/* late collision */
108
	Uflo		= 0x40000000,	/* underflow error */
109
	TxBuff		= 0x80000000,	/* buffer error */
110
};
111
 
112
typedef struct Ctlr Ctlr;
113
struct Ctlr {
114
	Lock;
115
	int	port;
116
	Pcidev*	pcidev;
117
	Ctlr*	next;
118
	int	active;
119
 
120
	int	init;			/* initialisation in progress */
121
	Iblock	iblock;
122
 
123
	Dre*	rdr;			/* receive descriptor ring */
124
	int	rdrx;
125
 
126
	Dre*	tdr;			/* transmit descriptor ring */
127
	int	tdrh;			/* host index into tdr */
128
	int	tdri;			/* interface index into tdr */
129
	int	ntq;			/* descriptors active */
130
 
131
	ulong	rxbuff;			/* receive statistics */
132
	ulong	crc;
133
	ulong	oflo;
134
	ulong	fram;
135
 
136
	ulong	rtry;			/* transmit statistics */
137
	ulong	lcar;
138
	ulong	lcol;
139
	ulong	uflo;
140
	ulong	txbuff;
141
 
142
	ulong	merr;			/* bobf is such a whiner */
143
	ulong	miss;
144
	ulong	babl;
145
 
146
	int	(*ior)(Ctlr*, int);
147
	void	(*iow)(Ctlr*, int, int);
148
};
149
 
150
static Ctlr* ctlrhead;
151
static Ctlr* ctlrtail;
152
 
153
/*
154
 * The Rdp, Rap, Sreset, Bdp ports are 32-bit port offset in the enumeration above.
155
 * To get to 16-bit offsets, scale down with 0x10 staying the same.
156
 */
157
static int
158
io16r(Ctlr *c, int r)
159
{
160
	if(r >= Rdp)
161
		r = (r-Rdp)/2+Rdp;
162
	return ins(c->port+r);
163
}
164
 
165
static void
166
io16w(Ctlr *c, int r, int v)
167
{
168
	if(r >= Rdp)
169
		r = (r-Rdp)/2+Rdp;
170
	outs(c->port+r, v);
171
}
172
 
173
static int
174
io32r(Ctlr *c, int r)
175
{
176
	return inl(c->port+r);
177
}
178
 
179
static void
180
io32w(Ctlr *c, int r, int v)
181
{
182
	outl(c->port+r, v);
183
}
184
 
185
static void
186
attach(Ether*)
187
{
188
}
189
 
190
static long
191
ifstat(Ether* ether, void* a, long n, ulong offset)
192
{
193
	char *p;
194
	int len;
195
	Ctlr *ctlr;
196
 
197
	ctlr = ether->ctlr;
198
 
199
	ether->crcs = ctlr->crc;
200
	ether->frames = ctlr->fram;
201
	ether->buffs = ctlr->rxbuff+ctlr->txbuff;
202
	ether->overflows = ctlr->oflo;
203
 
204
	if(n == 0)
205
		return 0;
206
 
207
	p = malloc(READSTR);
208
	if(p == nil)
209
		error(Enomem);
210
	len = snprint(p, READSTR, "Rxbuff: %ld\n", ctlr->rxbuff);
211
	len += snprint(p+len, READSTR-len, "Crc: %ld\n", ctlr->crc);
212
	len += snprint(p+len, READSTR-len, "Oflo: %ld\n", ctlr->oflo);
213
	len += snprint(p+len, READSTR-len, "Fram: %ld\n", ctlr->fram);
214
	len += snprint(p+len, READSTR-len, "Rtry: %ld\n", ctlr->rtry);
215
	len += snprint(p+len, READSTR-len, "Lcar: %ld\n", ctlr->lcar);
216
	len += snprint(p+len, READSTR-len, "Lcol: %ld\n", ctlr->lcol);
217
	len += snprint(p+len, READSTR-len, "Uflo: %ld\n", ctlr->uflo);
218
	len += snprint(p+len, READSTR-len, "Txbuff: %ld\n", ctlr->txbuff);
219
	len += snprint(p+len, READSTR-len, "Merr: %ld\n", ctlr->merr);
220
	len += snprint(p+len, READSTR-len, "Miss: %ld\n", ctlr->miss);
221
	snprint(p+len, READSTR-len, "Babl: %ld\n", ctlr->babl);
222
 
223
	n = readstr(offset, a, n, p);
224
	free(p);
225
 
226
	return n;
227
}
228
 
229
static void
230
ringinit(Ctlr* ctlr)
231
{
232
	Dre *dre;
233
 
234
	/*
235
	 * Initialise the receive and transmit buffer rings.
236
	 * The ring entries must be aligned on 16-byte boundaries.
237
	 *
238
	 * This routine is protected by ctlr->init.
239
	 */
240
	if(ctlr->rdr == 0){
241
		ctlr->rdr = xspanalloc(Nrdre*sizeof(Dre), 0x10, 0);
242
		for(dre = ctlr->rdr; dre < &ctlr->rdr[Nrdre]; dre++){
243
			dre->bp = iallocb(Rbsize);
244
			if(dre->bp == nil)
245
				panic("can't allocate ethernet receive ring\n");
246
			dre->addr = PADDR(dre->bp->rp);
247
			dre->md2 = 0;
248
			dre->md1 = Own|(-Rbsize & 0xFFFF);
249
		}
250
	}
251
	ctlr->rdrx = 0;
252
 
253
	if(ctlr->tdr == 0)
254
		ctlr->tdr = xspanalloc(Ntdre*sizeof(Dre), 0x10, 0);
255
	memset(ctlr->tdr, 0, Ntdre*sizeof(Dre));
256
	ctlr->tdrh = ctlr->tdri = 0;
257
}
258
 
259
static void
260
promiscuous(void* arg, int on)
261
{
262
	Ether *ether;
263
	int x;
264
	Ctlr *ctlr;
265
 
266
	ether = arg;
267
	ctlr = ether->ctlr;
268
 
269
	/*
270
	 * Put the chip into promiscuous mode. First must wait until
271
	 * anyone transmitting is done, then stop the chip and put
272
	 * it in promiscuous mode. Restarting is made harder by the chip
273
	 * reloading the transmit and receive descriptor pointers with their
274
	 * base addresses when Strt is set (unlike the older Lance chip),
275
	 * so the rings must be re-initialised.
276
	 */
277
	ilock(ctlr);
278
	if(ctlr->init){
279
		iunlock(ctlr);
280
		return;
281
	}
282
	ctlr->init = 1;
283
	iunlock(ctlr);
284
 
285
	while(ctlr->ntq)
286
		;
287
 
288
	ctlr->iow(ctlr, Rdp, Stop);
289
 
290
	ctlr->iow(ctlr, Rap, 15);
291
	x = ctlr->ior(ctlr, Rdp) & ~Prom;
292
	if(on)
293
		x |= Prom;
294
	ctlr->iow(ctlr, Rdp, x);
295
	ctlr->iow(ctlr, Rap, 0);
296
 
297
	ringinit(ctlr);
298
 
299
	ilock(ctlr);
300
	ctlr->init = 0;
301
	ctlr->iow(ctlr, Rdp, Iena|Strt);
302
	iunlock(ctlr);
303
}
304
 
305
static void
306
multicast(void* arg, uchar*, int)
307
{
308
	promiscuous(arg, 1);
309
}
310
 
311
static void
312
shutdown(Ether *ether)
313
{
314
	Ctlr *ctlr;
315
 
316
	ctlr = ether->ctlr;
317
	ilock(ctlr);
318
	io32r(ctlr, Sreset);
319
	io16r(ctlr, Sreset);
320
	iunlock(ctlr);
321
}
322
 
323
static void
324
txstart(Ether* ether)
325
{
326
	Ctlr *ctlr;
327
	Block *bp;
328
	Dre *dre;
329
 
330
	ctlr = ether->ctlr;
331
 
332
	if(ctlr->init)
333
		return;
334
 
335
	while(ctlr->ntq < (Ntdre-1)){
336
		bp = qget(ether->oq);
337
		if(bp == nil)
338
			break;
339
 
340
		/*
341
		 * Give ownership of the descriptor to the chip,
342
		 * increment the software ring descriptor pointer
343
		 * and tell the chip to poll.
344
		 * There's no need to pad to ETHERMINTU
345
		 * here as ApadXmt is set in CSR4.
346
		 */
347
		dre = &ctlr->tdr[ctlr->tdrh];
348
		dre->bp = bp;
349
		dre->addr = PADDR(bp->rp);
350
		dre->md2 = 0;
351
		dre->md1 = Own|Stp|Enp|(-BLEN(bp) & 0xFFFF);
352
		ctlr->ntq++;
353
		ctlr->iow(ctlr, Rdp, Iena|Tdmd);
354
		ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
355
	}
356
}
357
 
358
static void
359
transmit(Ether* ether)
360
{
361
	Ctlr *ctlr;
362
 
363
	ctlr = ether->ctlr;
364
	ilock(ctlr);
365
	txstart(ether);
366
	iunlock(ctlr);
367
}
368
 
369
static void
370
interrupt(Ureg*, void* arg)
371
{
372
	Ctlr *ctlr;
373
	Ether *ether;
374
	int csr0, len;
375
	Dre *dre;
376
	Block *bp;
377
 
378
	ether = arg;
379
	ctlr = ether->ctlr;
380
 
381
	/*
382
	 * Acknowledge all interrupts and whine about those that shouldn't
383
	 * happen.
384
	 */
385
intrloop:
386
	csr0 = ctlr->ior(ctlr, Rdp) & 0xFFFF;
387
	ctlr->iow(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
388
	if(csr0 & Merr)
389
		ctlr->merr++;
390
	if(csr0 & Miss)
391
		ctlr->miss++;
392
	if(csr0 & Babl)
393
		ctlr->babl++;
394
	//if(csr0 & (Babl|Miss|Merr))
395
	//	print("#l%d: csr0 = 0x%uX\n", ether->ctlrno, csr0);
396
	if(!(csr0 & (Rint|Tint)))
397
		return;
398
 
399
	/*
400
	 * Receiver interrupt: run round the descriptor ring logging
401
	 * errors and passing valid receive data up to the higher levels
402
	 * until a descriptor is encountered still owned by the chip.
403
	 */
404
	if(csr0 & Rint){
405
		dre = &ctlr->rdr[ctlr->rdrx];
406
		while(!(dre->md1 & Own)){
407
			if(dre->md1 & RxErr){
408
				if(dre->md1 & RxBuff)
409
					ctlr->rxbuff++;
410
				if(dre->md1 & Crc)
411
					ctlr->crc++;
412
				if(dre->md1 & Oflo)
413
					ctlr->oflo++;
414
				if(dre->md1 & Fram)
415
					ctlr->fram++;
416
			}
417
			else if(bp = iallocb(Rbsize)){
418
				len = (dre->md2 & 0x0FFF)-4;
419
				dre->bp->wp = dre->bp->rp+len;
420
				etheriq(ether, dre->bp, 1);
421
				dre->bp = bp;
422
				dre->addr = PADDR(bp->rp);
423
			}
424
 
425
			/*
426
			 * Finished with this descriptor, reinitialise it,
427
			 * give it back to the chip, then on to the next...
428
			 */
429
			dre->md2 = 0;
430
			dre->md1 = Own|(-Rbsize & 0xFFFF);
431
 
432
			ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
433
			dre = &ctlr->rdr[ctlr->rdrx];
434
		}
435
	}
436
 
437
	/*
438
	 * Transmitter interrupt: wakeup anyone waiting for a free descriptor.
439
	 */
440
	if(csr0 & Tint){
441
		lock(ctlr);
442
		while(ctlr->ntq){
443
			dre = &ctlr->tdr[ctlr->tdri];
444
			if(dre->md1 & Own)
445
				break;
446
 
447
			if(dre->md1 & TxErr){
448
				if(dre->md2 & Rtry)
449
					ctlr->rtry++;
450
				if(dre->md2 & Lcar)
451
					ctlr->lcar++;
452
				if(dre->md2 & Lcol)
453
					ctlr->lcol++;
454
				if(dre->md2 & Uflo)
455
					ctlr->uflo++;
456
				if(dre->md2 & TxBuff)
457
					ctlr->txbuff++;
458
				ether->oerrs++;
459
			}
460
 
461
			freeb(dre->bp);
462
 
463
			ctlr->ntq--;
464
			ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
465
		}
466
		txstart(ether);
467
		unlock(ctlr);
468
	}
469
	goto intrloop;
470
}
471
 
472
static void
473
amd79c970pci(void)
474
{
475
	int port;
476
	Ctlr *ctlr;
477
	Pcidev *p;
478
 
479
	p = nil;
480
	while(p = pcimatch(p, 0x1022, 0x2000)){
481
		port = p->mem[0].bar & ~0x01;
482
		if(ioalloc(port, p->mem[0].size, 0, "amd79c970") < 0){
483
			print("amd79c970: port 0x%uX in use\n", port);
484
			continue;
485
		}
486
		ctlr = malloc(sizeof(Ctlr));
487
		if(ctlr == nil)
488
			error(Enomem);
489
		ctlr->port = p->mem[0].bar & ~0x01;
490
		ctlr->pcidev = p;
491
 
492
		if(ctlrhead != nil)
493
			ctlrtail->next = ctlr;
494
		else
495
			ctlrhead = ctlr;
496
		ctlrtail = ctlr;
497
	}
498
}
499
 
500
static int
501
reset(Ether* ether)
502
{
503
	int x;
504
	uchar ea[Eaddrlen];
505
	Ctlr *ctlr;
506
 
507
	if(ctlrhead == nil)
508
		amd79c970pci();
509
 
510
	/*
511
	 * Any adapter matches if no port is supplied,
512
	 * otherwise the ports must match.
513
	 */
514
	for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
515
		if(ctlr->active)
516
			continue;
517
		if(ether->port == 0 || ether->port == ctlr->port){
518
			ctlr->active = 1;
519
			break;
520
		}
521
	}
522
	if(ctlr == nil)
523
		return -1;
524
 
525
	/*
526
	 * Allocate a controller structure and start to initialise it.
527
	 */
528
	ether->ctlr = ctlr;
529
	ether->port = ctlr->port;
530
	ether->irq = ctlr->pcidev->intl;
531
	ether->tbdf = ctlr->pcidev->tbdf;
532
	pcisetbme(ctlr->pcidev);
533
	shutdown(ether);
534
	ilock(ctlr);
535
	ctlr->init = 1;
536
 
537
	if(io16w(ctlr, Rap, 0), io16r(ctlr, Rdp) == 4){
538
		ctlr->ior = io16r;
539
		ctlr->iow = io16w;
540
	}else if(io32w(ctlr, Rap, 0), io32r(ctlr, Rdp) == 4){
541
		ctlr->ior = io32r;
542
		ctlr->iow = io32w;
543
	}else{
544
		print("#l%d: card doesn't talk right\n", ether->ctlrno);
545
		iunlock(ctlr);
546
		return -1;
547
	}
548
 
549
	ctlr->iow(ctlr, Rap, 88);
550
	x = ctlr->ior(ctlr, Rdp);
551
	ctlr->iow(ctlr, Rap, 89);
552
	x |= ctlr->ior(ctlr, Rdp)<<16;
553
 
554
	switch(x&0xFFFFFFF){
555
	case 0x2420003:	/* PCnet/PCI 79C970 */
556
	case 0x2621003:	/* PCnet/PCI II 79C970A */
557
	case 0x2625003:	/* PCnet-FAST III 79C973 */
558
		break;
559
	default:
560
		print("#l%d: unknown PCnet card version 0x%.7ux\n",
561
			ether->ctlrno, x&0xFFFFFFF);
562
		iunlock(ctlr);
563
		return -1;
564
	}
565
 
566
	/*
567
	 * Set the software style in BCR20 to be PCnet-PCI to ensure 32-bit access.
568
	 * Set the auto pad transmit in CSR4.
569
	 */
570
	ctlr->iow(ctlr, Rap, 20);
571
	ctlr->iow(ctlr, Bdp, 0x0002);
572
 
573
	ctlr->iow(ctlr, Rap, 4);
574
	x = ctlr->ior(ctlr, Rdp) & 0xFFFF;
575
	ctlr->iow(ctlr, Rdp, ApadXmt|x);
576
 
577
	ctlr->iow(ctlr, Rap, 0);
578
 
579
	/*
580
	 * Check if the adapter's station address is to be overridden.
581
	 * If not, read it from the I/O-space and set in ether->ea prior to
582
	 * loading the station address in the initialisation block.
583
	 */
584
	memset(ea, 0, Eaddrlen);
585
	if(!memcmp(ea, ether->ea, Eaddrlen)){
586
		x = ctlr->ior(ctlr, Aprom);
587
		ether->ea[0] = x;
588
		ether->ea[1] = x>>8;
589
		if(ctlr->ior == io16r)
590
			x = ctlr->ior(ctlr, Aprom+2);
591
		else
592
			x >>= 16;
593
		ether->ea[2] = x;
594
		ether->ea[3] = x>>8;
595
		x = ctlr->ior(ctlr, Aprom+4);
596
		ether->ea[4] = x;
597
		ether->ea[5] = x>>8;
598
	}
599
 
600
	/*
601
	 * Start to fill in the initialisation block
602
	 * (must be DWORD aligned).
603
	 */
604
	ctlr->iblock.rlen = Lognrdre<<4;
605
	ctlr->iblock.tlen = Logntdre<<4;
606
	memmove(ctlr->iblock.padr, ether->ea, sizeof(ctlr->iblock.padr));
607
 
608
	ringinit(ctlr);
609
	ctlr->iblock.rdra = PADDR(ctlr->rdr);
610
	ctlr->iblock.tdra = PADDR(ctlr->tdr);
611
 
612
	/*
613
	 * Point the chip at the initialisation block and tell it to go.
614
	 * Mask the Idon interrupt and poll for completion. Strt and interrupt
615
	 * enables will be set later when attaching to the network.
616
	 */
617
	x = PADDR(&ctlr->iblock);
618
	ctlr->iow(ctlr, Rap, 1);
619
	ctlr->iow(ctlr, Rdp, x & 0xFFFF);
620
	ctlr->iow(ctlr, Rap, 2);
621
	ctlr->iow(ctlr, Rdp, (x>>16) & 0xFFFF);
622
	ctlr->iow(ctlr, Rap, 3);
623
	ctlr->iow(ctlr, Rdp, Idon);
624
	ctlr->iow(ctlr, Rap, 0);
625
	ctlr->iow(ctlr, Rdp, Init);
626
 
627
	while(!(ctlr->ior(ctlr, Rdp) & Idon))
628
		;
629
 
630
	/*
631
	 * We used to set CSR0 to Idon|Stop here, and then
632
	 * in attach change it to Iena|Strt.  Apparently the simulated
633
	 * 79C970 in VMware never enables after a write of Idon|Stop,
634
	 * so we enable the device here now.
635
	 */
636
	ctlr->iow(ctlr, Rdp, Iena|Strt);
637
	ctlr->init = 0;
638
	iunlock(ctlr);
639
 
640
	/*
641
	 * Linkage to the generic ethernet driver.
642
	 */
643
	ether->attach = attach;
644
	ether->transmit = transmit;
645
	ether->interrupt = interrupt;
646
	ether->ifstat = ifstat;
647
 
648
	ether->arg = ether;
649
	ether->promiscuous = promiscuous;
650
	ether->multicast = multicast;
651
	ether->shutdown = shutdown;
652
 
653
	return 0;
654
}
655
 
656
void
657
ether79c970link(void)
658
{
659
	addethercard("AMD79C970",  reset);
660
}