Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * FCCn ethernet
3
 */
4
 
5
#include "u.h"
6
#include "../port/lib.h"
7
#include "mem.h"
8
#include "dat.h"
9
#include "fns.h"
10
#include "io.h"
11
#include "imm.h"
12
#include "../port/error.h"
13
#include "../port/netif.h"
14
 
15
#include "etherif.h"
16
#include "../ppc/ethermii.h"
17
 
18
#define DBG 1
19
 
20
enum {
21
	Nrdre		= 128,			/* receive descriptor ring entries */
22
	Ntdre		= 128,			/* transmit descriptor ring entries */
23
 
24
	Rbsize		= ETHERMAXTU+4,		/* ring buffer size (+4 for CRC) */
25
	Bufsize		= Rbsize+CACHELINESZ,	/* extra room for alignment */
26
};
27
 
28
enum {
29
 
30
	/* ether-specific Rx BD bits */
31
	RxMiss=		SBIT(7),
32
	RxeLG=		SBIT(10),
33
	RxeNO=		SBIT(11),
34
	RxeSH=		SBIT(12),
35
	RxeCR=		SBIT(13),
36
	RxeOV=		SBIT(14),
37
	RxeCL=		SBIT(15),
38
	RxError=	(RxeLG|RxeNO|RxeSH|RxeCR|RxeOV|RxeCL),	/* various error flags */
39
 
40
	/* ether-specific Tx BD bits */
41
	TxPad=		SBIT(1),	/* pad short frames */
42
	TxTC=		SBIT(5),	/* transmit CRC */
43
	TxeDEF=		SBIT(6),
44
	TxeHB=		SBIT(7),
45
	TxeLC=		SBIT(8),
46
	TxeRL=		SBIT(9),
47
	TxeUN=		SBIT(14),
48
	TxeCSL=		SBIT(15),
49
 
50
	/* psmr */
51
	CRCE=		BIT(24),	/* Ethernet CRC */
52
	FCE=		BIT(10),	/* flow control */
53
	PRO=		BIT(9),		/* promiscuous mode */
54
	FDE=		BIT(5),		/* full duplex ethernet */
55
	LPB=		BIT(3),		/* local protect bit */
56
 
57
	/* gfmr */
58
	ENET=		0xc,		/* ethernet mode */
59
	ENT=		BIT(27),
60
	ENR=		BIT(26),
61
	TCI=		BIT(2),
62
 
63
	/* FCC function code register */
64
	GBL=		0x20,
65
	BO=		0x18,
66
	EB=		0x10,		/* Motorola byte order */
67
	TC2=		0x04,
68
	DTB=		0x02,
69
	BDB=		0x01,
70
 
71
	/* FCC Event/Mask bits */
72
	GRA=		SBIT(8),
73
	RXC=		SBIT(9),
74
	TXC=		SBIT(10),
75
	TXE=		SBIT(11),
76
	RXF=		SBIT(12),
77
	BSY=		SBIT(13),
78
	TXB=		SBIT(14),
79
	RXB=		SBIT(15),
80
};
81
 
82
enum {		/* Mcr */
83
	MDIread	=	0x60020000,	/* read opcode */
84
	MDIwrite =	0x50020000,	/* write opcode */
85
};
86
 
87
typedef struct Etherparam Etherparam;
88
struct Etherparam {
89
/*0x00*/	FCCparam;
90
/*0x3c*/	ulong	stat_buf;
91
/*0x40*/	ulong	cam_ptr;
92
/*0x44*/	ulong	cmask;
93
/*0x48*/	ulong	cpres;
94
/*0x4c*/	ulong	crcec;
95
/*0x50*/	ulong	alec;
96
/*0x54*/	ulong	disfc;
97
/*0x58*/	ushort	retlim;
98
/*0x5a*/	ushort	retcnt;
99
/*0x5c*/	ushort	p_per;
100
/*0x5e*/	ushort	boff_cnt;
101
/*0x60*/	ulong	gaddr[2];
102
/*0x68*/	ushort	tfcstat;
103
/*0x6a*/	ushort	tfclen;
104
/*0x6c*/	ulong	tfcptr;
105
/*0x70*/	ushort	mflr;
106
/*0x72*/	ushort	paddr[3];
107
/*0x78*/	ushort	ibd_cnt;
108
/*0x7a*/	ushort	ibd_start;
109
/*0x7c*/	ushort	ibd_end;
110
/*0x7e*/	ushort	tx_len;
111
/*0x80*/	uchar	ibd_base[32];
112
/*0xa0*/	ulong	iaddr[2];
113
/*0xa8*/	ushort	minflr;
114
/*0xaa*/	ushort	taddr[3];
115
/*0xb0*/	ushort	padptr;
116
/*0xb2*/	ushort	Rsvdb2;
117
/*0xb4*/	ushort	cf_range;
118
/*0xb6*/	ushort	max_b;
119
/*0xb8*/	ushort	maxd1;
120
/*0xba*/	ushort	maxd2;
121
/*0xbc*/	ushort	maxd;
122
/*0xbe*/	ushort	dma_cnt;
123
/*0xc0*/	ulong	octc;
124
/*0xc4*/	ulong	colc;
125
/*0xc8*/	ulong	broc;
126
/*0xcc*/	ulong	mulc;
127
/*0xd0*/	ulong	uspc;
128
/*0xd4*/	ulong	frgc;
129
/*0xd8*/	ulong	ospc;
130
/*0xdc*/	ulong	jbrc;
131
/*0xe0*/	ulong	p64c;
132
/*0xe4*/	ulong	p65c;
133
/*0xe8*/	ulong	p128c;
134
/*0xec*/	ulong	p256c;
135
/*0xf0*/	ulong	p512c;
136
/*0xf4*/	ulong	p1024c;
137
/*0xf8*/	ulong	cam_buf;
138
/*0xfc*/	ulong	Rsvdfc;
139
/*0x100*/
140
};
141
 
142
typedef struct Ctlr Ctlr;
143
struct Ctlr {
144
	Lock;
145
	int	fccid;
146
	int	port;
147
	ulong	pmdio;
148
	ulong	pmdck;
149
	int	init;
150
	int	active;
151
	int	duplex;		/* 1 == full */
152
	FCC*	fcc;
153
 
154
	Ring;
155
	Block*	rcvbufs[Nrdre];
156
	Mii*	mii;
157
	Timer;
158
 
159
	ulong	interrupts;	/* statistics */
160
	ulong	deferred;
161
	ulong	heartbeat;
162
	ulong	latecoll;
163
	ulong	retrylim;
164
	ulong	underrun;
165
	ulong	overrun;
166
	ulong	carrierlost;
167
	ulong	retrycount;
168
};
169
 
170
static	int	fccirq[] = {0x20, 0x21, 0x22};
171
static	int	fccid[] = {FCC1ID, FCC2ID, FCC3ID};
172
 
173
#ifdef DBG
174
ulong fccrhisto[16];
175
ulong fccthisto[16];
176
ulong fccrthisto[16];
177
ulong fcctrhisto[16];
178
ulong ehisto[0x80];
179
#endif
180
 
181
static int fccmiimir(Mii*, int, int);
182
static int fccmiimiw(Mii*, int, int, int);
183
static void fccltimer(Ureg*, Timer*);
184
 
185
static void
186
attach(Ether *ether)
187
{
188
	Ctlr *ctlr;
189
 
190
	ctlr = ether->ctlr;
191
	ilock(ctlr);
192
	ctlr->active = 1;
193
	ctlr->fcc->gfmr |= ENR|ENT;
194
	iunlock(ctlr);
195
	ctlr->tmode = Tperiodic;
196
	ctlr->tf = fccltimer;
197
	ctlr->ta = ether;
198
	ctlr->tns = 5000000000LL;	/* 5 seconds */
199
	timeradd(ctlr);
200
}
201
 
202
static void
203
closed(Ether *ether)
204
{
205
	Ctlr *ctlr;
206
 
207
	ctlr = ether->ctlr;
208
	ilock(ctlr);
209
	ctlr->active = 0;
210
	ctlr->fcc->gfmr &= ~(ENR|ENT);
211
	iunlock(ctlr);
212
	print("Ether closed\n");
213
}
214
 
215
static void
216
promiscuous(void* arg, int on)
217
{
218
	Ether *ether;
219
	Ctlr *ctlr;
220
 
221
	ether = (Ether*)arg;
222
	ctlr = ether->ctlr;
223
 
224
	ilock(ctlr);
225
	if(on || ether->nmaddr)
226
		ctlr->fcc->fpsmr |= PRO;
227
	else
228
		ctlr->fcc->fpsmr &= ~PRO;
229
	iunlock(ctlr);
230
}
231
 
232
static void
233
multicast(void* arg, uchar *addr, int on)
234
{
235
	Ether *ether;
236
	Ctlr *ctlr;
237
 
238
	USED(addr, on);	/* if on, could SetGroupAddress; if !on, it's hard */
239
 
240
	ether = (Ether*)arg;
241
	ctlr = ether->ctlr;
242
 
243
	ilock(ctlr);
244
	if(ether->prom || ether->nmaddr)
245
		ctlr->fcc->fpsmr |= PRO;
246
	else
247
		ctlr->fcc->fpsmr &= ~PRO;
248
	iunlock(ctlr);
249
}
250
 
251
static void
252
txstart(Ether *ether)
253
{
254
	int len;
255
	Ctlr *ctlr;
256
	Block *b;
257
	BD *dre;
258
 
259
	ctlr = ether->ctlr;
260
	if(ctlr->init)
261
		return;
262
	while(ctlr->ntq < Ntdre-1){
263
		b = qget(ether->oq);
264
		if(b == 0)
265
			break;
266
 
267
		dre = &ctlr->tdr[ctlr->tdrh];
268
		dczap(dre, sizeof(BD));
269
		if(dre->status & BDReady)
270
			panic("ether: txstart");
271
 
272
		/*
273
		 * Give ownership of the descriptor to the chip, increment the
274
		 * software ring descriptor pointer and tell the chip to poll.
275
		 */
276
		len = BLEN(b);
277
		if(ctlr->txb[ctlr->tdrh] != nil)
278
			panic("fcc/ether: txstart");
279
		ctlr->txb[ctlr->tdrh] = b;
280
		if((ulong)b->rp&1)
281
			panic("fcc/ether: txstart align");	/* TO DO: ensure alignment */
282
		dre->addr = PADDR(b->rp);
283
		dre->length = len;
284
		dcflush(b->rp, len);
285
		dcflush(dre, sizeof(BD));
286
		dre->status = (dre->status & BDWrap) | BDReady|TxPad|BDInt|BDLast|TxTC;
287
		dcflush(dre, sizeof(BD));
288
/*		ctlr->fcc->ftodr = 1<<15;	/* transmit now; Don't do this according to errata */
289
		ctlr->ntq++;
290
		ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
291
	}
292
}
293
 
294
static void
295
transmit(Ether* ether)
296
{
297
	Ctlr *ctlr;
298
 
299
	ctlr = ether->ctlr;
300
	ilock(ctlr);
301
	txstart(ether);
302
	iunlock(ctlr);
303
}
304
 
305
static void
306
interrupt(Ureg*, void *arg)
307
{
308
	int len, status, rcvd, xmtd, restart;
309
	ushort events;
310
	Ctlr *ctlr;
311
	BD *dre;
312
	Block *b, *nb;
313
	Ether *ether = arg;
314
 
315
	ctlr = ether->ctlr;
316
	if(!ctlr->active)
317
		return;	/* not ours */
318
 
319
	/*
320
	 * Acknowledge all interrupts and whine about those that shouldn't
321
	 * happen.
322
	 */
323
	events = ctlr->fcc->fcce;
324
	ctlr->fcc->fcce = events;		/* clear events */
325
 
326
#ifdef DBG
327
	ehisto[events & 0x7f]++;
328
#endif
329
 
330
	ctlr->interrupts++;
331
 
332
	if(events & BSY)
333
		ctlr->overrun++;
334
	if(events & TXE)
335
		ether->oerrs++;
336
 
337
#ifdef DBG
338
	rcvd = xmtd = 0;
339
#endif
340
	/*
341
	 * Receiver interrupt: run round the descriptor ring logging
342
	 * errors and passing valid receive data up to the higher levels
343
	 * until we encounter a descriptor still owned by the chip.
344
	 */
345
	if(events & RXF){
346
		dre = &ctlr->rdr[ctlr->rdrx];
347
		dczap(dre, sizeof(BD));
348
		while(((status = dre->status) & BDEmpty) == 0){
349
			rcvd++;
350
			if(status & RxError || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){
351
				if(status & (RxeLG|RxeSH))
352
					ether->buffs++;
353
				if(status & RxeNO)
354
					ether->frames++;
355
				if(status & RxeCR)
356
					ether->crcs++;
357
				if(status & RxeOV)
358
					ether->overflows++;
359
				print("eth rx: %ux\n", status);
360
			}else{
361
				/*
362
				 * We have a packet. Read it in.
363
				 */
364
				len = dre->length-4;
365
				b = ctlr->rcvbufs[ctlr->rdrx];
366
				assert(dre->addr == PADDR(b->rp));
367
				dczap(b->rp, len);
368
				if(nb = iallocb(Bufsize)){
369
					b->wp += len;
370
					etheriq(ether, b, 1);
371
					b = nb;
372
					b->rp = (uchar*)(((ulong)b->rp + CACHELINESZ-1) & ~(CACHELINESZ-1));
373
					b->wp = b->rp;
374
					ctlr->rcvbufs[ctlr->rdrx] = b;
375
					ctlr->rdr[ctlr->rdrx].addr = PADDR(b->wp);
376
				}else
377
					ether->soverflows++;
378
			}
379
 
380
			/*
381
			 * Finished with this descriptor, reinitialise it,
382
			 * give it back to the chip, then on to the next...
383
			 */
384
			dre->length = 0;
385
			dre->status = (status & BDWrap) | BDEmpty | BDInt;
386
			dcflush(dre, sizeof(BD));
387
 
388
			ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
389
			dre = &ctlr->rdr[ctlr->rdrx];
390
			dczap(dre, sizeof(BD));
391
		}
392
	}
393
 
394
	/*
395
	 * Transmitter interrupt: handle anything queued for a free descriptor.
396
	 */
397
	if(events & (TXB|TXE)){
398
		ilock(ctlr);
399
		restart = 0;
400
		while(ctlr->ntq){
401
			dre = &ctlr->tdr[ctlr->tdri];
402
			dczap(dre, sizeof(BD));
403
			status = dre->status;
404
			if(status & BDReady)
405
				break;
406
			if(status & TxeDEF)
407
				ctlr->deferred++;
408
			if(status & TxeHB)
409
				ctlr->heartbeat++;
410
			if(status & TxeLC)
411
				ctlr->latecoll++;
412
			if(status & TxeRL)
413
				ctlr->retrylim++;
414
			if(status & TxeUN)
415
				ctlr->underrun++;
416
			if(status & TxeCSL)
417
				ctlr->carrierlost++;
418
			if(status & (TxeLC|TxeRL|TxeUN))
419
				restart = 1;
420
			ctlr->retrycount += (status>>2)&0xF;
421
			b = ctlr->txb[ctlr->tdri];
422
			if(b == nil)
423
				panic("fcce/interrupt: bufp");
424
			ctlr->txb[ctlr->tdri] = nil;
425
			freeb(b);
426
			ctlr->ntq--;
427
			ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
428
			xmtd++;
429
		}
430
 
431
		if(restart){
432
			ctlr->fcc->gfmr &= ~ENT;
433
			delay(10);
434
			ctlr->fcc->gfmr |= ENT;
435
			cpmop(RestartTx, ctlr->fccid, 0xc);
436
		}
437
		txstart(ether);
438
		iunlock(ctlr);
439
	}
440
#ifdef DBG
441
	if(rcvd >= nelem(fccrhisto))
442
		rcvd = nelem(fccrhisto) - 1;
443
	if(xmtd >= nelem(fccthisto))
444
		xmtd = nelem(fccthisto) - 1;
445
	if(rcvd)
446
		fcctrhisto[xmtd]++;
447
	else
448
		fccthisto[xmtd]++;
449
	if(xmtd)
450
		fccrthisto[rcvd]++;
451
	else
452
		fccrhisto[rcvd]++;
453
#endif
454
}
455
 
456
static long
457
ifstat(Ether* ether, void* a, long n, ulong offset)
458
{
459
	char *p;
460
	int len, i, r;
461
	Ctlr *ctlr;
462
	MiiPhy *phy;
463
 
464
	if(n == 0)
465
		return 0;
466
 
467
	ctlr = ether->ctlr;
468
 
469
	p = malloc(READSTR);
470
	len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts);
471
	len += snprint(p+len, READSTR-len, "carrierlost: %lud\n", ctlr->carrierlost);
472
	len += snprint(p+len, READSTR-len, "heartbeat: %lud\n", ctlr->heartbeat);
473
	len += snprint(p+len, READSTR-len, "retrylimit: %lud\n", ctlr->retrylim);
474
	len += snprint(p+len, READSTR-len, "retrycount: %lud\n", ctlr->retrycount);
475
	len += snprint(p+len, READSTR-len, "latecollisions: %lud\n", ctlr->latecoll);
476
	len += snprint(p+len, READSTR-len, "rxoverruns: %lud\n", ctlr->overrun);
477
	len += snprint(p+len, READSTR-len, "txunderruns: %lud\n", ctlr->underrun);
478
	len += snprint(p+len, READSTR-len, "framesdeferred: %lud\n", ctlr->deferred);
479
	miistatus(ctlr->mii);
480
	phy = ctlr->mii->curphy;
481
	len += snprint(p+len, READSTR-len, "phy: link=%d, tfc=%d, rfc=%d, speed=%d, fd=%d\n",
482
		phy->link, phy->tfc, phy->rfc, phy->speed, phy->fd);
483
 
484
#ifdef DBG
485
	if(ctlr->mii != nil && ctlr->mii->curphy != nil){
486
		len += snprint(p+len, READSTR, "phy:   ");
487
		for(i = 0; i < NMiiPhyr; i++){
488
			if(i && ((i & 0x07) == 0))
489
				len += snprint(p+len, READSTR-len, "\n       ");
490
			r = miimir(ctlr->mii, i);
491
			len += snprint(p+len, READSTR-len, " %4.4uX", r);
492
		}
493
		snprint(p+len, READSTR-len, "\n");
494
	}
495
#endif
496
	snprint(p+len, READSTR-len, "\n");
497
 
498
	n = readstr(offset, a, n, p);
499
	free(p);
500
 
501
	return n;
502
}
503
 
504
IMM* imm;
505
 
506
/*
507
 * This follows the MPC8260 user guide: section28.9's initialisation sequence.
508
 */
509
static int
510
fccsetup(Ctlr *ctlr, FCC *fcc, uchar *ea)
511
{
512
	int i;
513
	Etherparam *p;
514
	MiiPhy *phy;
515
 
516
	/* Turn Ethernet off */
517
	fcc->gfmr &= ~(ENR | ENT);
518
 
519
	ioplock();
520
	switch(ctlr->port) {
521
	default:
522
		iopunlock();
523
		return -1;
524
	case 0:
525
		/* Step 1 (Section 28.9), write the parallel ports */
526
		ctlr->pmdio = 0x01000000;
527
		ctlr->pmdck = 0x08000000;
528
		imm->port[0].pdir &= ~A1dir0;
529
		imm->port[0].pdir |= A1dir1;
530
		imm->port[0].psor &= ~A1psor0;
531
		imm->port[0].psor |= A1psor1;
532
		imm->port[0].ppar |= (A1dir0 | A1dir1);
533
		/* Step 2, Port C clocks */
534
		imm->port[2].psor &= ~0x00000c00;
535
		imm->port[2].pdir &= ~0x00000c00;
536
		imm->port[2].ppar |= 0x00000c00;
537
		imm->port[3].pdat |= (ctlr->pmdio | ctlr->pmdck);
538
		imm->port[3].podr |= ctlr->pmdio;
539
		imm->port[3].pdir |= (ctlr->pmdio | ctlr->pmdck);
540
		imm->port[3].ppar &= ~(ctlr->pmdio | ctlr->pmdck);
541
		eieio();
542
		/* Step 3, Serial Interface clock routing */
543
		imm->cmxfcr &= ~0xff000000;	/* Clock mask */
544
		imm->cmxfcr |= 0x37000000;	/* Clock route */
545
		break;
546
 
547
	case 1:
548
		/* Step 1 (Section 28.9), write the parallel ports */
549
		ctlr->pmdio = 0x00400000;
550
		ctlr->pmdck = 0x00200000;
551
		imm->port[1].pdir &= ~B2dir0;
552
		imm->port[1].pdir |= B2dir1;
553
		imm->port[1].psor &= ~B2psor0;
554
		imm->port[1].psor |= B2psor1;
555
		imm->port[1].ppar |= (B2dir0 | B2dir1);
556
		/* Step 2, Port C clocks */
557
		imm->port[2].psor &= ~0x00003000;
558
		imm->port[2].pdir &= ~0x00003000;
559
		imm->port[2].ppar |= 0x00003000;
560
 
561
		imm->port[2].pdat |= (ctlr->pmdio | ctlr->pmdck);
562
		imm->port[2].podr |= ctlr->pmdio;
563
		imm->port[2].pdir |= (ctlr->pmdio | ctlr->pmdck);
564
		imm->port[2].ppar &= ~(ctlr->pmdio | ctlr->pmdck);
565
		eieio();
566
		/* Step 3, Serial Interface clock routing */
567
		imm->cmxfcr &= ~0x00ff0000;
568
		imm->cmxfcr |= 0x00250000;
569
		break;
570
 
571
	case 2:
572
		/* Step 1 (Section 28.9), write the parallel ports */
573
		imm->port[1].pdir &= ~B3dir0;
574
		imm->port[1].pdir |= B3dir1;
575
		imm->port[1].psor &= ~B3psor0;
576
		imm->port[1].psor |= B3psor1;
577
		imm->port[1].ppar |= (B3dir0 | B3dir1);
578
		/* Step 2, Port C clocks */
579
		imm->port[2].psor &= ~0x0000c000;
580
		imm->port[2].pdir &= ~0x0000c000;
581
		imm->port[2].ppar |= 0x0000c000;
582
		imm->port[3].pdat |= (ctlr->pmdio | ctlr->pmdck);
583
		imm->port[3].podr |= ctlr->pmdio;
584
		imm->port[3].pdir |= (ctlr->pmdio | ctlr->pmdck);
585
		imm->port[3].ppar &= ~(ctlr->pmdio | ctlr->pmdck);
586
		eieio();
587
		/* Step 3, Serial Interface clock routing */
588
		imm->cmxfcr &= ~0x0000ff00;
589
		imm->cmxfcr |= 0x00003700;
590
		break;
591
	}
592
	iopunlock();
593
 
594
	p = (Etherparam*)(m->immr->prmfcc + ctlr->port);
595
	memset(p, 0, sizeof(Etherparam));
596
 
597
	/* Step 4 */
598
	fcc->gfmr |= ENET;
599
 
600
	/* Step 5 */
601
	fcc->fpsmr = CRCE | FDE | LPB;	/* full duplex operation */
602
	ctlr->duplex = ~0;
603
 
604
	/* Step 6 */
605
	fcc->fdsr = 0xd555;
606
 
607
	/* Step 7, initialize parameter ram */
608
	p->rbase = PADDR(ctlr->rdr);
609
	p->tbase = PADDR(ctlr->tdr);
610
	p->rstate = (GBL | EB) << 24;
611
	p->tstate = (GBL | EB) << 24;
612
 
613
	p->cmask = 0xdebb20e3;
614
	p->cpres = 0xffffffff;
615
 
616
	p->retlim = 15;	/* retry limit */
617
 
618
	p->mrblr = (Rbsize+0x1f)&~0x1f;		/* multiple of 32 */
619
	p->mflr = Rbsize;
620
	p->minflr = ETHERMINTU;
621
	p->maxd1 = (Rbsize+7) & ~7;
622
	p->maxd2 = (Rbsize+7) & ~7;
623
 
624
	for(i=0; i<Eaddrlen; i+=2)
625
		p->paddr[2-i/2] = (ea[i+1]<<8)|ea[i];
626
 
627
	/* Step 7, initialize parameter ram, configuration-dependent values */
628
	p->riptr = m->immr->fccextra[ctlr->port].ri - (uchar*)IMMR;
629
	p->tiptr = m->immr->fccextra[ctlr->port].ti - (uchar*)IMMR;
630
	p->padptr = m->immr->fccextra[ctlr->port].pad - (uchar*)IMMR;
631
	memset(m->immr->fccextra[ctlr->port].pad, 0x88, 0x20);
632
 
633
	/* Step 8, clear out events */
634
	fcc->fcce = ~0;
635
 
636
	/* Step 9, Interrupt enable */
637
	fcc->fccm = TXE | RXF | TXB;
638
 
639
	/* Step 10, Configure interrupt priority (not done here) */
640
	/* Step 11, Clear out current events */
641
	/* Step 12, Enable interrupts to the CP interrupt controller */
642
 
643
	/* Step 13, Issue the Init Tx and Rx command, specifying 0xc for ethernet*/
644
	cpmop(InitRxTx, fccid[ctlr->port], 0xc);
645
 
646
	/* Step 14, Link management */
647
	if((ctlr->mii = malloc(sizeof(Mii))) == nil)
648
		return -1;
649
	ctlr->mii->mir = fccmiimir;
650
	ctlr->mii->miw = fccmiimiw;
651
	ctlr->mii->ctlr = ctlr;
652
 
653
	if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
654
		free(ctlr->mii);
655
		ctlr->mii = nil;
656
		return -1;
657
	}
658
	miiane(ctlr->mii, ~0, ~0, ~0);
659
#ifdef DBG
660
	print("oui=%X, phyno=%d, ", phy->oui, phy->phyno);
661
	print("anar=%ux, ", phy->anar);
662
	print("fc=%ux, ", phy->fc);
663
	print("mscr=%ux, ", phy->mscr);
664
 
665
	print("link=%ux, ", phy->link);
666
	print("speed=%ux, ", phy->speed);
667
	print("fd=%ux, ", phy->fd);
668
	print("rfc=%ux, ", phy->rfc);
669
	print("tfc=%ux\n", phy->tfc);
670
#endif
671
	/* Step 15, Enable ethernet: done at attach time */
672
	return 0;
673
}
674
 
675
static int
676
reset(Ether* ether)
677
{
678
	uchar ea[Eaddrlen];
679
	Ctlr *ctlr;
680
	FCC *fcc;
681
	Block *b;
682
	int i;
683
 
684
	if(m->cpuhz < 24000000){
685
		print("%s ether: system speed must be >= 24MHz for ether use\n", ether->type);
686
		return -1;
687
	}
688
 
689
	if(ether->port > 3){
690
		print("%s ether: no FCC port %ld\n", ether->type, ether->port);
691
		return -1;
692
	}
693
	ether->irq = fccirq[ether->port];
694
	ether->tbdf = BusPPC;
695
	fcc = imm->fcc + ether->port;
696
 
697
	ctlr = malloc(sizeof(*ctlr));
698
	ether->ctlr = ctlr;
699
	memset(ctlr, 0, sizeof(*ctlr));
700
	ctlr->fcc = fcc;
701
	ctlr->port = ether->port;
702
	ctlr->fccid = fccid[ether->port];
703
 
704
	/* Ioringinit will allocate the buffer descriptors in normal memory
705
	 * and NOT in Dual-Ported Ram, as prescribed by the MPC8260
706
	 * PowerQUICC II manual (Section 28.6).  When they are allocated
707
	 * in DPram and the Dcache is enabled, the processor will hang
708
	 */
709
	if(ioringinit(ctlr, Nrdre, Ntdre, 0) < 0)
710
		panic("etherfcc init");
711
	for(i = 0; i < Nrdre; i++){
712
		b = iallocb(Bufsize);
713
		b->rp = (uchar*)(((ulong)b->rp + CACHELINESZ-1) & ~(CACHELINESZ-1));
714
		b->wp = b->rp;
715
		ctlr->rcvbufs[i] = b;
716
		ctlr->rdr[i].addr = PADDR(b->wp);
717
	}
718
 
719
	fccsetup(ctlr, fcc, ether->ea);
720
 
721
	ether->mbps = 100;	/* TO DO: could be 10mbps */
722
	ether->attach = attach;
723
	ether->transmit = transmit;
724
	ether->interrupt = interrupt;
725
	ether->ifstat = ifstat;
726
 
727
	ether->arg = ether;
728
	ether->promiscuous = promiscuous;
729
	ether->multicast = multicast;
730
 
731
	/*
732
	 * Until we know where to find it, insist that the plan9.ini
733
	 * entry holds the Ethernet address.
734
	 */
735
	memset(ea, 0, Eaddrlen);
736
	if(memcmp(ea, ether->ea, Eaddrlen) == 0){
737
		print("no ether address");
738
		return -1;
739
	}
740
 
741
	return 0;
742
}
743
 
744
void
745
etherfcclink(void)
746
{
747
	addethercard("fcc", reset);
748
}
749
 
750
static void
751
nanodelay(void)
752
{
753
	static int count;
754
	int i;
755
 
756
	for(i = 0; i < 500; i++)
757
		count++;
758
	return;
759
}
760
 
761
static
762
void miiwriteloop(Ctlr *ctlr, Port *port, int cnt, ulong cmd)
763
{
764
	int i;
765
 
766
	for(i = 0; i < cnt; i++){
767
		port->pdat &= ~ctlr->pmdck;
768
		if(cmd & BIT(i))
769
			port->pdat |= ctlr->pmdio;
770
		else
771
			port->pdat &= ~ctlr->pmdio;
772
		nanodelay();
773
		port->pdat |= ctlr->pmdck;
774
		nanodelay();
775
	}
776
}
777
 
778
static int
779
fccmiimiw(Mii *mii, int pa, int ra, int data)
780
{
781
	int x;
782
	Port *port;
783
	ulong cmd;
784
	Ctlr *ctlr;
785
 
786
	/*
787
	 * MII Management Interface Write.
788
	 */
789
 
790
	ctlr = mii->ctlr;
791
	port = imm->port + 3;
792
	cmd = MDIwrite | (pa<<(5+2+16))| (ra<<(2+16)) | (data & 0xffff);
793
 
794
	x = splhi();
795
 
796
	port->pdir |= (ctlr->pmdio|ctlr->pmdck);
797
	nanodelay();
798
 
799
	miiwriteloop(ctlr, port, 32, ~0);
800
	miiwriteloop(ctlr, port, 32, cmd);
801
 
802
	port->pdir |= (ctlr->pmdio|ctlr->pmdck);
803
	nanodelay();
804
 
805
	miiwriteloop(ctlr, port, 32, ~0);
806
 
807
	splx(x);
808
	return 1;
809
}
810
 
811
static int
812
fccmiimir(Mii *mii, int pa, int ra)
813
{
814
	int data, i, x;
815
	Port *port;
816
	ulong cmd;
817
	Ctlr *ctlr;
818
 
819
	ctlr = mii->ctlr;
820
	port = imm->port + 3;
821
 
822
	cmd = MDIread | pa<<(5+2+16) | ra<<(2+16);
823
 
824
	x = splhi();
825
	port->pdir |= (ctlr->pmdio|ctlr->pmdck);
826
	nanodelay();
827
 
828
	miiwriteloop(ctlr, port, 32, ~0);
829
 
830
	/* Clock out the first 14 MS bits of the command */
831
	miiwriteloop(ctlr, port, 14, cmd);
832
 
833
	/* Turn-around */
834
	port->pdat &= ~ctlr->pmdck;
835
	port->pdir &= ~ctlr->pmdio;
836
	nanodelay();
837
 
838
	/* For read, clock in 18 bits, use 16 */
839
	data = 0;
840
	for(i=0; i<18; i++){
841
		data <<= 1;
842
		if(port->pdat & ctlr->pmdio)
843
			data |= 1;
844
		port->pdat |= ctlr->pmdck;
845
		nanodelay();
846
		port->pdat &= ~ctlr->pmdck;
847
		nanodelay();
848
	}
849
	port->pdir |= (ctlr->pmdio|ctlr->pmdck);
850
	nanodelay();
851
	miiwriteloop(ctlr, port, 32, ~0);
852
	splx(x);
853
	return data & 0xffff;
854
}
855
 
856
static void
857
fccltimer(Ureg*, Timer *t)
858
{
859
	Ether *ether;
860
	Ctlr *ctlr;
861
	MiiPhy *phy;
862
	ulong gfmr;
863
 
864
	ether = t->ta;
865
	ctlr = ether->ctlr;
866
	if(ctlr->mii == nil || ctlr->mii->curphy == nil)
867
		return;
868
	phy = ctlr->mii->curphy;
869
	if(miistatus(ctlr->mii) < 0){
870
		print("miistatus failed\n");
871
		return;
872
	}
873
	if(phy->link == 0){
874
		print("link lost\n");
875
		return;
876
	}
877
	ether->mbps = phy->speed;
878
 
879
	if(phy->fd != ctlr->duplex)
880
		print("set duplex\n");
881
	ilock(ctlr);
882
	gfmr = ctlr->fcc->gfmr;
883
	if(phy->fd != ctlr->duplex){
884
		ctlr->fcc->gfmr &= ~(ENR|ENT);
885
		if(phy->fd)
886
			ctlr->fcc->fpsmr |= FDE | LPB;		/* full duplex operation */
887
		else
888
			ctlr->fcc->fpsmr &= ~(FDE | LPB);	/* half duplex operation */
889
		ctlr->duplex = phy->fd;
890
	}
891
	ctlr->fcc->gfmr = gfmr;
892
	iunlock(ctlr);
893
}