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/pc/ether8390.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  * National Semiconductor DP8390 and clone
    3  * Network Interface Controller.
    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 "../port/error.h"
   12 #include "../port/netif.h"
   13 
   14 #include "etherif.h"
   15 #include "ether8390.h"
   16 
   17 enum {                                  /* NIC core registers */
   18         Cr              = 0x00,         /* command register, all pages */
   19 
   20                                         /* Page 0, read */
   21         Clda0           = 0x01,         /* current local DMA address 0 */
   22         Clda1           = 0x02,         /* current local DMA address 1 */
   23         Bnry            = 0x03,         /* boundary pointer (R/W) */
   24         Tsr             = 0x04,         /* transmit status register */
   25         Ncr             = 0x05,         /* number of collisions register */
   26         Fifo            = 0x06,         /* FIFO */
   27         Isr             = 0x07,         /* interrupt status register (R/W) */
   28         Crda0           = 0x08,         /* current remote DMA address 0 */
   29         Crda1           = 0x09,         /* current remote DMA address 1 */
   30         Rsr             = 0x0C,         /* receive status register */
   31         Ref0            = 0x0D,         /* frame alignment errors */
   32         Ref1            = 0x0E,         /* CRC errors */
   33         Ref2            = 0x0F,         /* missed packet errors */
   34 
   35                                         /* Page 0, write */
   36         Pstart          = 0x01,         /* page start register */
   37         Pstop           = 0x02,         /* page stop register */
   38         Tpsr            = 0x04,         /* transmit page start address */
   39         Tbcr0           = 0x05,         /* transmit byte count register 0 */
   40         Tbcr1           = 0x06,         /* transmit byte count register 1 */
   41         Rsar0           = 0x08,         /* remote start address register 0 */
   42         Rsar1           = 0x09,         /* remote start address register 1 */
   43         Rbcr0           = 0x0A,         /* remote byte count register 0 */
   44         Rbcr1           = 0x0B,         /* remote byte count register 1 */
   45         Rcr             = 0x0C,         /* receive configuration register */
   46         Tcr             = 0x0D,         /* transmit configuration register */
   47         Dcr             = 0x0E,         /* data configuration register */
   48         Imr             = 0x0F,         /* interrupt mask */
   49 
   50                                         /* Page 1, read/write */
   51         Par0            = 0x01,         /* physical address register 0 */
   52         Curr            = 0x07,         /* current page register */
   53         Mar0            = 0x08,         /* multicast address register 0 */
   54 };
   55 
   56 enum {                                  /* Cr */
   57         Stp             = 0x01,         /* stop */
   58         Sta             = 0x02,         /* start */
   59         Txp             = 0x04,         /* transmit packet */
   60         Rd0             = 0x08,         /* remote DMA command */
   61         Rd1             = 0x10, 
   62         Rd2             = 0x20,
   63         RdREAD          = Rd0,          /* remote read */
   64         RdWRITE         = Rd1,          /* remote write */
   65         RdSEND          = Rd1|Rd0,      /* send packet */
   66         RdABORT         = Rd2,          /* abort/complete remote DMA */
   67         Ps0             = 0x40,         /* page select */
   68         Ps1             = 0x80,
   69         Page0           = 0x00,
   70         Page1           = Ps0,
   71         Page2           = Ps1,
   72 };
   73 
   74 enum {                                  /* Isr/Imr */
   75         Prx             = 0x01,         /* packet received */
   76         Ptx             = 0x02,         /* packet transmitted */
   77         Rxe             = 0x04,         /* receive error */
   78         Txe             = 0x08,         /* transmit error */
   79         Ovw             = 0x10,         /* overwrite warning */
   80         Cnt             = 0x20,         /* counter overflow */
   81         Rdc             = 0x40,         /* remote DMA complete */
   82         Rst             = 0x80,         /* reset status */
   83 };
   84 
   85 enum {                                  /* Dcr */
   86         Wts             = 0x01,         /* word transfer select */
   87         Bos             = 0x02,         /* byte order select */
   88         Las             = 0x04,         /* long address select */
   89         Ls              = 0x08,         /* loopback select */
   90         Arm             = 0x10,         /* auto-initialise remote */
   91         Ft0             = 0x20,         /* FIFO threshold select */
   92         Ft1             = 0x40,
   93         Ft1WORD         = 0x00,
   94         Ft2WORD         = Ft0,
   95         Ft4WORD         = Ft1,
   96         Ft6WORD         = Ft1|Ft0,
   97 };
   98 
   99 enum {                                  /* Tcr */
  100         Crc             = 0x01,         /* inhibit CRC */
  101         Lb0             = 0x02,         /* encoded loopback control */
  102         Lb1             = 0x04,
  103         LpbkNORMAL      = 0x00,         /* normal operation */
  104         LpbkNIC         = Lb0,          /* internal NIC module loopback */
  105         LpbkENDEC       = Lb1,          /* internal ENDEC module loopback */
  106         LpbkEXTERNAL    = Lb1|Lb0,      /* external loopback */
  107         Atd             = 0x08,         /* auto transmit disable */
  108         Ofst            = 0x10,         /* collision offset enable */
  109 };
  110 
  111 enum {                                  /* Tsr */
  112         Ptxok           = 0x01,         /* packet transmitted */
  113         Col             = 0x04,         /* transmit collided */
  114         Abt             = 0x08,         /* tranmit aborted */
  115         Crs             = 0x10,         /* carrier sense lost */
  116         Fu              = 0x20,         /* FIFO underrun */
  117         Cdh             = 0x40,         /* CD heartbeat */
  118         Owc             = 0x80,         /* out of window collision */
  119 };
  120 
  121 enum {                                  /* Rcr */
  122         Sep             = 0x01,         /* save errored packets */
  123         Ar              = 0x02,         /* accept runt packets */
  124         Ab              = 0x04,         /* accept broadcast */
  125         Am              = 0x08,         /* accept multicast */
  126         Pro             = 0x10,         /* promiscuous physical */
  127         Mon             = 0x20,         /* monitor mode */
  128 };
  129 
  130 enum {                                  /* Rsr */
  131         Prxok           = 0x01,         /* packet received intact */
  132         Crce            = 0x02,         /* CRC error */
  133         Fae             = 0x04,         /* frame alignment error */
  134         Fo              = 0x08,         /* FIFO overrun */
  135         Mpa             = 0x10,         /* missed packet */
  136         Phy             = 0x20,         /* physical/multicast address */
  137         Dis             = 0x40,         /* receiver disabled */
  138         Dfr             = 0x80,         /* deferring */
  139 };
  140 
  141 typedef struct Hdr Hdr;
  142 struct Hdr {
  143         uchar   status;
  144         uchar   next;
  145         uchar   len0;
  146         uchar   len1;
  147 };
  148 
  149 void
  150 dp8390getea(Ether* ether, uchar* ea)
  151 {
  152         Dp8390 *ctlr;
  153         uchar cr;
  154         int i;
  155 
  156         ctlr = ether->ctlr;
  157 
  158         /*
  159          * Get the ethernet address from the chip.
  160          * Take care to restore the command register
  161          * afterwards.
  162          */
  163         ilock(ctlr);
  164         cr = regr(ctlr, Cr) & ~Txp;
  165         regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
  166         for(i = 0; i < Eaddrlen; i++)
  167                 ea[i] = regr(ctlr, Par0+i);
  168         regw(ctlr, Cr, cr);
  169         iunlock(ctlr);
  170 }
  171 
  172 void
  173 dp8390setea(Ether* ether)
  174 {
  175         int i;
  176         uchar cr;
  177         Dp8390 *ctlr;
  178 
  179         ctlr = ether->ctlr;
  180 
  181         /*
  182          * Set the ethernet address into the chip.
  183          * Take care to restore the command register
  184          * afterwards. Don't care about multicast
  185          * addresses as multicast is never enabled
  186          * (currently).
  187          */
  188         ilock(ctlr);
  189         cr = regr(ctlr, Cr) & ~Txp;
  190         regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
  191         for(i = 0; i < Eaddrlen; i++)
  192                 regw(ctlr, Par0+i, ether->ea[i]);
  193         regw(ctlr, Cr, cr);
  194         iunlock(ctlr);
  195 }
  196 
  197 static void*
  198 _dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len)
  199 {
  200         uchar cr;
  201         int timo;
  202 
  203         /*
  204          * Read some data at offset 'from' in the card's memory
  205          * using the DP8390 remote DMA facility, and place it at
  206          * 'to' in main memory, via the I/O data port.
  207          */
  208         cr = regr(ctlr, Cr) & ~Txp;
  209         regw(ctlr, Cr, Page0|RdABORT|Sta);
  210         regw(ctlr, Isr, Rdc);
  211 
  212         /*
  213          * Set up the remote DMA address and count.
  214          */
  215         len = ROUNDUP(len, ctlr->width);
  216         regw(ctlr, Rbcr0, len & 0xFF);
  217         regw(ctlr, Rbcr1, (len>>8) & 0xFF);
  218         regw(ctlr, Rsar0, from & 0xFF);
  219         regw(ctlr, Rsar1, (from>>8) & 0xFF);
  220 
  221         /*
  222          * Start the remote DMA read and suck the data
  223          * out of the I/O port.
  224          */
  225         regw(ctlr, Cr, Page0|RdREAD|Sta);
  226         rdread(ctlr, to, len);
  227 
  228         /*
  229          * Wait for the remote DMA to complete. The timeout
  230          * is necessary because this routine may be called on
  231          * a non-existent chip during initialisation and, due
  232          * to the miracles of the bus, it's possible to get this
  233          * far and still be talking to a slot full of nothing.
  234          */
  235         for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--)
  236                         ;
  237 
  238         regw(ctlr, Isr, Rdc);
  239         regw(ctlr, Cr, cr);
  240 
  241         return to;
  242 }
  243 
  244 void*
  245 dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len)
  246 {
  247         void *v;
  248 
  249         ilock(ctlr);
  250         v = _dp8390read(ctlr, to, from, len);
  251         iunlock(ctlr);
  252 
  253         return v;
  254 }
  255 
  256 static void*
  257 dp8390write(Dp8390* ctlr, ulong to, void* from, ulong len)
  258 {
  259         ulong crda;
  260         uchar cr;
  261         int timo, width;
  262 
  263 top:
  264         /*
  265          * Write some data to offset 'to' in the card's memory
  266          * using the DP8390 remote DMA facility, reading it at
  267          * 'from' in main memory, via the I/O data port.
  268          */
  269         cr = regr(ctlr, Cr) & ~Txp;
  270         regw(ctlr, Cr, Page0|RdABORT|Sta);
  271         regw(ctlr, Isr, Rdc);
  272 
  273         len = ROUNDUP(len, ctlr->width);
  274 
  275         /*
  276          * Set up the remote DMA address and count.
  277          * This is straight from the DP8390[12D] datasheet,
  278          * hence the initial set up for read.
  279          * Assumption here that the A7000 EtherV card will
  280          * never need a dummyrr.
  281          */
  282         if(ctlr->dummyrr && (ctlr->width == 1 || ctlr->width == 2)){
  283                 if(ctlr->width == 2)
  284                         width = 1;
  285                 else
  286                         width = 0;
  287                 crda = to-1-width;
  288                 regw(ctlr, Rbcr0, (len+1+width) & 0xFF);
  289                 regw(ctlr, Rbcr1, ((len+1+width)>>8) & 0xFF);
  290                 regw(ctlr, Rsar0, crda & 0xFF);
  291                 regw(ctlr, Rsar1, (crda>>8) & 0xFF);
  292                 regw(ctlr, Cr, Page0|RdREAD|Sta);
  293         
  294                 for(timo=0;; timo++){
  295                         if(timo > 10000){
  296                                 print("ether8390: dummyrr timeout; assuming nodummyrr\n");
  297                                 ctlr->dummyrr = 0;
  298                                 goto top;
  299                         }
  300                         crda = regr(ctlr, Crda0);
  301                         crda |= regr(ctlr, Crda1)<<8;
  302                         if(crda == to){
  303                                 /*
  304                                  * Start the remote DMA write and make sure
  305                                  * the registers are correct.
  306                                  */
  307                                 regw(ctlr, Cr, Page0|RdWRITE|Sta);
  308         
  309                                 crda = regr(ctlr, Crda0);
  310                                 crda |= regr(ctlr, Crda1)<<8;
  311                                 if(crda != to)
  312                                         panic("crda write %lud to %lud\n", crda, to);
  313         
  314                                 break;
  315                         }
  316                 }
  317         }
  318         else{
  319                 regw(ctlr, Rsar0, to & 0xFF);
  320                 regw(ctlr, Rsar1, (to>>8) & 0xFF);
  321                 regw(ctlr, Rbcr0, len & 0xFF);
  322                 regw(ctlr, Rbcr1, (len>>8) & 0xFF);
  323                 regw(ctlr, Cr, Page0|RdWRITE|Sta);
  324         }
  325 
  326         /*
  327          * Pump the data into the I/O port
  328          * then wait for the remote DMA to finish.
  329          */
  330         rdwrite(ctlr, from, len);
  331         for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--)
  332                         ;
  333 
  334         regw(ctlr, Isr, Rdc);
  335         regw(ctlr, Cr, cr);
  336 
  337         return (void*)to;
  338 }
  339 
  340 static void
  341 ringinit(Dp8390* ctlr)
  342 {
  343         regw(ctlr, Pstart, ctlr->pstart);
  344         regw(ctlr, Pstop, ctlr->pstop);
  345         regw(ctlr, Bnry, ctlr->pstop-1);
  346 
  347         regw(ctlr, Cr, Page1|RdABORT|Stp);
  348         regw(ctlr, Curr, ctlr->pstart);
  349         regw(ctlr, Cr, Page0|RdABORT|Stp);
  350 
  351         ctlr->nxtpkt = ctlr->pstart;
  352 }
  353 
  354 static uchar
  355 getcurr(Dp8390* ctlr)
  356 {
  357         uchar cr, curr;
  358 
  359         cr = regr(ctlr, Cr) & ~Txp;
  360         regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
  361         curr = regr(ctlr, Curr);
  362         regw(ctlr, Cr, cr);
  363 
  364         return curr;
  365 }
  366 
  367 static void
  368 receive(Ether* ether)
  369 {
  370         Dp8390 *ctlr;
  371         uchar curr, *p;
  372         Hdr hdr;
  373         ulong count, data, len;
  374         Block *bp;
  375 
  376         ctlr = ether->ctlr;
  377         for(curr = getcurr(ctlr); ctlr->nxtpkt != curr; curr = getcurr(ctlr)){
  378                 data = ctlr->nxtpkt*Dp8390BufSz;
  379                 if(ctlr->ram)
  380                         memmove(&hdr, (void*)(ether->mem+data), sizeof(Hdr));
  381                 else
  382                         _dp8390read(ctlr, &hdr, data, sizeof(Hdr));
  383 
  384                 /*
  385                  * Don't believe the upper byte count, work it
  386                  * out from the software next-page pointer and
  387                  * the current next-page pointer.
  388                  */
  389                 if(hdr.next > ctlr->nxtpkt)
  390                         len = hdr.next - ctlr->nxtpkt - 1;
  391                 else
  392                         len = (ctlr->pstop-ctlr->nxtpkt) + (hdr.next-ctlr->pstart) - 1;
  393                 if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr)))
  394                         len--;
  395 
  396                 len = ((len<<8)|hdr.len0)-4;
  397 
  398                 /*
  399                  * Chip is badly scrogged, reinitialise the ring.
  400                  */
  401                 if(hdr.next < ctlr->pstart || hdr.next >= ctlr->pstop
  402                   || len < 60 || len > sizeof(Etherpkt)){
  403                         print("dp8390: H%2.2ux+%2.2ux+%2.2ux+%2.2ux,%lud\n",
  404                                 hdr.status, hdr.next, hdr.len0, hdr.len1, len);
  405                         regw(ctlr, Cr, Page0|RdABORT|Stp);
  406                         ringinit(ctlr);
  407                         regw(ctlr, Cr, Page0|RdABORT|Sta);
  408 
  409                         return;
  410                 }
  411 
  412                 /*
  413                  * If it's a good packet read it in to the software buffer.
  414                  * If the packet wraps round the hardware ring, read it in
  415                  * two pieces.
  416                  */
  417                 if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && (bp = iallocb(len))){
  418                         p = bp->rp;
  419                         bp->wp = p+len;
  420                         data += sizeof(Hdr);
  421 
  422                         if((data+len) >= ctlr->pstop*Dp8390BufSz){
  423                                 count = ctlr->pstop*Dp8390BufSz - data;
  424                                 if(ctlr->ram)
  425                                         memmove(p, (void*)(ether->mem+data), count);
  426                                 else
  427                                         _dp8390read(ctlr, p, data, count);
  428                                 p += count;
  429                                 data = ctlr->pstart*Dp8390BufSz;
  430                                 len -= count;
  431                         }
  432                         if(len){
  433                                 if(ctlr->ram)
  434                                         memmove(p, (void*)(ether->mem+data), len);
  435                                 else
  436                                         _dp8390read(ctlr, p, data, len);
  437                         }
  438 
  439                         /*
  440                          * Copy the packet to whoever wants it.
  441                          */
  442                         etheriq(ether, bp, 1);
  443                 }
  444 
  445                 /*
  446                  * Finished with this packet, update the
  447                  * hardware and software ring pointers.
  448                  */
  449                 ctlr->nxtpkt = hdr.next;
  450 
  451                 hdr.next--;
  452                 if(hdr.next < ctlr->pstart)
  453                         hdr.next = ctlr->pstop-1;
  454                 regw(ctlr, Bnry, hdr.next);
  455         }
  456 }
  457 
  458 static void
  459 txstart(Ether* ether)
  460 {
  461         int len;
  462         Dp8390 *ctlr;
  463         Block *bp;
  464         uchar minpkt[ETHERMINTU], *rp;
  465 
  466         ctlr = ether->ctlr;
  467 
  468         /*
  469          * This routine is called both from the top level and from interrupt
  470          * level and expects to be called with ctlr already locked.
  471          */
  472         if(ctlr->txbusy)
  473                 return;
  474         bp = qget(ether->oq);
  475         if(bp == nil)
  476                 return;
  477 
  478         /*
  479          * Make sure the packet is of minimum length;
  480          * copy it to the card's memory by the appropriate means;
  481          * start the transmission.
  482          */
  483         len = BLEN(bp);
  484         rp = bp->rp;
  485         if(len < ETHERMINTU){
  486                 rp = minpkt;
  487                 memmove(rp, bp->rp, len);
  488                 memset(rp+len, 0, ETHERMINTU-len);
  489                 len = ETHERMINTU;
  490         }
  491 
  492         if(ctlr->ram)
  493                 memmove((void*)(ether->mem+ctlr->tstart*Dp8390BufSz), rp, len);
  494         else
  495                 dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, rp, len);
  496         freeb(bp);
  497 
  498         regw(ctlr, Tbcr0, len & 0xFF);
  499         regw(ctlr, Tbcr1, (len>>8) & 0xFF);
  500         regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
  501 
  502         ether->outpackets++;
  503         ctlr->txbusy = 1;
  504 }
  505 
  506 static void
  507 transmit(Ether* ether)
  508 {
  509         Dp8390 *ctlr;
  510 
  511         ctlr = ether->ctlr;
  512 
  513         ilock(ctlr);
  514         txstart(ether);
  515         iunlock(ctlr);
  516 }
  517 
  518 static void
  519 overflow(Ether *ether)
  520 {
  521         Dp8390 *ctlr;
  522         uchar txp;
  523         int resend;
  524 
  525         ctlr = ether->ctlr;
  526 
  527         /*
  528          * The following procedure is taken from the DP8390[12D] datasheet,
  529          * it seems pretty adamant that this is what has to be done.
  530          */
  531         txp = regr(ctlr, Cr) & Txp;
  532         regw(ctlr, Cr, Page0|RdABORT|Stp);
  533         delay(2);
  534         regw(ctlr, Rbcr0, 0);
  535         regw(ctlr, Rbcr1, 0);
  536 
  537         resend = 0;
  538         if(txp && (regr(ctlr, Isr) & (Txe|Ptx)) == 0)
  539                 resend = 1;
  540 
  541         regw(ctlr, Tcr, LpbkNIC);
  542         regw(ctlr, Cr, Page0|RdABORT|Sta);
  543         receive(ether);
  544         regw(ctlr, Isr, Ovw);
  545         regw(ctlr, Tcr, LpbkNORMAL);
  546 
  547         if(resend)
  548                 regw(ctlr, Cr, Page0|RdABORT|Txp|Sta);
  549 }
  550 
  551 static void
  552 interrupt(Ureg*, void* arg)
  553 {
  554         Ether *ether;
  555         Dp8390 *ctlr;
  556         uchar isr, r;
  557 
  558         ether = arg;
  559         ctlr = ether->ctlr;
  560 
  561         /*
  562          * While there is something of interest,
  563          * clear all the interrupts and process.
  564          */
  565         ilock(ctlr);
  566         regw(ctlr, Imr, 0x00);
  567         while(isr = (regr(ctlr, Isr) & (Cnt|Ovw|Txe|Rxe|Ptx|Prx))){
  568                 if(isr & Ovw){
  569                         overflow(ether);
  570                         regw(ctlr, Isr, Ovw);
  571                         ether->overflows++;
  572                 }
  573 
  574                 /*
  575                  * Packets have been received.
  576                  * Take a spin round the ring.
  577                  */
  578                 if(isr & (Rxe|Prx)){
  579                         receive(ether);
  580                         regw(ctlr, Isr, Rxe|Prx);
  581                 }
  582 
  583                 /*
  584                  * A packet completed transmission, successfully or
  585                  * not. Start transmission on the next buffered packet,
  586                  * and wake the output routine.
  587                  */
  588                 if(isr & (Txe|Ptx)){
  589                         r = regr(ctlr, Tsr);
  590                         if((isr & Txe) && (r & (Cdh|Fu|Crs|Abt))){
  591                                 print("dp8390: Tsr %#2.2ux", r);
  592                                 ether->oerrs++;
  593                         }
  594 
  595                         regw(ctlr, Isr, Txe|Ptx);
  596 
  597                         if(isr & Ptx)
  598                                 ether->outpackets++;
  599                         ctlr->txbusy = 0;
  600                         txstart(ether);
  601                 }
  602 
  603                 if(isr & Cnt){
  604                         ether->frames += regr(ctlr, Ref0);
  605                         ether->crcs += regr(ctlr, Ref1);
  606                         ether->buffs += regr(ctlr, Ref2);
  607                         regw(ctlr, Isr, Cnt);
  608                 }
  609         }
  610         regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
  611         iunlock(ctlr);
  612 }
  613 
  614 static uchar allmar[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  615 
  616 static void
  617 setfilter(Ether *ether, Dp8390 *ctlr)
  618 {
  619         uchar r, cr;
  620         int i;
  621         uchar *mar;
  622 
  623         r = Ab;
  624         mar = 0;
  625         if(ether->prom){
  626                 r |= Pro|Am;
  627                 mar = allmar;
  628         } else if(ether->nmaddr){
  629                 r |= Am;
  630                 mar = ctlr->mar;
  631         }
  632         if(mar){
  633                 cr = regr(ctlr, Cr) & ~Txp;
  634                 regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr));
  635                 for(i = 0; i < 8; i++)
  636                         regw(ctlr, Mar0+i, *(mar++));
  637                 regw(ctlr, Cr, cr);
  638         }
  639         regw(ctlr, Rcr, r);
  640 }
  641 
  642 static void
  643 promiscuous(void *arg, int )
  644 {
  645         Ether *ether;
  646         Dp8390 *ctlr;
  647 
  648         ether = arg;
  649         ctlr = ether->ctlr;
  650 
  651         ilock(ctlr);
  652         setfilter(ether, ctlr);
  653         iunlock(ctlr);
  654 }
  655 
  656 static void
  657 setbit(Dp8390 *ctlr, int bit, int on)
  658 {
  659         int i, h;
  660 
  661         i = bit/8;
  662         h = bit%8;
  663         if(on){
  664                 if(++(ctlr->mref[bit]) == 1)
  665                         ctlr->mar[i] |= 1<<h;
  666         } else {
  667                 if(--(ctlr->mref[bit]) <= 0){
  668                         ctlr->mref[bit] = 0;
  669                         ctlr->mar[i] &= ~(1<<h);
  670                 }
  671         }
  672 }
  673 
  674 static uchar reverse[64];
  675 
  676 static void
  677 multicast(void* arg, uchar *addr, int on)
  678 {
  679         Ether *ether;
  680         Dp8390 *ctlr;
  681         int i;
  682         ulong h;
  683 
  684         ether = arg;
  685         ctlr = ether->ctlr;
  686         if(reverse[1] == 0){
  687                 for(i = 0; i < 64; i++)
  688                         reverse[i] = ((i&1)<<5) | ((i&2)<<3) | ((i&4)<<1)
  689                                    | ((i&8)>>1) | ((i&16)>>3) | ((i&32)>>5);
  690         }
  691 
  692         /*
  693          *  change filter bits
  694          */
  695         h = ethercrc(addr, 6);
  696         ilock(ctlr);
  697         setbit(ctlr, reverse[h&0x3f], on);
  698         setfilter(ether, ctlr);
  699         iunlock(ctlr);
  700 }
  701 
  702 static void
  703 attach(Ether* ether)
  704 {
  705         Dp8390 *ctlr;
  706         uchar r;
  707 
  708         ctlr = ether->ctlr;
  709 
  710         /*
  711          * Enable the chip for transmit/receive.
  712          * The init routine leaves the chip in monitor
  713          * mode. Clear the missed-packet counter, it
  714          * increments while in monitor mode.
  715          * Sometimes there's an interrupt pending at this
  716          * point but there's nothing in the Isr, so
  717          * any pending interrupts are cleared and the
  718          * mask of acceptable interrupts is enabled here.
  719          */
  720         r = Ab;
  721         if(ether->prom)
  722                 r |= Pro;
  723         if(ether->nmaddr)
  724                 r |= Am;
  725         ilock(ctlr);
  726         regw(ctlr, Isr, 0xFF);
  727         regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx);
  728         regw(ctlr, Rcr, r);
  729         r = regr(ctlr, Ref2);
  730         regw(ctlr, Tcr, LpbkNORMAL);
  731         iunlock(ctlr);
  732         USED(r);
  733 }
  734 
  735 static void
  736 disable(Dp8390* ctlr)
  737 {
  738         int timo;
  739 
  740         /*
  741          * Stop the chip. Set the Stp bit and wait for the chip
  742          * to finish whatever was on its tiny mind before it sets
  743          * the Rst bit.
  744          * The timeout is needed because there may not be a real
  745          * chip there if this is called when probing for a device
  746          * at boot.
  747          */
  748         regw(ctlr, Cr, Page0|RdABORT|Stp);
  749         regw(ctlr, Rbcr0, 0);
  750         regw(ctlr, Rbcr1, 0);
  751         for(timo = 10000; (regr(ctlr, Isr) & Rst) == 0 && timo; timo--)
  752                         ;
  753 }
  754 
  755 int
  756 dp8390reset(Ether* ether)
  757 {
  758         Dp8390 *ctlr;
  759 
  760         ctlr = ether->ctlr;
  761 
  762         /*
  763          * This is the initialisation procedure described
  764          * as 'mandatory' in the datasheet, with references
  765          * to the 3C503 technical reference manual.
  766          */ 
  767         disable(ctlr);
  768         if(ctlr->width != 1)
  769                 regw(ctlr, Dcr, Ft4WORD|Ls|Wts);
  770         else
  771                 regw(ctlr, Dcr, Ft4WORD|Ls);
  772 
  773         regw(ctlr, Rbcr0, 0);
  774         regw(ctlr, Rbcr1, 0);
  775 
  776         regw(ctlr, Tcr, LpbkNIC);
  777         regw(ctlr, Rcr, Mon);
  778 
  779         /*
  780          * Init the ring hardware and software ring pointers.
  781          * Can't initialise ethernet address as it may not be
  782          * known yet.
  783          */
  784         ringinit(ctlr);
  785         regw(ctlr, Tpsr, ctlr->tstart);
  786 
  787         /*
  788          * Clear any pending interrupts and mask then all off.
  789          */
  790         regw(ctlr, Isr, 0xFF);
  791         regw(ctlr, Imr, 0);
  792 
  793         /*
  794          * Leave the chip initialised,
  795          * but in monitor mode.
  796          */
  797         regw(ctlr, Cr, Page0|RdABORT|Sta);
  798 
  799         /*
  800          * Set up the software configuration.
  801          */
  802         ether->attach = attach;
  803         ether->transmit = transmit;
  804         ether->interrupt = interrupt;
  805         ether->ifstat = 0;
  806 
  807         ether->promiscuous = promiscuous;
  808         ether->multicast = multicast;
  809         ether->arg = ether;
  810 
  811         return 0;
  812 }

Cache object: 0e1093ae42accf71b3fe0e0838e99724


[ 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.