]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ppc/etherfcc.c
audiohda: fix syntax error
[plan9front.git] / sys / src / 9 / 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 #include "../port/etherif.h"
15
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);
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->ifstat = ifstat;
723
724         ether->arg = ether;
725         ether->promiscuous = promiscuous;
726         ether->multicast = multicast;
727
728         /*
729          * Until we know where to find it, insist that the plan9.ini
730          * entry holds the Ethernet address.
731          */
732         memset(ea, 0, Eaddrlen);
733         if(memcmp(ea, ether->ea, Eaddrlen) == 0){
734                 print("no ether address");
735                 return -1;
736         }
737
738         intrenable(ether->irq, interrupt, ether, ether->name);
739
740         return 0;
741 }
742
743 void
744 etherfcclink(void)
745 {
746         addethercard("fcc", reset);
747 }
748
749 static void
750 nanodelay(void)
751 {
752         static int count;
753         int i;
754
755         for(i = 0; i < 500; i++)
756                 count++;
757         return;
758 }
759
760 static
761 void miiwriteloop(Ctlr *ctlr, Port *port, int cnt, ulong cmd)
762 {
763         int i;
764
765         for(i = 0; i < cnt; i++){
766                 port->pdat &= ~ctlr->pmdck;
767                 if(cmd & BIT(i))
768                         port->pdat |= ctlr->pmdio;
769                 else
770                         port->pdat &= ~ctlr->pmdio;
771                 nanodelay();
772                 port->pdat |= ctlr->pmdck;
773                 nanodelay();
774         }
775 }
776
777 static int
778 fccmiimiw(Mii *mii, int pa, int ra, int data)
779 {
780         int x;
781         Port *port;
782         ulong cmd;
783         Ctlr *ctlr;
784
785         /*
786          * MII Management Interface Write.
787          */
788
789         ctlr = mii->ctlr;
790         port = imm->port + 3;
791         cmd = MDIwrite | (pa<<(5+2+16))| (ra<<(2+16)) | (data & 0xffff);
792
793         x = splhi();
794
795         port->pdir |= (ctlr->pmdio|ctlr->pmdck);
796         nanodelay();
797
798         miiwriteloop(ctlr, port, 32, ~0);
799         miiwriteloop(ctlr, port, 32, cmd);
800
801         port->pdir |= (ctlr->pmdio|ctlr->pmdck);
802         nanodelay();
803
804         miiwriteloop(ctlr, port, 32, ~0);
805
806         splx(x);
807         return 1;
808 }
809
810 static int
811 fccmiimir(Mii *mii, int pa, int ra)
812 {
813         int data, i, x;
814         Port *port;
815         ulong cmd;
816         Ctlr *ctlr;
817
818         ctlr = mii->ctlr;
819         port = imm->port + 3;
820
821         cmd = MDIread | pa<<(5+2+16) | ra<<(2+16);
822
823         x = splhi();
824         port->pdir |= (ctlr->pmdio|ctlr->pmdck);
825         nanodelay();
826
827         miiwriteloop(ctlr, port, 32, ~0);
828
829         /* Clock out the first 14 MS bits of the command */
830         miiwriteloop(ctlr, port, 14, cmd);
831
832         /* Turn-around */
833         port->pdat &= ~ctlr->pmdck;
834         port->pdir &= ~ctlr->pmdio;
835         nanodelay();
836
837         /* For read, clock in 18 bits, use 16 */
838         data = 0;
839         for(i=0; i<18; i++){
840                 data <<= 1;
841                 if(port->pdat & ctlr->pmdio)
842                         data |= 1;
843                 port->pdat |= ctlr->pmdck;
844                 nanodelay();
845                 port->pdat &= ~ctlr->pmdck;
846                 nanodelay();
847         }
848         port->pdir |= (ctlr->pmdio|ctlr->pmdck);
849         nanodelay();
850         miiwriteloop(ctlr, port, 32, ~0);
851         splx(x);
852         return data & 0xffff;
853 }
854
855 static void
856 fccltimer(Ureg*, Timer *t)
857 {
858         Ether *ether;
859         Ctlr *ctlr;
860         MiiPhy *phy;
861         ulong gfmr;
862
863         ether = t->ta;
864         ctlr = ether->ctlr;
865         if(ctlr->mii == nil || ctlr->mii->curphy == nil)
866                 return;
867         phy = ctlr->mii->curphy;
868         if(miistatus(ctlr->mii) < 0){
869                 print("miistatus failed\n");
870                 return;
871         }
872         if(phy->link == 0){
873                 print("link lost\n");
874                 return;
875         }
876         ether->mbps = phy->speed;
877
878         if(phy->fd != ctlr->duplex)
879                 print("set duplex\n");
880         ilock(ctlr);
881         gfmr = ctlr->fcc->gfmr;
882         if(phy->fd != ctlr->duplex){
883                 ctlr->fcc->gfmr &= ~(ENR|ENT);
884                 if(phy->fd)
885                         ctlr->fcc->fpsmr |= FDE | LPB;          /* full duplex operation */
886                 else
887                         ctlr->fcc->fpsmr &= ~(FDE | LPB);       /* half duplex operation */
888                 ctlr->duplex = phy->fd;
889         }
890         ctlr->fcc->gfmr = gfmr;
891         iunlock(ctlr);
892 }