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/i386/isa/if_el.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1994, Matthew E. Kimmel.  Permission is hereby granted
    3  * to use, copy, modify and distribute this software provided that both
    4  * the copyright notice and this permission notice appear in all copies
    5  * of the software, derivative works or modified versions, and any
    6  * portions thereof.
    7  *
    8  * Questions, comments, bug reports and fixes to kimmel@cs.umass.edu.
    9  */
   10 
   11 #include <sys/cdefs.h>
   12 __FBSDID("$FreeBSD: src/sys/i386/isa/if_el.c,v 1.64.2.1 2005/01/31 23:26:05 imp Exp $");
   13 
   14 /* Except of course for the portions of code lifted from other FreeBSD
   15  * drivers (mainly elread, elget and el_ioctl)
   16  */
   17 /* 3COM Etherlink 3C501 device driver for FreeBSD */
   18 /* Yeah, I know these cards suck, but you can also get them for free
   19  * really easily...
   20  */
   21 /* Bugs/possible improvements:
   22  *      - Does not currently support DMA
   23  *      - Does not currently support multicasts
   24  */
   25 #include "opt_inet.h"
   26 #include "opt_ipx.h"
   27 
   28 #include <sys/param.h>
   29 #include <sys/systm.h>
   30 #include <sys/kernel.h>
   31 #include <sys/module.h>
   32 #include <sys/sockio.h>
   33 #include <sys/mbuf.h>
   34 #include <sys/socket.h>
   35 #include <sys/syslog.h>
   36 #include <sys/bus.h>
   37 
   38 #include <net/ethernet.h>
   39 #include <net/if.h>
   40 
   41 #include <netinet/in.h>
   42 #include <netinet/if_ether.h>
   43 
   44 #include <net/bpf.h>
   45 
   46 #include <machine/bus_pio.h>
   47 #include <machine/bus.h>
   48 #include <machine/resource.h>
   49 #include <sys/bus.h>
   50 #include <sys/rman.h>
   51 
   52 #include <isa/isavar.h>
   53 
   54 #include <i386/isa/if_elreg.h>
   55 
   56 /* For debugging convenience */
   57 #ifdef EL_DEBUG
   58 #define dprintf(x) printf x
   59 #else
   60 #define dprintf(x)
   61 #endif
   62 
   63 /* el_softc: per line info and status */
   64 struct el_softc {
   65         struct arpcom arpcom;   /* Ethernet common */
   66         bus_space_handle_t      el_bhandle;
   67         bus_space_tag_t         el_btag;
   68         void                    *el_intrhand;
   69         struct resource         *el_irq;
   70         struct resource         *el_res;
   71         struct mtx              el_mtx;
   72         char el_pktbuf[EL_BUFSIZ];      /* Frame buffer */
   73 };
   74 
   75 /* Prototypes */
   76 static int el_attach(device_t);
   77 static int el_detach(device_t);
   78 static void el_init(void *);
   79 static int el_ioctl(struct ifnet *,u_long,caddr_t);
   80 static int el_probe(device_t);
   81 static void el_start(struct ifnet *);
   82 static void el_reset(void *);
   83 static void el_watchdog(struct ifnet *);
   84 static int el_shutdown(device_t);
   85 
   86 static void el_stop(void *);
   87 static int el_xmit(struct el_softc *,int);
   88 static void elintr(void *);
   89 static __inline void elread(struct el_softc *,caddr_t,int);
   90 static struct mbuf *elget(caddr_t,int,struct ifnet *);
   91 static __inline void el_hardreset(void *);
   92 
   93 static device_method_t el_methods[] = {
   94         /* Device interface */
   95         DEVMETHOD(device_probe,         el_probe),
   96         DEVMETHOD(device_attach,        el_attach),
   97         DEVMETHOD(device_detach,        el_detach),
   98         DEVMETHOD(device_shutdown,      el_shutdown),
   99         { 0, 0 }
  100 };
  101 
  102 static driver_t el_driver = {
  103         "el",
  104         el_methods,
  105         sizeof(struct el_softc)
  106 };
  107 
  108 static devclass_t el_devclass;
  109 
  110 DRIVER_MODULE(if_el, isa, el_driver, el_devclass, 0, 0);
  111 
  112 #define CSR_WRITE_1(sc, reg, val)       \
  113         bus_space_write_1(sc->el_btag, sc->el_bhandle, reg, val)
  114 #define CSR_READ_1(sc, reg)             \
  115         bus_space_read_1(sc->el_btag, sc->el_bhandle, reg)
  116 
  117 #define EL_LOCK(_sc)            mtx_lock(&(_sc)->el_mtx)
  118 #define EL_UNLOCK(_sc)          mtx_unlock(&(_sc)->el_mtx)
  119 
  120 /* Probe routine.  See if the card is there and at the right place. */
  121 static int
  122 el_probe(device_t dev)
  123 {
  124         struct el_softc *sc;
  125         u_short base; /* Just for convenience */
  126         u_char station_addr[ETHER_ADDR_LEN];
  127         int i, rid;
  128 
  129         /* Grab some info for our structure */
  130         sc = device_get_softc(dev);
  131 
  132         if (isa_get_logicalid(dev))             /* skip PnP probes */
  133                 return (ENXIO);
  134 
  135         if ((base = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
  136                 return (ENXIO);
  137 
  138         /* First check the base */
  139         if((base < 0x280) || (base > 0x3f0)) {
  140                 device_printf(dev,
  141                     "ioaddr must be between 0x280 and 0x3f0\n");
  142                 return(ENXIO);
  143         }
  144 
  145         /* Temporarily map the resources. */
  146         rid = 0;
  147         sc->el_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
  148             0, ~0, EL_IOSIZ, RF_ACTIVE);
  149 
  150         if (sc->el_res == NULL)
  151                 return(ENXIO);
  152 
  153         sc->el_btag = rman_get_bustag(sc->el_res);
  154         sc->el_bhandle = rman_get_bushandle(sc->el_res);
  155         mtx_init(&sc->el_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
  156             MTX_DEF | MTX_RECURSE);
  157         EL_LOCK(sc);
  158 
  159         /* Now attempt to grab the station address from the PROM
  160          * and see if it contains the 3com vendor code.
  161          */
  162         dprintf(("Probing 3c501 at 0x%x...\n",base));
  163 
  164         /* Reset the board */
  165         dprintf(("Resetting board...\n"));
  166         CSR_WRITE_1(sc,EL_AC,EL_AC_RESET);
  167         DELAY(5);
  168         CSR_WRITE_1(sc,EL_AC,0);
  169         dprintf(("Reading station address...\n"));
  170         /* Now read the address */
  171         for(i=0;i<ETHER_ADDR_LEN;i++) {
  172                 CSR_WRITE_1(sc,EL_GPBL,i);
  173                 station_addr[i] = CSR_READ_1(sc,EL_EAW);
  174         }
  175 
  176         /* Now release resources */
  177         bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->el_res);
  178         EL_UNLOCK(sc);
  179         mtx_destroy(&sc->el_mtx);
  180 
  181         dprintf(("Address is %6D\n",station_addr, ":"));
  182 
  183         /* If the vendor code is ok, return a 1.  We'll assume that
  184          * whoever configured this system is right about the IRQ.
  185          */
  186         if((station_addr[0] != 0x02) || (station_addr[1] != 0x60)
  187            || (station_addr[2] != 0x8c)) {
  188                 dprintf(("Bad vendor code.\n"));
  189                 return(ENXIO);
  190         } else {
  191                 dprintf(("Vendor code ok.\n"));
  192                 /* Copy the station address into the arpcom structure */
  193                 bcopy(station_addr,sc->arpcom.ac_enaddr,ETHER_ADDR_LEN);
  194         }
  195 
  196         device_set_desc(dev, "3Com 3c501 Ethernet");
  197 
  198         return(0);
  199 }
  200 
  201 /* Do a hardware reset of the 3c501.  Do not call until after el_probe()! */
  202 static __inline void
  203 el_hardreset(xsc)
  204         void *xsc;
  205 {
  206         register struct el_softc *sc = xsc;
  207         register int j;
  208 
  209         /* First reset the board */
  210         CSR_WRITE_1(sc,EL_AC,EL_AC_RESET);
  211         DELAY(5);
  212         CSR_WRITE_1(sc,EL_AC,0);
  213 
  214         /* Then give it back its ethernet address.  Thanks to the mach
  215          * source code for this undocumented goodie...
  216          */
  217         for(j=0;j<ETHER_ADDR_LEN;j++)
  218                 CSR_WRITE_1(sc,j,sc->arpcom.ac_enaddr[j]);
  219 }
  220 
  221 /* Attach the interface to the kernel data structures.  By the time
  222  * this is called, we know that the card exists at the given I/O address.
  223  * We still assume that the IRQ given is correct.
  224  */
  225 static int
  226 el_attach(device_t dev)
  227 {
  228         struct el_softc *sc;
  229         struct ifnet *ifp;
  230         int rid, error;
  231 
  232         dprintf(("Attaching el%d...\n",device_get_unit(dev)));
  233 
  234         /* Get things pointing to the right places. */
  235         sc = device_get_softc(dev);
  236         ifp = &sc->arpcom.ac_if;
  237 
  238         rid = 0;
  239         sc->el_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
  240             0, ~0, EL_IOSIZ, RF_ACTIVE);
  241 
  242         if (sc->el_res == NULL)
  243                 return(ENXIO);
  244 
  245         rid = 0;
  246         sc->el_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  247             RF_SHAREABLE | RF_ACTIVE);
  248 
  249         if (sc->el_irq == NULL) {
  250                 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->el_res);
  251                 return(ENXIO);
  252         }
  253 
  254         error = bus_setup_intr(dev, sc->el_irq, INTR_TYPE_NET,
  255                 elintr, sc, &sc->el_intrhand);
  256 
  257         if (error) {
  258                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->el_irq);
  259                 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->el_res);
  260                 return(ENXIO);
  261         }
  262 
  263         /* Now reset the board */
  264         dprintf(("Resetting board...\n"));
  265         el_hardreset(sc);
  266 
  267         /* Initialize ifnet structure */
  268         ifp->if_softc = sc;
  269         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
  270         ifp->if_mtu = ETHERMTU;
  271         ifp->if_start = el_start;
  272         ifp->if_ioctl = el_ioctl;
  273         ifp->if_watchdog = el_watchdog;
  274         ifp->if_init = el_init;
  275         ifp->if_flags = (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX);
  276         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  277 
  278         /* Now we can attach the interface */
  279         dprintf(("Attaching interface...\n"));
  280         ether_ifattach(ifp, sc->arpcom.ac_enaddr);
  281 
  282         dprintf(("el_attach() finished.\n"));
  283         return(0);
  284 }
  285 
  286 static int el_detach(dev)
  287         device_t dev;
  288 {
  289         struct el_softc *sc;
  290         struct ifnet *ifp;
  291 
  292         sc = device_get_softc(dev);
  293         ifp = &sc->arpcom.ac_if;
  294 
  295         el_stop(sc);
  296         EL_LOCK(sc);
  297         ether_ifdetach(ifp);
  298         bus_teardown_intr(dev, sc->el_irq, sc->el_intrhand);
  299         bus_release_resource(dev, SYS_RES_IRQ, 0, sc->el_irq);
  300         bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->el_res);
  301         EL_UNLOCK(sc);
  302         mtx_destroy(&sc->el_mtx);
  303 
  304         return(0);
  305 }
  306 
  307 static int
  308 el_shutdown(dev)
  309         device_t dev;
  310 {
  311         struct el_softc *sc;
  312 
  313         sc = device_get_softc(dev);
  314         el_stop(sc);
  315         return(0);
  316 }
  317 
  318 /* This routine resets the interface. */
  319 static void 
  320 el_reset(xsc)
  321         void *xsc;
  322 {
  323         struct el_softc *sc = xsc;
  324 
  325         dprintf(("elreset()\n"));
  326         el_stop(sc);
  327         el_init(sc);
  328 }
  329 
  330 static void el_stop(xsc)
  331         void *xsc;
  332 {
  333         struct el_softc *sc = xsc;
  334 
  335         EL_LOCK(sc);
  336         CSR_WRITE_1(sc,EL_AC,0);
  337         el_hardreset(sc);
  338         EL_UNLOCK(sc);
  339 }
  340 
  341 /* Initialize interface.  */
  342 static void 
  343 el_init(xsc)
  344         void *xsc;
  345 {
  346         struct el_softc *sc = xsc;
  347         struct ifnet *ifp;
  348 
  349         /* Set up pointers */
  350         ifp = &sc->arpcom.ac_if;
  351 
  352         /* If address not known, do nothing. */
  353         if(TAILQ_EMPTY(&ifp->if_addrhead)) /* XXX unlikely */
  354                 return;
  355 
  356         EL_LOCK(sc);
  357 
  358         /* First, reset the board. */
  359         dprintf(("Resetting board...\n"));
  360         el_hardreset(sc);
  361 
  362         /* Configure rx */
  363         dprintf(("Configuring rx...\n"));
  364         if(ifp->if_flags & IFF_PROMISC)
  365                 CSR_WRITE_1(sc,EL_RXC,
  366                     (EL_RXC_PROMISC|EL_RXC_ABROAD|EL_RXC_AMULTI|
  367                     EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
  368         else
  369                 CSR_WRITE_1(sc,EL_RXC,
  370                     (EL_RXC_ABROAD|EL_RXC_AMULTI|
  371                     EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
  372         CSR_WRITE_1(sc,EL_RBC,0);
  373 
  374         /* Configure TX */
  375         dprintf(("Configuring tx...\n"));
  376         CSR_WRITE_1(sc,EL_TXC,0);
  377 
  378         /* Start reception */
  379         dprintf(("Starting reception...\n"));
  380         CSR_WRITE_1(sc,EL_AC,(EL_AC_IRQE|EL_AC_RX));
  381 
  382         /* Set flags appropriately */
  383         ifp->if_flags |= IFF_RUNNING;
  384         ifp->if_flags &= ~IFF_OACTIVE;
  385 
  386         /* And start output. */
  387         el_start(ifp);
  388 
  389         EL_UNLOCK(sc);
  390 }
  391 
  392 /* Start output on interface.  Get datagrams from the queue and output
  393  * them, giving the receiver a chance between datagrams.  Call only
  394  * from splimp or interrupt level!
  395  */
  396 static void
  397 el_start(struct ifnet *ifp)
  398 {
  399         struct el_softc *sc;
  400         struct mbuf *m, *m0;
  401         int i, len, retries, done;
  402 
  403         /* Get things pointing in the right directions */
  404         sc = ifp->if_softc;
  405 
  406         dprintf(("el_start()...\n"));
  407         EL_LOCK(sc);
  408 
  409         /* Don't do anything if output is active */
  410         if(sc->arpcom.ac_if.if_flags & IFF_OACTIVE)
  411                 return;
  412         sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
  413 
  414         /* The main loop.  They warned me against endless loops, but
  415          * would I listen?  NOOO....
  416          */
  417         while(1) {
  418                 /* Dequeue the next datagram */
  419                 IF_DEQUEUE(&sc->arpcom.ac_if.if_snd,m0);
  420 
  421                 /* If there's nothing to send, return. */
  422                 if(m0 == NULL) {
  423                         sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
  424                         EL_UNLOCK(sc);
  425                         return;
  426                 }
  427 
  428                 /* Disable the receiver */
  429                 CSR_WRITE_1(sc,EL_AC,EL_AC_HOST);
  430                 CSR_WRITE_1(sc,EL_RBC,0);
  431 
  432                 /* Copy the datagram to the buffer. */
  433                 len = 0;
  434                 for(m = m0; m != NULL; m = m->m_next) {
  435                         if(m->m_len == 0)
  436                                 continue;
  437                         bcopy(mtod(m,caddr_t),sc->el_pktbuf+len,m->m_len);
  438                         len += m->m_len;
  439                 }
  440                 m_freem(m0);
  441 
  442                 len = max(len,ETHER_MIN_LEN);
  443 
  444                 /* Give the packet to the bpf, if any */
  445                 BPF_TAP(&sc->arpcom.ac_if, sc->el_pktbuf, len);
  446 
  447                 /* Transfer datagram to board */
  448                 dprintf(("el: xfr pkt length=%d...\n",len));
  449                 i = EL_BUFSIZ - len;
  450                 CSR_WRITE_1(sc,EL_GPBL,(i & 0xff));
  451                 CSR_WRITE_1(sc,EL_GPBH,((i>>8)&0xff));
  452                 bus_space_write_multi_1(sc->el_btag, sc->el_bhandle,
  453                     EL_BUF, sc->el_pktbuf, len);
  454 
  455                 /* Now transmit the datagram */
  456                 retries=0;
  457                 done=0;
  458                 while(!done) {
  459                         if(el_xmit(sc,len)) { /* Something went wrong */
  460                                 done = -1;
  461                                 break;
  462                         }
  463                         /* Check out status */
  464                         i = CSR_READ_1(sc,EL_TXS);
  465                         dprintf(("tx status=0x%x\n",i));
  466                         if(!(i & EL_TXS_READY)) {
  467                                 dprintf(("el: err txs=%x\n",i));
  468                                 sc->arpcom.ac_if.if_oerrors++;
  469                                 if(i & (EL_TXS_COLL|EL_TXS_COLL16)) {
  470                                         if((!(i & EL_TXC_DCOLL16)) && retries < 15) {
  471                                                 retries++;
  472                                                 CSR_WRITE_1(sc,EL_AC,EL_AC_HOST);
  473                                         }
  474                                 }
  475                                 else
  476                                         done = 1;
  477                         }
  478                         else {
  479                                 sc->arpcom.ac_if.if_opackets++;
  480                                 done = 1;
  481                         }
  482                 }
  483                 if(done == -1)  /* Packet not transmitted */
  484                         continue;
  485 
  486                 /* Now give the card a chance to receive.
  487                  * Gotta love 3c501s...
  488                  */
  489                 (void)CSR_READ_1(sc,EL_AS);
  490                 CSR_WRITE_1(sc,EL_AC,(EL_AC_IRQE|EL_AC_RX));
  491                 EL_UNLOCK(sc);
  492                 /* Interrupt here */
  493                 EL_LOCK(sc);
  494         }
  495 }
  496 
  497 /* This function actually attempts to transmit a datagram downloaded
  498  * to the board.  Call at splimp or interrupt, after downloading data!
  499  * Returns 0 on success, non-0 on failure
  500  */
  501 static int
  502 el_xmit(struct el_softc *sc,int len)
  503 {
  504         int gpl;
  505         int i;
  506 
  507         gpl = EL_BUFSIZ - len;
  508         dprintf(("el: xmit..."));
  509         CSR_WRITE_1(sc,EL_GPBL,(gpl & 0xff));
  510         CSR_WRITE_1(sc,EL_GPBH,((gpl>>8)&0xff));
  511         CSR_WRITE_1(sc,EL_AC,EL_AC_TXFRX);
  512         i = 20000;
  513         while((CSR_READ_1(sc,EL_AS) & EL_AS_TXBUSY) && (i>0))
  514                 i--;
  515         if(i == 0) {
  516                 dprintf(("tx not ready\n"));
  517                 sc->arpcom.ac_if.if_oerrors++;
  518                 return(-1);
  519         }
  520         dprintf(("%d cycles.\n",(20000-i)));
  521         return(0);
  522 }
  523 
  524 /* Pass a packet up to the higher levels. */
  525 static __inline void
  526 elread(struct el_softc *sc,caddr_t buf,int len)
  527 {
  528         struct ifnet *ifp = &sc->arpcom.ac_if;
  529         struct mbuf *m;
  530 
  531         /*
  532          * Put packet into an mbuf chain
  533          */
  534         m = elget(buf,len,ifp);
  535         if(m == 0)
  536                 return;
  537 
  538         (*ifp->if_input)(ifp,m);
  539 }
  540 
  541 /* controller interrupt */
  542 static void
  543 elintr(void *xsc)
  544 {
  545         register struct el_softc *sc;
  546         int stat, rxstat, len, done;
  547 
  548 
  549         /* Get things pointing properly */
  550         sc = xsc;
  551         EL_LOCK(sc);
  552         dprintf(("elintr: "));
  553 
  554         /* Check board status */
  555         stat = CSR_READ_1(sc,EL_AS);
  556         if(stat & EL_AS_RXBUSY) {
  557                 (void)CSR_READ_1(sc,EL_RXC);
  558                 CSR_WRITE_1(sc,EL_AC,(EL_AC_IRQE|EL_AC_RX));
  559                 EL_UNLOCK(sc);
  560                 return;
  561         }
  562 
  563         done = 0;
  564         while(!done) {
  565                 rxstat = CSR_READ_1(sc,EL_RXS);
  566                 if(rxstat & EL_RXS_STALE) {
  567                         (void)CSR_READ_1(sc,EL_RXC);
  568                         CSR_WRITE_1(sc,EL_AC,(EL_AC_IRQE|EL_AC_RX));
  569                         EL_UNLOCK(sc);
  570                         return;
  571                 }
  572 
  573                 /* If there's an overflow, reinit the board. */
  574                 if(!(rxstat & EL_RXS_NOFLOW)) {
  575                         dprintf(("overflow.\n"));
  576                         el_hardreset(sc);
  577                         /* Put board back into receive mode */
  578                         if(sc->arpcom.ac_if.if_flags & IFF_PROMISC)
  579                                 CSR_WRITE_1(sc,EL_RXC,
  580                                     (EL_RXC_PROMISC|EL_RXC_ABROAD|
  581                                     EL_RXC_AMULTI|EL_RXC_AGF|EL_RXC_DSHORT|
  582                                     EL_RXC_DDRIB|EL_RXC_DOFLOW));
  583                         else
  584                                 CSR_WRITE_1(sc,EL_RXC,
  585                                     (EL_RXC_ABROAD|
  586                                     EL_RXC_AMULTI|EL_RXC_AGF|EL_RXC_DSHORT|
  587                                     EL_RXC_DDRIB|EL_RXC_DOFLOW));
  588                         (void)CSR_READ_1(sc,EL_AS);
  589                         CSR_WRITE_1(sc,EL_RBC,0);
  590                         (void)CSR_READ_1(sc,EL_RXC);
  591                         CSR_WRITE_1(sc,EL_AC,(EL_AC_IRQE|EL_AC_RX));
  592                         EL_UNLOCK(sc);
  593                         return;
  594                 }
  595 
  596                 /* Incoming packet */
  597                 len = CSR_READ_1(sc,EL_RBL);
  598                 len |= CSR_READ_1(sc,EL_RBH) << 8;
  599                 dprintf(("receive len=%d rxstat=%x ",len,rxstat));
  600                 CSR_WRITE_1(sc,EL_AC,EL_AC_HOST);
  601 
  602                 /* If packet too short or too long, restore rx mode and return
  603                  */
  604                 if((len <= sizeof(struct ether_header)) || (len > ETHER_MAX_LEN)) {
  605                         if(sc->arpcom.ac_if.if_flags & IFF_PROMISC)
  606                                 CSR_WRITE_1(sc,EL_RXC,
  607                                     (EL_RXC_PROMISC|EL_RXC_ABROAD|
  608                                     EL_RXC_AMULTI|EL_RXC_AGF|EL_RXC_DSHORT|
  609                                     EL_RXC_DDRIB|EL_RXC_DOFLOW));
  610                         else
  611                                 CSR_WRITE_1(sc,EL_RXC,
  612                                     (EL_RXC_ABROAD|
  613                                     EL_RXC_AMULTI|EL_RXC_AGF|EL_RXC_DSHORT|
  614                                     EL_RXC_DDRIB|EL_RXC_DOFLOW));
  615                         (void)CSR_READ_1(sc,EL_AS);
  616                         CSR_WRITE_1(sc,EL_RBC,0);
  617                         (void)CSR_READ_1(sc,EL_RXC);
  618                         CSR_WRITE_1(sc,EL_AC,(EL_AC_IRQE|EL_AC_RX));
  619                         EL_UNLOCK(sc);
  620                         return;
  621                 }
  622 
  623                 sc->arpcom.ac_if.if_ipackets++;
  624 
  625                 /* Copy the data into our buffer */
  626                 CSR_WRITE_1(sc,EL_GPBL,0);
  627                 CSR_WRITE_1(sc,EL_GPBH,0);
  628                 bus_space_read_multi_1(sc->el_btag, sc->el_bhandle,
  629                     EL_BUF, sc->el_pktbuf, len);
  630                 CSR_WRITE_1(sc,EL_RBC,0);
  631                 CSR_WRITE_1(sc,EL_AC,EL_AC_RX);
  632                 dprintf(("%6D-->",sc->el_pktbuf+6,":"));
  633                 dprintf(("%6D\n",sc->el_pktbuf,":"));
  634 
  635                 /* Pass data up to upper levels */
  636                 elread(sc,(caddr_t)(sc->el_pktbuf),len);
  637 
  638                 /* Is there another packet? */
  639                 stat = CSR_READ_1(sc,EL_AS);
  640 
  641                 /* If so, do it all again (i.e. don't set done to 1) */
  642                 if(!(stat & EL_AS_RXBUSY))
  643                         dprintf(("<rescan> "));
  644                 else
  645                         done = 1;
  646         }
  647 
  648         (void)CSR_READ_1(sc,EL_RXC);
  649         CSR_WRITE_1(sc,EL_AC,(EL_AC_IRQE|EL_AC_RX));
  650         EL_UNLOCK(sc);
  651         return;
  652 }
  653 
  654 /*
  655  * Pull read data off an interface.
  656  * Len is length of data, with local net header stripped.
  657  */
  658 static struct mbuf *
  659 elget(buf, totlen, ifp)
  660         caddr_t buf;
  661         int totlen;
  662         struct ifnet *ifp;
  663 {
  664         struct mbuf *top, **mp, *m;
  665         int len;
  666         register caddr_t cp;
  667         char *epkt;
  668 
  669         buf += sizeof(struct ether_header);
  670         cp = buf;
  671         epkt = cp + totlen;
  672 
  673         MGETHDR(m, M_DONTWAIT, MT_DATA);
  674         if (m == 0)
  675                 return (0);
  676         m->m_pkthdr.rcvif = ifp;
  677         m->m_pkthdr.len = totlen;
  678         m->m_len = MHLEN;
  679         top = 0;
  680         mp = &top;
  681         while (totlen > 0) {
  682                 if (top) {
  683                         MGET(m, M_DONTWAIT, MT_DATA);
  684                         if (m == 0) {
  685                                 m_freem(top);
  686                                 return (0);
  687                         }
  688                         m->m_len = MLEN;
  689                 }
  690                 len = min(totlen, epkt - cp);
  691                 if (len >= MINCLSIZE) {
  692                         MCLGET(m, M_DONTWAIT);
  693                         if (m->m_flags & M_EXT)
  694                                 m->m_len = len = min(len, MCLBYTES);
  695                         else
  696                                 len = m->m_len;
  697                 } else {
  698                         /*
  699                          * Place initial small packet/header at end of mbuf.
  700                          */
  701                         if (len < m->m_len) {
  702                                 if (top == 0 && len + max_linkhdr <= m->m_len)
  703                                         m->m_data += max_linkhdr;
  704                                 m->m_len = len;
  705                         } else
  706                                 len = m->m_len;
  707                 }
  708                 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
  709                 cp += len;
  710                 *mp = m;
  711                 mp = &m->m_next;
  712                 totlen -= len;
  713                 if (cp == epkt)
  714                         cp = buf;
  715         }
  716         return (top);
  717 }
  718 
  719 /*
  720  * Process an ioctl request. This code needs some work - it looks
  721  *      pretty ugly.
  722  */
  723 static int
  724 el_ioctl(ifp, command, data)
  725         register struct ifnet *ifp;
  726         u_long command;
  727         caddr_t data;
  728 {
  729         int error = 0;
  730         struct el_softc *sc;
  731 
  732         sc = ifp->if_softc;
  733         EL_LOCK(sc);
  734 
  735         switch (command) {
  736         case SIOCSIFFLAGS:
  737                 /*
  738                  * If interface is marked down and it is running, then stop it
  739                  */
  740                 if (((ifp->if_flags & IFF_UP) == 0) &&
  741                     (ifp->if_flags & IFF_RUNNING)) {
  742                         el_stop(ifp->if_softc);
  743                         ifp->if_flags &= ~IFF_RUNNING;
  744                 } else {
  745                 /*
  746                  * If interface is marked up and it is stopped, then start it
  747                  */
  748                         if ((ifp->if_flags & IFF_UP) &&
  749                             ((ifp->if_flags & IFF_RUNNING) == 0))
  750                                 el_init(ifp->if_softc);
  751                 }
  752                 break;
  753         default:
  754                 error = ether_ioctl(ifp, command, data);
  755                 break;
  756         }
  757         EL_UNLOCK(sc);
  758         return (error);
  759 }
  760 
  761 /* Device timeout routine */
  762 static void
  763 el_watchdog(struct ifnet *ifp)
  764 {
  765         log(LOG_ERR,"%s: device timeout\n", ifp->if_xname);
  766         ifp->if_oerrors++;
  767         el_reset(ifp->if_softc);
  768 }

Cache object: 55b7f949fa9bc25fbb7ec26e95e7c555


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