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

Cache object: 92ba5e50f860425730dc0f9f279752aa


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