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

Cache object: 22fa981c28e098cca9bae657cb32d5d5


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