The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ppc/etherfcc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.