FreeBSD/Linux Kernel Cross Reference
sys/ppc/etherfcc.c
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 /*
505 * This follows the MPC8260 user guide: section28.9's initialisation sequence.
506 */
507 static int
508 fccsetup(Ctlr *ctlr, FCC *fcc, uchar *ea)
509 {
510 int i;
511 Etherparam *p;
512 MiiPhy *phy;
513
514 /* Turn Ethernet off */
515 fcc->gfmr &= ~(ENR | ENT);
516
517 ioplock();
518 switch(ctlr->port) {
519 default:
520 iopunlock();
521 return -1;
522 case 0:
523 /* Step 1 (Section 28.9), write the parallel ports */
524 ctlr->pmdio = 0x01000000;
525 ctlr->pmdck = 0x08000000;
526 imm->port[0].pdir &= ~A1dir0;
527 imm->port[0].pdir |= A1dir1;
528 imm->port[0].psor &= ~A1psor0;
529 imm->port[0].psor |= A1psor1;
530 imm->port[0].ppar |= (A1dir0 | A1dir1);
531 /* Step 2, Port C clocks */
532 imm->port[2].psor &= ~0x00000c00;
533 imm->port[2].pdir &= ~0x00000c00;
534 imm->port[2].ppar |= 0x00000c00;
535 imm->port[3].pdat |= (ctlr->pmdio | ctlr->pmdck);
536 imm->port[3].podr |= ctlr->pmdio;
537 imm->port[3].pdir |= (ctlr->pmdio | ctlr->pmdck);
538 imm->port[3].ppar &= ~(ctlr->pmdio | ctlr->pmdck);
539 eieio();
540 /* Step 3, Serial Interface clock routing */
541 imm->cmxfcr &= ~0xff000000; /* Clock mask */
542 imm->cmxfcr |= 0x37000000; /* Clock route */
543 break;
544
545 case 1:
546 /* Step 1 (Section 28.9), write the parallel ports */
547 ctlr->pmdio = 0x00400000;
548 ctlr->pmdck = 0x00200000;
549 imm->port[1].pdir &= ~B2dir0;
550 imm->port[1].pdir |= B2dir1;
551 imm->port[1].psor &= ~B2psor0;
552 imm->port[1].psor |= B2psor1;
553 imm->port[1].ppar |= (B2dir0 | B2dir1);
554 /* Step 2, Port C clocks */
555 imm->port[2].psor &= ~0x00003000;
556 imm->port[2].pdir &= ~0x00003000;
557 imm->port[2].ppar |= 0x00003000;
558
559 imm->port[2].pdat |= (ctlr->pmdio | ctlr->pmdck);
560 imm->port[2].podr |= ctlr->pmdio;
561 imm->port[2].pdir |= (ctlr->pmdio | ctlr->pmdck);
562 imm->port[2].ppar &= ~(ctlr->pmdio | ctlr->pmdck);
563 eieio();
564 /* Step 3, Serial Interface clock routing */
565 imm->cmxfcr &= ~0x00ff0000;
566 imm->cmxfcr |= 0x00250000;
567 break;
568
569 case 2:
570 /* Step 1 (Section 28.9), write the parallel ports */
571 imm->port[1].pdir &= ~B3dir0;
572 imm->port[1].pdir |= B3dir1;
573 imm->port[1].psor &= ~B3psor0;
574 imm->port[1].psor |= B3psor1;
575 imm->port[1].ppar |= (B3dir0 | B3dir1);
576 /* Step 2, Port C clocks */
577 imm->port[2].psor &= ~0x0000c000;
578 imm->port[2].pdir &= ~0x0000c000;
579 imm->port[2].ppar |= 0x0000c000;
580 imm->port[3].pdat |= (ctlr->pmdio | ctlr->pmdck);
581 imm->port[3].podr |= ctlr->pmdio;
582 imm->port[3].pdir |= (ctlr->pmdio | ctlr->pmdck);
583 imm->port[3].ppar &= ~(ctlr->pmdio | ctlr->pmdck);
584 eieio();
585 /* Step 3, Serial Interface clock routing */
586 imm->cmxfcr &= ~0x0000ff00;
587 imm->cmxfcr |= 0x00003700;
588 break;
589 }
590 iopunlock();
591
592 p = (Etherparam*)(m->immr->prmfcc + ctlr->port);
593 memset(p, 0, sizeof(Etherparam));
594
595 /* Step 4 */
596 fcc->gfmr |= ENET;
597
598 /* Step 5 */
599 fcc->fpsmr = CRCE | FDE | LPB; /* full duplex operation */
600 ctlr->duplex = ~0;
601
602 /* Step 6 */
603 fcc->fdsr = 0xd555;
604
605 /* Step 7, initialize parameter ram */
606 p->rbase = PADDR(ctlr->rdr);
607 p->tbase = PADDR(ctlr->tdr);
608 p->rstate = (GBL | EB) << 24;
609 p->tstate = (GBL | EB) << 24;
610
611 p->cmask = 0xdebb20e3;
612 p->cpres = 0xffffffff;
613
614 p->retlim = 15; /* retry limit */
615
616 p->mrblr = (Rbsize+0x1f)&~0x1f; /* multiple of 32 */
617 p->mflr = Rbsize;
618 p->minflr = ETHERMINTU;
619 p->maxd1 = (Rbsize+7) & ~7;
620 p->maxd2 = (Rbsize+7) & ~7;
621
622 for(i=0; i<Eaddrlen; i+=2)
623 p->paddr[2-i/2] = (ea[i+1]<<8)|ea[i];
624
625 /* Step 7, initialize parameter ram, configuration-dependent values */
626 p->riptr = m->immr->fccextra[ctlr->port].ri - (uchar*)IMMR;
627 p->tiptr = m->immr->fccextra[ctlr->port].ti - (uchar*)IMMR;
628 p->padptr = m->immr->fccextra[ctlr->port].pad - (uchar*)IMMR;
629 memset(m->immr->fccextra[ctlr->port].pad, 0x88, 0x20);
630
631 /* Step 8, clear out events */
632 fcc->fcce = ~0;
633
634 /* Step 9, Interrupt enable */
635 fcc->fccm = TXE | RXF | TXB;
636
637 /* Step 10, Configure interrupt priority (not done here) */
638 /* Step 11, Clear out current events */
639 /* Step 12, Enable interrupts to the CP interrupt controller */
640
641 /* Step 13, Issue the Init Tx and Rx command, specifying 0xc for ethernet*/
642 cpmop(InitRxTx, fccid[ctlr->port], 0xc);
643
644 /* Step 14, Link management */
645 if((ctlr->mii = malloc(sizeof(Mii))) == nil)
646 return -1;
647 ctlr->mii->mir = fccmiimir;
648 ctlr->mii->miw = fccmiimiw;
649 ctlr->mii->ctlr = ctlr;
650
651 if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
652 free(ctlr->mii);
653 ctlr->mii = nil;
654 return -1;
655 }
656 miiane(ctlr->mii, ~0, ~0, ~0);
657 #ifdef DBG
658 print("oui=%X, phyno=%d, ", phy->oui, phy->phyno);
659 print("anar=%ux, ", phy->anar);
660 print("fc=%ux, ", phy->fc);
661 print("mscr=%ux, ", phy->mscr);
662
663 print("link=%ux, ", phy->link);
664 print("speed=%ux, ", phy->speed);
665 print("fd=%ux, ", phy->fd);
666 print("rfc=%ux, ", phy->rfc);
667 print("tfc=%ux\n", phy->tfc);
668 #endif
669 /* Step 15, Enable ethernet: done at attach time */
670 return 0;
671 }
672
673 static int
674 reset(Ether* ether)
675 {
676 uchar ea[Eaddrlen];
677 Ctlr *ctlr;
678 FCC *fcc;
679 Block *b;
680 int i;
681
682 if(m->cpuhz < 24000000){
683 print("%s ether: system speed must be >= 24MHz for ether use\n", ether->type);
684 return -1;
685 }
686
687 if(ether->port > 3){
688 print("%s ether: no FCC port %ld\n", ether->type, ether->port);
689 return -1;
690 }
691 ether->irq = fccirq[ether->port];
692 ether->tbdf = BusPPC;
693 fcc = imm->fcc + ether->port;
694
695 ctlr = malloc(sizeof(*ctlr));
696 ether->ctlr = ctlr;
697 memset(ctlr, 0, sizeof(*ctlr));
698 ctlr->fcc = fcc;
699 ctlr->port = ether->port;
700 ctlr->fccid = fccid[ether->port];
701
702 /* Ioringinit will allocate the buffer descriptors in normal memory
703 * and NOT in Dual-Ported Ram, as prescribed by the MPC8260
704 * PowerQUICC II manual (Section 28.6). When they are allocated
705 * in DPram and the Dcache is enabled, the processor will hang
706 */
707 if(ioringinit(ctlr, Nrdre, Ntdre, 0) < 0)
708 panic("etherfcc init");
709 for(i = 0; i < Nrdre; i++){
710 b = iallocb(Bufsize);
711 b->rp = (uchar*)(((ulong)b->rp + CACHELINESZ-1) & ~(CACHELINESZ-1));
712 b->wp = b->rp;
713 ctlr->rcvbufs[i] = b;
714 ctlr->rdr[i].addr = PADDR(b->wp);
715 }
716
717 fccsetup(ctlr, fcc, ether->ea);
718
719 ether->mbps = 100; /* TO DO: could be 10mbps */
720 ether->attach = attach;
721 ether->transmit = transmit;
722 ether->interrupt = interrupt;
723 ether->ifstat = ifstat;
724
725 ether->arg = ether;
726 ether->promiscuous = promiscuous;
727 ether->multicast = multicast;
728
729 /*
730 * Until we know where to find it, insist that the plan9.ini
731 * entry holds the Ethernet address.
732 */
733 memset(ea, 0, Eaddrlen);
734 if(memcmp(ea, ether->ea, Eaddrlen) == 0){
735 print("no ether address");
736 return -1;
737 }
738
739 return 0;
740 }
741
742 void
743 etherfcclink(void)
744 {
745 addethercard("fcc", reset);
746 }
747
748 static void
749 nanodelay(void)
750 {
751 static int count;
752 int i;
753
754 for(i = 0; i < 500; i++)
755 count++;
756 return;
757 }
758
759 static
760 void miiwriteloop(Ctlr *ctlr, Port *port, int cnt, ulong cmd)
761 {
762 int i;
763
764 for(i = 0; i < cnt; i++){
765 port->pdat &= ~ctlr->pmdck;
766 if(cmd & BIT(i))
767 port->pdat |= ctlr->pmdio;
768 else
769 port->pdat &= ~ctlr->pmdio;
770 nanodelay();
771 port->pdat |= ctlr->pmdck;
772 nanodelay();
773 }
774 }
775
776 static int
777 fccmiimiw(Mii *mii, int pa, int ra, int data)
778 {
779 int x;
780 Port *port;
781 ulong cmd;
782 Ctlr *ctlr;
783
784 /*
785 * MII Management Interface Write.
786 */
787
788 ctlr = mii->ctlr;
789 port = imm->port + 3;
790 cmd = MDIwrite | (pa<<(5+2+16))| (ra<<(2+16)) | (data & 0xffff);
791
792 x = splhi();
793
794 port->pdir |= (ctlr->pmdio|ctlr->pmdck);
795 nanodelay();
796
797 miiwriteloop(ctlr, port, 32, ~0);
798 miiwriteloop(ctlr, port, 32, cmd);
799
800 port->pdir |= (ctlr->pmdio|ctlr->pmdck);
801 nanodelay();
802
803 miiwriteloop(ctlr, port, 32, ~0);
804
805 splx(x);
806 return 1;
807 }
808
809 static int
810 fccmiimir(Mii *mii, int pa, int ra)
811 {
812 int data, i, x;
813 Port *port;
814 ulong cmd;
815 Ctlr *ctlr;
816
817 ctlr = mii->ctlr;
818 port = imm->port + 3;
819
820 cmd = MDIread | pa<<(5+2+16) | ra<<(2+16);
821
822 x = splhi();
823 port->pdir |= (ctlr->pmdio|ctlr->pmdck);
824 nanodelay();
825
826 miiwriteloop(ctlr, port, 32, ~0);
827
828 /* Clock out the first 14 MS bits of the command */
829 miiwriteloop(ctlr, port, 14, cmd);
830
831 /* Turn-around */
832 port->pdat &= ~ctlr->pmdck;
833 port->pdir &= ~ctlr->pmdio;
834 nanodelay();
835
836 /* For read, clock in 18 bits, use 16 */
837 data = 0;
838 for(i=0; i<18; i++){
839 data <<= 1;
840 if(port->pdat & ctlr->pmdio)
841 data |= 1;
842 port->pdat |= ctlr->pmdck;
843 nanodelay();
844 port->pdat &= ~ctlr->pmdck;
845 nanodelay();
846 }
847 port->pdir |= (ctlr->pmdio|ctlr->pmdck);
848 nanodelay();
849 miiwriteloop(ctlr, port, 32, ~0);
850 splx(x);
851 return data & 0xffff;
852 }
853
854 static void
855 fccltimer(Ureg*, Timer *t)
856 {
857 Ether *ether;
858 Ctlr *ctlr;
859 MiiPhy *phy;
860 ulong gfmr;
861
862 ether = t->ta;
863 ctlr = ether->ctlr;
864 if(ctlr->mii == nil || ctlr->mii->curphy == nil)
865 return;
866 phy = ctlr->mii->curphy;
867 if(miistatus(ctlr->mii) < 0){
868 print("miistatus failed\n");
869 return;
870 }
871 if(phy->link == 0){
872 print("link lost\n");
873 return;
874 }
875 ether->mbps = phy->speed;
876
877 if(phy->fd != ctlr->duplex)
878 print("set duplex\n");
879 ilock(ctlr);
880 gfmr = ctlr->fcc->gfmr;
881 if(phy->fd != ctlr->duplex){
882 ctlr->fcc->gfmr &= ~(ENR|ENT);
883 if(phy->fd)
884 ctlr->fcc->fpsmr |= FDE | LPB; /* full duplex operation */
885 else
886 ctlr->fcc->fpsmr &= ~(FDE | LPB); /* half duplex operation */
887 ctlr->duplex = phy->fd;
888 }
889 ctlr->fcc->gfmr = gfmr;
890 iunlock(ctlr);
891 }
Cache object: c7bf98782043a98af483a46570c7c45b
|