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/ether79c970.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  * AMD79C970
    3  * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus
    4  * To do:
    5  *      finish this rewrite
    6  */
    7 #include "u.h"
    8 #include "../port/lib.h"
    9 #include "mem.h"
   10 #include "dat.h"
   11 #include "fns.h"
   12 #include "io.h"
   13 #include "../port/error.h"
   14 #include "../port/netif.h"
   15 
   16 #include "etherif.h"
   17 
   18 enum {
   19         Lognrdre        = 6,
   20         Nrdre           = (1<<Lognrdre),/* receive descriptor ring entries */
   21         Logntdre        = 4,
   22         Ntdre           = (1<<Logntdre),/* transmit descriptor ring entries */
   23 
   24         Rbsize          = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */
   25 };
   26 
   27 enum {                                  /* DWIO I/O resource map */
   28         Aprom           = 0x0000,       /* physical address */
   29         Rdp             = 0x0010,       /* register data port */
   30         Rap             = 0x0014,       /* register address port */
   31         Sreset          = 0x0018,       /* software reset */
   32         Bdp             = 0x001C,       /* bus configuration register data port */
   33 };
   34 
   35 enum {                                  /* CSR0 */
   36         Init            = 0x0001,       /* begin initialisation */
   37         Strt            = 0x0002,       /* enable chip */
   38         Stop            = 0x0004,       /* disable chip */
   39         Tdmd            = 0x0008,       /* transmit demand */
   40         Txon            = 0x0010,       /* transmitter on */
   41         Rxon            = 0x0020,       /* receiver on */
   42         Iena            = 0x0040,       /* interrupt enable */
   43         Intr            = 0x0080,       /* interrupt flag */
   44         Idon            = 0x0100,       /* initialisation done */
   45         Tint            = 0x0200,       /* transmit interrupt */
   46         Rint            = 0x0400,       /* receive interrupt */
   47         Merr            = 0x0800,       /* memory error */
   48         Miss            = 0x1000,       /* missed frame */
   49         Cerr            = 0x2000,       /* collision */
   50         Babl            = 0x4000,       /* transmitter timeout */
   51         Err             = 0x8000,       /* Babl|Cerr|Miss|Merr */
   52 };
   53         
   54 enum {                                  /* CSR3 */
   55         Bswp            = 0x0004,       /* byte swap */
   56         Emba            = 0x0008,       /* enable modified back-off algorithm */
   57         Dxmt2pd         = 0x0010,       /* disable transmit two part deferral */
   58         Lappen          = 0x0020,       /* look-ahead packet processing enable */
   59 };
   60 
   61 enum {                                  /* CSR4 */
   62         ApadXmt         = 0x0800,       /* auto pad transmit */
   63 };
   64 
   65 enum {                                  /* CSR15 */
   66         Prom            = 0x8000,       /* promiscuous mode */
   67 };
   68 
   69 typedef struct Iblock Iblock;
   70 struct Iblock {                 /* Initialisation Block */
   71         ushort  mode;
   72         uchar   rlen;                   /* upper 4 bits */
   73         uchar   tlen;                   /* upper 4 bits */
   74         uchar   padr[6];
   75         uchar   res[2];
   76         uchar   ladr[8];
   77         ulong   rdra;
   78         ulong   tdra;
   79 };
   80 
   81 typedef struct Dre Dre;
   82 struct Dre {                    /* descriptor ring entry */
   83         ulong   addr;
   84         ulong   md1;                    /* status|bcnt */
   85         ulong   md2;                    /* rcc|rpc|mcnt */
   86         Block*  bp;
   87 };
   88 
   89 enum {                                  /* md1 */
   90         Enp             = 0x01000000,   /* end of packet */
   91         Stp             = 0x02000000,   /* start of packet */
   92         RxBuff          = 0x04000000,   /* buffer error */
   93         Def             = 0x04000000,   /* deferred */
   94         Crc             = 0x08000000,   /* CRC error */
   95         One             = 0x08000000,   /* one retry needed */
   96         Oflo            = 0x10000000,   /* overflow error */
   97         More            = 0x10000000,   /* more than one retry needed */
   98         Fram            = 0x20000000,   /* framing error */
   99         RxErr           = 0x40000000,   /* Fram|Oflo|Crc|RxBuff */
  100         TxErr           = 0x40000000,   /* Uflo|Lcol|Lcar|Rtry */
  101         Own             = 0x80000000,
  102 };
  103 
  104 enum {                                  /* md2 */
  105         Rtry            = 0x04000000,   /* failed after repeated retries */
  106         Lcar            = 0x08000000,   /* loss of carrier */
  107         Lcol            = 0x10000000,   /* late collision */
  108         Uflo            = 0x40000000,   /* underflow error */
  109         TxBuff          = 0x80000000,   /* buffer error */
  110 };
  111 
  112 typedef struct Ctlr Ctlr;
  113 struct Ctlr {
  114         Lock;
  115         int     port;
  116         Pcidev* pcidev;
  117         Ctlr*   next;
  118         int     active;
  119 
  120         int     init;                   /* initialisation in progress */
  121         Iblock  iblock;
  122 
  123         Dre*    rdr;                    /* receive descriptor ring */
  124         int     rdrx;
  125 
  126         Dre*    tdr;                    /* transmit descriptor ring */
  127         int     tdrh;                   /* host index into tdr */
  128         int     tdri;                   /* interface index into tdr */
  129         int     ntq;                    /* descriptors active */
  130 
  131         ulong   rxbuff;                 /* receive statistics */
  132         ulong   crc;
  133         ulong   oflo;
  134         ulong   fram;
  135 
  136         ulong   rtry;                   /* transmit statistics */
  137         ulong   lcar;
  138         ulong   lcol;
  139         ulong   uflo;
  140         ulong   txbuff;
  141 
  142         ulong   merr;                   /* bobf is such a whiner */
  143         ulong   miss;
  144         ulong   babl;
  145 
  146         int     (*ior)(Ctlr*, int);
  147         void    (*iow)(Ctlr*, int, int);
  148 };
  149 
  150 static Ctlr* ctlrhead;
  151 static Ctlr* ctlrtail;
  152 
  153 /*
  154  * The Rdp, Rap, Sreset, Bdp ports are 32-bit port offset in the enumeration above.
  155  * To get to 16-bit offsets, scale down with 0x10 staying the same.
  156  */
  157 static int
  158 io16r(Ctlr *c, int r)
  159 {
  160         if(r >= Rdp)
  161                 r = (r-Rdp)/2+Rdp;
  162         return ins(c->port+r);
  163 }
  164 
  165 static void
  166 io16w(Ctlr *c, int r, int v)
  167 {
  168         if(r >= Rdp)
  169                 r = (r-Rdp)/2+Rdp;
  170         outs(c->port+r, v);
  171 }
  172 
  173 static int
  174 io32r(Ctlr *c, int r)
  175 {
  176         return inl(c->port+r);
  177 }
  178 
  179 static void
  180 io32w(Ctlr *c, int r, int v)
  181 {
  182         outl(c->port+r, v);
  183 }
  184 
  185 static void
  186 attach(Ether*)
  187 {
  188 }
  189 
  190 static long
  191 ifstat(Ether* ether, void* a, long n, ulong offset)
  192 {
  193         char *p;
  194         int len;
  195         Ctlr *ctlr;
  196 
  197         ctlr = ether->ctlr;
  198 
  199         ether->crcs = ctlr->crc;
  200         ether->frames = ctlr->fram;
  201         ether->buffs = ctlr->rxbuff+ctlr->txbuff;
  202         ether->overflows = ctlr->oflo;
  203 
  204         if(n == 0)
  205                 return 0;
  206 
  207         p = malloc(READSTR);
  208         len = snprint(p, READSTR, "Rxbuff: %ld\n", ctlr->rxbuff);
  209         len += snprint(p+len, READSTR-len, "Crc: %ld\n", ctlr->crc);
  210         len += snprint(p+len, READSTR-len, "Oflo: %ld\n", ctlr->oflo);
  211         len += snprint(p+len, READSTR-len, "Fram: %ld\n", ctlr->fram);
  212         len += snprint(p+len, READSTR-len, "Rtry: %ld\n", ctlr->rtry);
  213         len += snprint(p+len, READSTR-len, "Lcar: %ld\n", ctlr->lcar);
  214         len += snprint(p+len, READSTR-len, "Lcol: %ld\n", ctlr->lcol);
  215         len += snprint(p+len, READSTR-len, "Uflo: %ld\n", ctlr->uflo);
  216         len += snprint(p+len, READSTR-len, "Txbuff: %ld\n", ctlr->txbuff);
  217         len += snprint(p+len, READSTR-len, "Merr: %ld\n", ctlr->merr);
  218         len += snprint(p+len, READSTR-len, "Miss: %ld\n", ctlr->miss);
  219         snprint(p+len, READSTR-len, "Babl: %ld\n", ctlr->babl);
  220 
  221         n = readstr(offset, a, n, p);
  222         free(p);
  223 
  224         return n;
  225 }
  226 
  227 static void
  228 ringinit(Ctlr* ctlr)
  229 {
  230         Dre *dre;
  231 
  232         /*
  233          * Initialise the receive and transmit buffer rings.
  234          * The ring entries must be aligned on 16-byte boundaries.
  235          *
  236          * This routine is protected by ctlr->init.
  237          */
  238         if(ctlr->rdr == 0){
  239                 ctlr->rdr = xspanalloc(Nrdre*sizeof(Dre), 0x10, 0);
  240                 for(dre = ctlr->rdr; dre < &ctlr->rdr[Nrdre]; dre++){
  241                         dre->bp = iallocb(Rbsize);
  242                         if(dre->bp == nil)
  243                                 panic("can't allocate ethernet receive ring\n");
  244                         dre->addr = PADDR(dre->bp->rp);
  245                         dre->md2 = 0;
  246                         dre->md1 = Own|(-Rbsize & 0xFFFF);
  247                 }
  248         }
  249         ctlr->rdrx = 0;
  250 
  251         if(ctlr->tdr == 0)
  252                 ctlr->tdr = xspanalloc(Ntdre*sizeof(Dre), 0x10, 0);
  253         memset(ctlr->tdr, 0, Ntdre*sizeof(Dre));
  254         ctlr->tdrh = ctlr->tdri = 0;
  255 }
  256 
  257 static void
  258 promiscuous(void* arg, int on)
  259 {
  260         Ether *ether;
  261         int x;
  262         Ctlr *ctlr;
  263 
  264         ether = arg;
  265         ctlr = ether->ctlr;
  266 
  267         /*
  268          * Put the chip into promiscuous mode. First must wait until
  269          * anyone transmitting is done, then stop the chip and put
  270          * it in promiscuous mode. Restarting is made harder by the chip
  271          * reloading the transmit and receive descriptor pointers with their
  272          * base addresses when Strt is set (unlike the older Lance chip),
  273          * so the rings must be re-initialised.
  274          */
  275         ilock(ctlr);
  276         if(ctlr->init){
  277                 iunlock(ctlr);
  278                 return;
  279         }
  280         ctlr->init = 1;
  281         iunlock(ctlr);
  282 
  283         while(ctlr->ntq)
  284                 ;
  285 
  286         ctlr->iow(ctlr, Rdp, Stop);
  287 
  288         ctlr->iow(ctlr, Rap, 15);
  289         x = ctlr->ior(ctlr, Rdp) & ~Prom;
  290         if(on)
  291                 x |= Prom;
  292         ctlr->iow(ctlr, Rdp, x);
  293         ctlr->iow(ctlr, Rap, 0);
  294 
  295         ringinit(ctlr);
  296 
  297         ilock(ctlr);
  298         ctlr->init = 0;
  299         ctlr->iow(ctlr, Rdp, Iena|Strt);
  300         iunlock(ctlr);
  301 }
  302 
  303 static void
  304 multicast(void* arg, uchar*, int)
  305 {
  306         promiscuous(arg, 1);
  307 }
  308 
  309 static void
  310 txstart(Ether* ether)
  311 {
  312         Ctlr *ctlr;
  313         Block *bp;
  314         Dre *dre;
  315 
  316         ctlr = ether->ctlr;
  317 
  318         if(ctlr->init)
  319                 return;
  320 
  321         while(ctlr->ntq < (Ntdre-1)){
  322                 bp = qget(ether->oq);
  323                 if(bp == nil)
  324                         break;
  325 
  326                 /*
  327                  * Give ownership of the descriptor to the chip,
  328                  * increment the software ring descriptor pointer
  329                  * and tell the chip to poll.
  330                  * There's no need to pad to ETHERMINTU
  331                  * here as ApadXmt is set in CSR4.
  332                  */
  333                 dre = &ctlr->tdr[ctlr->tdrh];
  334                 dre->bp = bp;
  335                 dre->addr = PADDR(bp->rp);
  336                 dre->md2 = 0;
  337                 dre->md1 = Own|Stp|Enp|(-BLEN(bp) & 0xFFFF);
  338                 ctlr->ntq++;
  339                 ctlr->iow(ctlr, Rdp, Iena|Tdmd);
  340                 ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
  341         }
  342 }
  343 
  344 static void
  345 transmit(Ether* ether)
  346 {
  347         Ctlr *ctlr;
  348 
  349         ctlr = ether->ctlr;
  350         ilock(ctlr);
  351         txstart(ether);
  352         iunlock(ctlr);
  353 }
  354 
  355 static void
  356 interrupt(Ureg*, void* arg)
  357 {
  358         Ctlr *ctlr;
  359         Ether *ether;
  360         int csr0, len;
  361         Dre *dre;
  362         Block *bp;
  363 
  364         ether = arg;
  365         ctlr = ether->ctlr;
  366 
  367         /*
  368          * Acknowledge all interrupts and whine about those that shouldn't
  369          * happen.
  370          */
  371 intrloop:
  372         csr0 = ctlr->ior(ctlr, Rdp) & 0xFFFF;
  373         ctlr->iow(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
  374         if(csr0 & Merr)
  375                 ctlr->merr++;
  376         if(csr0 & Miss)
  377                 ctlr->miss++;
  378         if(csr0 & Babl)
  379                 ctlr->babl++;
  380         //if(csr0 & (Babl|Miss|Merr))
  381         //      print("#l%d: csr0 = 0x%uX\n", ether->ctlrno, csr0);
  382         if(!(csr0 & (Rint|Tint)))
  383                 return;
  384 
  385         /*
  386          * Receiver interrupt: run round the descriptor ring logging
  387          * errors and passing valid receive data up to the higher levels
  388          * until a descriptor is encountered still owned by the chip.
  389          */
  390         if(csr0 & Rint){
  391                 dre = &ctlr->rdr[ctlr->rdrx];
  392                 while(!(dre->md1 & Own)){
  393                         if(dre->md1 & RxErr){
  394                                 if(dre->md1 & RxBuff)
  395                                         ctlr->rxbuff++;
  396                                 if(dre->md1 & Crc)
  397                                         ctlr->crc++;
  398                                 if(dre->md1 & Oflo)
  399                                         ctlr->oflo++;
  400                                 if(dre->md1 & Fram)
  401                                         ctlr->fram++;
  402                         }
  403                         else if(bp = iallocb(Rbsize)){
  404                                 len = (dre->md2 & 0x0FFF)-4;
  405                                 dre->bp->wp = dre->bp->rp+len;
  406                                 etheriq(ether, dre->bp, 1);
  407                                 dre->bp = bp;
  408                                 dre->addr = PADDR(bp->rp);
  409                         }
  410 
  411                         /*
  412                          * Finished with this descriptor, reinitialise it,
  413                          * give it back to the chip, then on to the next...
  414                          */
  415                         dre->md2 = 0;
  416                         dre->md1 = Own|(-Rbsize & 0xFFFF);
  417 
  418                         ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
  419                         dre = &ctlr->rdr[ctlr->rdrx];
  420                 }
  421         }
  422 
  423         /*
  424          * Transmitter interrupt: wakeup anyone waiting for a free descriptor.
  425          */
  426         if(csr0 & Tint){
  427                 lock(ctlr);
  428                 while(ctlr->ntq){
  429                         dre = &ctlr->tdr[ctlr->tdri];
  430                         if(dre->md1 & Own)
  431                                 break;
  432         
  433                         if(dre->md1 & TxErr){
  434                                 if(dre->md2 & Rtry)
  435                                         ctlr->rtry++;
  436                                 if(dre->md2 & Lcar)
  437                                         ctlr->lcar++;
  438                                 if(dre->md2 & Lcol)
  439                                         ctlr->lcol++;
  440                                 if(dre->md2 & Uflo)
  441                                         ctlr->uflo++;
  442                                 if(dre->md2 & TxBuff)
  443                                         ctlr->txbuff++;
  444                                 ether->oerrs++;
  445                         }
  446         
  447                         freeb(dre->bp);
  448         
  449                         ctlr->ntq--;
  450                         ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
  451                 }
  452                 txstart(ether);
  453                 unlock(ctlr);
  454         }
  455         goto intrloop;
  456 }
  457 
  458 static void
  459 amd79c970pci(void)
  460 {
  461         int port;
  462         Ctlr *ctlr;
  463         Pcidev *p;
  464 
  465         p = nil;
  466         while(p = pcimatch(p, 0x1022, 0x2000)){
  467                 port = p->mem[0].bar & ~0x01;
  468                 if(ioalloc(port, p->mem[0].size, 0, "amd79c970") < 0){
  469                         print("amd79c970: port 0x%uX in use\n", port);
  470                         continue;
  471                 }
  472                 ctlr = malloc(sizeof(Ctlr));
  473                 ctlr->port = p->mem[0].bar & ~0x01;
  474                 ctlr->pcidev = p;
  475 
  476                 if(ctlrhead != nil)
  477                         ctlrtail->next = ctlr;
  478                 else
  479                         ctlrhead = ctlr;
  480                 ctlrtail = ctlr;
  481         }
  482 }
  483 
  484 static int
  485 reset(Ether* ether)
  486 {
  487         int x;
  488         uchar ea[Eaddrlen];
  489         Ctlr *ctlr;
  490 
  491         if(ctlrhead == nil)
  492                 amd79c970pci();
  493 
  494         /*
  495          * Any adapter matches if no port is supplied,
  496          * otherwise the ports must match.
  497          */
  498         for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
  499                 if(ctlr->active)
  500                         continue;
  501                 if(ether->port == 0 || ether->port == ctlr->port){
  502                         ctlr->active = 1;
  503                         break;
  504                 }
  505         }
  506         if(ctlr == nil)
  507                 return -1;
  508 
  509         /*
  510          * Allocate a controller structure and start to initialise it.
  511          */
  512         ether->ctlr = ctlr;
  513         ether->port = ctlr->port;
  514         ether->irq = ctlr->pcidev->intl;
  515         ether->tbdf = ctlr->pcidev->tbdf;
  516         pcisetbme(ctlr->pcidev);
  517         ilock(ctlr);
  518         ctlr->init = 1;
  519 
  520         io32r(ctlr, Sreset);
  521         io16r(ctlr, Sreset);
  522 
  523         if(io16w(ctlr, Rap, 0), io16r(ctlr, Rdp) == 4){
  524                 ctlr->ior = io16r;
  525                 ctlr->iow = io16w;
  526         }else if(io32w(ctlr, Rap, 0), io32r(ctlr, Rdp) == 4){
  527                 ctlr->ior = io32r;
  528                 ctlr->iow = io32w;
  529         }else{
  530                 print("#l%d: card doesn't talk right\n", ether->ctlrno);
  531                 iunlock(ctlr);
  532                 return -1;
  533         }
  534 
  535         ctlr->iow(ctlr, Rap, 88);
  536         x = ctlr->ior(ctlr, Rdp);
  537         ctlr->iow(ctlr, Rap, 89);
  538         x |= ctlr->ior(ctlr, Rdp)<<16;
  539 
  540         switch(x&0xFFFFFFF){
  541         case 0x2420003: /* PCnet/PCI 79C970 */
  542         case 0x2621003: /* PCnet/PCI II 79C970A */
  543                 break;
  544         default:
  545                 print("#l%d: unknown PCnet card version %.7ux\n",
  546                         ether->ctlrno, x&0xFFFFFFF);
  547                 iunlock(ctlr);
  548                 return -1;
  549         }
  550 
  551         /*
  552          * Set the software style in BCR20 to be PCnet-PCI to ensure 32-bit access.
  553          * Set the auto pad transmit in CSR4.
  554          */
  555         ctlr->iow(ctlr, Rap, 20);
  556         ctlr->iow(ctlr, Bdp, 0x0002);
  557 
  558         ctlr->iow(ctlr, Rap, 4);
  559         x = ctlr->ior(ctlr, Rdp) & 0xFFFF;
  560         ctlr->iow(ctlr, Rdp, ApadXmt|x);
  561 
  562         ctlr->iow(ctlr, Rap, 0);
  563 
  564         /*
  565          * Check if the adapter's station address is to be overridden.
  566          * If not, read it from the I/O-space and set in ether->ea prior to
  567          * loading the station address in the initialisation block.
  568          */
  569         memset(ea, 0, Eaddrlen);
  570         if(!memcmp(ea, ether->ea, Eaddrlen)){
  571                 x = ctlr->ior(ctlr, Aprom);
  572                 ether->ea[0] = x;
  573                 ether->ea[1] = x>>8;
  574                 if(ctlr->ior == io16r)
  575                         x = ctlr->ior(ctlr, Aprom+2);
  576                 else
  577                         x >>= 16;
  578                 ether->ea[2] = x;
  579                 ether->ea[3] = x>>8;
  580                 x = ctlr->ior(ctlr, Aprom+4);
  581                 ether->ea[4] = x;
  582                 ether->ea[5] = x>>8;
  583         }
  584 
  585         /*
  586          * Start to fill in the initialisation block
  587          * (must be DWORD aligned).
  588          */
  589         ctlr->iblock.rlen = Lognrdre<<4;
  590         ctlr->iblock.tlen = Logntdre<<4;
  591         memmove(ctlr->iblock.padr, ether->ea, sizeof(ctlr->iblock.padr));
  592 
  593         ringinit(ctlr);
  594         ctlr->iblock.rdra = PADDR(ctlr->rdr);
  595         ctlr->iblock.tdra = PADDR(ctlr->tdr);
  596 
  597         /*
  598          * Point the chip at the initialisation block and tell it to go.
  599          * Mask the Idon interrupt and poll for completion. Strt and interrupt
  600          * enables will be set later when attaching to the network.
  601          */
  602         x = PADDR(&ctlr->iblock);
  603         ctlr->iow(ctlr, Rap, 1);
  604         ctlr->iow(ctlr, Rdp, x & 0xFFFF);
  605         ctlr->iow(ctlr, Rap, 2);
  606         ctlr->iow(ctlr, Rdp, (x>>16) & 0xFFFF);
  607         ctlr->iow(ctlr, Rap, 3);
  608         ctlr->iow(ctlr, Rdp, Idon);
  609         ctlr->iow(ctlr, Rap, 0);
  610         ctlr->iow(ctlr, Rdp, Init);
  611 
  612         while(!(ctlr->ior(ctlr, Rdp) & Idon))
  613                 ;
  614 
  615         /*
  616          * We used to set CSR0 to Idon|Stop here, and then
  617          * in attach change it to Iena|Strt.  Apparently the simulated
  618          * 79C970 in VMware never enables after a write of Idon|Stop,
  619          * so we enable the device here now.
  620          */
  621         ctlr->iow(ctlr, Rdp, Iena|Strt);
  622         ctlr->init = 0;
  623         iunlock(ctlr);
  624 
  625         /*
  626          * Linkage to the generic ethernet driver.
  627          */
  628         ether->attach = attach;
  629         ether->transmit = transmit;
  630         ether->interrupt = interrupt;
  631         ether->ifstat = ifstat;
  632 
  633         ether->arg = ether;
  634         ether->promiscuous = promiscuous;
  635         ether->multicast = multicast;
  636 //      ether->shutdown = shutdown;
  637 
  638         return 0;
  639 }
  640 
  641 void
  642 ether79c970link(void)
  643 {
  644         addethercard("AMD79C970",  reset);
  645 }

Cache object: 1b125515001b4a0863b262e0e74f0ab7


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