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/dev/isa/if_el.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 /*      $NetBSD: if_el.c,v 1.70 2003/01/15 22:01:16 bouyer Exp $        */
    2 
    3 /*
    4  * Copyright (c) 1994, Matthew E. Kimmel.  Permission is hereby granted
    5  * to use, copy, modify and distribute this software provided that both
    6  * the copyright notice and this permission notice appear in all copies
    7  * of the software, derivative works or modified versions, and any
    8  * portions thereof.
    9  */
   10 
   11 /*
   12  * 3COM Etherlink 3C501 device driver
   13  */
   14 
   15 /*
   16  * Bugs/possible improvements:
   17  *      - Does not currently support DMA
   18  *      - Does not currently support multicasts
   19  */
   20 
   21 #include <sys/cdefs.h>
   22 __KERNEL_RCSID(0, "$NetBSD: if_el.c,v 1.70 2003/01/15 22:01:16 bouyer Exp $");
   23 
   24 #include "opt_inet.h"
   25 #include "opt_ns.h"
   26 #include "bpfilter.h"
   27 #include "rnd.h"
   28 
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/errno.h>
   32 #include <sys/ioctl.h>
   33 #include <sys/mbuf.h>
   34 #include <sys/socket.h>
   35 #include <sys/syslog.h>
   36 #include <sys/device.h>
   37 #if NRND > 0
   38 #include <sys/rnd.h>
   39 #endif
   40 
   41 #include <net/if.h>
   42 #include <net/if_dl.h>
   43 #include <net/if_types.h>
   44 
   45 #include <net/if_ether.h>
   46 
   47 #ifdef INET
   48 #include <netinet/in.h>
   49 #include <netinet/in_systm.h>
   50 #include <netinet/in_var.h>
   51 #include <netinet/ip.h>
   52 #include <netinet/if_inarp.h>
   53 #endif
   54 
   55 #ifdef NS
   56 #include <netns/ns.h>
   57 #include <netns/ns_if.h>
   58 #endif
   59 
   60 #if NBPFILTER > 0
   61 #include <net/bpf.h>
   62 #include <net/bpfdesc.h>
   63 #endif
   64 
   65 #include <machine/cpu.h>
   66 #include <machine/intr.h>
   67 #include <machine/bus.h>
   68 
   69 #include <dev/isa/isavar.h>
   70 #include <dev/isa/if_elreg.h>
   71 
   72 /* for debugging convenience */
   73 #ifdef EL_DEBUG
   74 #define DPRINTF(x) printf x
   75 #else
   76 #define DPRINTF(x)
   77 #endif
   78 
   79 /*
   80  * per-line info and status
   81  */
   82 struct el_softc {
   83         struct device sc_dev;
   84         void *sc_ih;
   85 
   86         struct ethercom sc_ethercom;    /* ethernet common */
   87         bus_space_tag_t sc_iot;         /* bus space identifier */
   88         bus_space_handle_t sc_ioh;      /* i/o handle */
   89 
   90 #if NRND > 0
   91         rndsource_element_t rnd_source;
   92 #endif
   93 };
   94 
   95 /*
   96  * prototypes
   97  */
   98 int elintr __P((void *));
   99 void elinit __P((struct el_softc *));
  100 int elioctl __P((struct ifnet *, u_long, caddr_t));
  101 void elstart __P((struct ifnet *));
  102 void elwatchdog __P((struct ifnet *));
  103 void elreset __P((struct el_softc *));
  104 void elstop __P((struct el_softc *));
  105 static int el_xmit __P((struct el_softc *));
  106 void elread __P((struct el_softc *, int));
  107 struct mbuf *elget __P((struct el_softc *sc, int));
  108 static inline void el_hardreset __P((struct el_softc *));
  109 
  110 int elprobe __P((struct device *, struct cfdata *, void *));
  111 void elattach __P((struct device *, struct device *, void *));
  112 
  113 CFATTACH_DECL(el, sizeof(struct el_softc),
  114     elprobe, elattach, NULL, NULL);
  115 
  116 /*
  117  * Probe routine.
  118  *
  119  * See if the card is there and at the right place.
  120  * (XXX - cgd -- needs help)
  121  */
  122 int
  123 elprobe(parent, match, aux)
  124         struct device *parent;
  125         struct cfdata *match;
  126         void *aux;
  127 {
  128         struct isa_attach_args *ia = aux;
  129         bus_space_tag_t iot = ia->ia_iot;
  130         bus_space_handle_t ioh;
  131         int iobase;
  132         u_int8_t station_addr[ETHER_ADDR_LEN];
  133         u_int8_t i;
  134         int rval;
  135 
  136         rval = 0;
  137 
  138         if (ia->ia_nio < 1)
  139                 return (0);
  140         if (ia->ia_nirq < 1)
  141                 return (0);
  142 
  143         if (ISA_DIRECT_CONFIG(ia))
  144                 return (0);
  145 
  146         iobase = ia->ia_io[0].ir_addr;
  147 
  148         if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT)
  149                 return (0);
  150         if (ia->ia_irq[0].ir_irq == ISACF_IRQ_DEFAULT)
  151                 return (0);
  152 
  153         /* First check the base. */
  154         if (iobase < 0x200 || iobase > 0x3f0)
  155                 return 0;
  156 
  157         /* Map i/o space. */
  158         if (bus_space_map(iot, iobase, 16, 0, &ioh))
  159                 return 0;
  160 
  161         /*
  162          * Now attempt to grab the station address from the PROM and see if it
  163          * contains the 3com vendor code.
  164          */
  165         DPRINTF(("Probing 3c501 at 0x%x...\n", iobase));
  166 
  167         /* Reset the board. */
  168         DPRINTF(("Resetting board...\n"));
  169         bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET);
  170         delay(5);
  171         bus_space_write_1(iot, ioh, EL_AC, 0);
  172 
  173         /* Now read the address. */
  174         DPRINTF(("Reading station address...\n"));
  175         for (i = 0; i < ETHER_ADDR_LEN; i++) {
  176                 bus_space_write_1(iot, ioh, EL_GPBL, i);
  177                 station_addr[i] = bus_space_read_1(iot, ioh, EL_EAW);
  178         }
  179         DPRINTF(("Address is %s\n", ether_sprintf(station_addr)));
  180 
  181         /*
  182          * If the vendor code is ok, return a 1.  We'll assume that whoever
  183          * 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                 goto out;
  189         }
  190         DPRINTF(("Vendor code ok.\n"));
  191 
  192         ia->ia_nio = 1;
  193         ia->ia_io[0].ir_size = 16;
  194 
  195         ia->ia_nirq = 1;
  196 
  197         ia->ia_niomem = 0;
  198         ia->ia_ndrq = 0;
  199 
  200         rval = 1;
  201 
  202  out:
  203         bus_space_unmap(iot, ioh, 16);
  204         return rval;
  205 }
  206 
  207 /*
  208  * Attach the interface to the kernel data structures.  By the time this is
  209  * called, we know that the card exists at the given I/O address.  We still
  210  * assume that the IRQ given is correct.
  211  */
  212 void
  213 elattach(parent, self, aux)
  214         struct device *parent, *self;
  215         void *aux;
  216 {
  217         struct el_softc *sc = (void *)self;
  218         struct isa_attach_args *ia = aux;
  219         bus_space_tag_t iot = ia->ia_iot;
  220         bus_space_handle_t ioh;
  221         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  222         u_int8_t myaddr[ETHER_ADDR_LEN];
  223         u_int8_t i;
  224 
  225         printf("\n");
  226 
  227         DPRINTF(("Attaching %s...\n", sc->sc_dev.dv_xname));
  228 
  229         /* Map i/o space. */
  230         if (bus_space_map(iot, ia->ia_io[0].ir_addr, 16, 0, &ioh)) {
  231                 printf("%s: can't map i/o space\n", self->dv_xname);
  232                 return;
  233         }
  234 
  235         sc->sc_iot = iot;
  236         sc->sc_ioh = ioh;
  237 
  238         /* Reset the board. */
  239         bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET);
  240         delay(5);
  241         bus_space_write_1(iot, ioh, EL_AC, 0);
  242 
  243         /* Now read the address. */
  244         for (i = 0; i < ETHER_ADDR_LEN; i++) {
  245                 bus_space_write_1(iot, ioh, EL_GPBL, i);
  246                 myaddr[i] = bus_space_read_1(iot, ioh, EL_EAW);
  247         }
  248 
  249         /* Stop the board. */
  250         elstop(sc);
  251 
  252         /* Initialize ifnet structure. */
  253         strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
  254         ifp->if_softc = sc;
  255         ifp->if_start = elstart;
  256         ifp->if_ioctl = elioctl;
  257         ifp->if_watchdog = elwatchdog;
  258         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
  259         IFQ_SET_READY(&ifp->if_snd);
  260 
  261         /* Now we can attach the interface. */
  262         DPRINTF(("Attaching interface...\n"));
  263         if_attach(ifp);
  264         ether_ifattach(ifp, myaddr);
  265 
  266         /* Print out some information for the user. */
  267         printf("%s: address %s\n", self->dv_xname, ether_sprintf(myaddr));
  268 
  269         sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
  270             IST_EDGE, IPL_NET, elintr, sc);
  271 
  272 #if NRND > 0
  273         DPRINTF(("Attaching to random...\n"));
  274         rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
  275                           RND_TYPE_NET, 0);
  276 #endif
  277 
  278         DPRINTF(("elattach() finished.\n"));
  279 }
  280 
  281 /*
  282  * Reset interface.
  283  */
  284 void
  285 elreset(sc)
  286         struct el_softc *sc;
  287 {
  288         int s;
  289 
  290         DPRINTF(("elreset()\n"));
  291         s = splnet();
  292         elstop(sc);
  293         elinit(sc);
  294         splx(s);
  295 }
  296 
  297 /*
  298  * Stop interface.
  299  */
  300 void
  301 elstop(sc)
  302         struct el_softc *sc;
  303 {
  304 
  305         bus_space_write_1(sc->sc_iot, sc->sc_ioh, EL_AC, 0);
  306 }
  307 
  308 /*
  309  * Do a hardware reset of the board, and upload the ethernet address again in
  310  * case the board forgets.
  311  */
  312 static inline void
  313 el_hardreset(sc)
  314         struct el_softc *sc;
  315 {
  316         bus_space_tag_t iot = sc->sc_iot;
  317         bus_space_handle_t ioh = sc->sc_ioh;
  318         int i;
  319 
  320         bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET);
  321         delay(5);
  322         bus_space_write_1(iot, ioh, EL_AC, 0);
  323 
  324         for (i = 0; i < ETHER_ADDR_LEN; i++)
  325                 bus_space_write_1(iot, ioh, i,
  326                     LLADDR(sc->sc_ethercom.ec_if.if_sadl)[i]);
  327 }
  328 
  329 /*
  330  * Initialize interface.
  331  */
  332 void
  333 elinit(sc)
  334         struct el_softc *sc;
  335 {
  336         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  337         bus_space_tag_t iot = sc->sc_iot;
  338         bus_space_handle_t ioh = sc->sc_ioh;
  339 
  340         /* First, reset the board. */
  341         el_hardreset(sc);
  342 
  343         /* Configure rx. */
  344         DPRINTF(("Configuring rx...\n"));
  345         if (ifp->if_flags & IFF_PROMISC)
  346                 bus_space_write_1(iot, ioh, EL_RXC,
  347                     EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
  348                     EL_RXC_DOFLOW | EL_RXC_PROMISC);
  349         else
  350                 bus_space_write_1(iot, ioh, EL_RXC,
  351                     EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
  352                     EL_RXC_DOFLOW | EL_RXC_ABROAD);
  353         bus_space_write_1(iot, ioh, EL_RBC, 0);
  354 
  355         /* Configure TX. */
  356         DPRINTF(("Configuring tx...\n"));
  357         bus_space_write_1(iot, ioh, EL_TXC, 0);
  358 
  359         /* Start reception. */
  360         DPRINTF(("Starting reception...\n"));
  361         bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
  362 
  363         /* Set flags appropriately. */
  364         ifp->if_flags |= IFF_RUNNING;
  365         ifp->if_flags &= ~IFF_OACTIVE;
  366 
  367         /* And start output. */
  368         elstart(ifp);
  369 }
  370 
  371 /*
  372  * Start output on interface.  Get datagrams from the queue and output them,
  373  * giving the receiver a chance between datagrams.  Call only from splnet or
  374  * interrupt level!
  375  */
  376 void
  377 elstart(ifp)
  378         struct ifnet *ifp;
  379 {
  380         struct el_softc *sc = ifp->if_softc;
  381         bus_space_tag_t iot = sc->sc_iot;
  382         bus_space_handle_t ioh = sc->sc_ioh;
  383         struct mbuf *m, *m0;
  384         int s, i, off, retries;
  385 
  386         DPRINTF(("elstart()...\n"));
  387         s = splnet();
  388 
  389         /* Don't do anything if output is active. */
  390         if ((ifp->if_flags & IFF_OACTIVE) != 0) {
  391                 splx(s);
  392                 return;
  393         }
  394 
  395         ifp->if_flags |= IFF_OACTIVE;
  396 
  397         /*
  398          * The main loop.  They warned me against endless loops, but would I
  399          * listen?  NOOO....
  400          */
  401         for (;;) {
  402                 /* Dequeue the next datagram. */
  403                 IFQ_DEQUEUE(&ifp->if_snd, m0);
  404 
  405                 /* If there's nothing to send, return. */
  406                 if (m0 == 0)
  407                         break;
  408 
  409 #if NBPFILTER > 0
  410                 /* Give the packet to the bpf, if any. */
  411                 if (ifp->if_bpf)
  412                         bpf_mtap(ifp->if_bpf, m0);
  413 #endif
  414 
  415                 /* Disable the receiver. */
  416                 bus_space_write_1(iot, ioh, EL_AC, EL_AC_HOST);
  417                 bus_space_write_1(iot, ioh, EL_RBC, 0);
  418 
  419                 /* Transfer datagram to board. */
  420                 DPRINTF(("el: xfr pkt length=%d...\n", m0->m_pkthdr.len));
  421                 off = EL_BUFSIZ - max(m0->m_pkthdr.len,
  422                     ETHER_MIN_LEN - ETHER_CRC_LEN);
  423 #ifdef DIAGNOSTIC
  424                 if ((off & 0xffff) != off)
  425                         printf("%s: bogus off 0x%x\n",
  426                             sc->sc_dev.dv_xname, off);
  427 #endif
  428                 bus_space_write_1(iot, ioh, EL_GPBL, off & 0xff);
  429                 bus_space_write_1(iot, ioh, EL_GPBH, (off >> 8) & 0xff);
  430 
  431                 /* Copy the datagram to the buffer. */
  432                 for (m = m0; m != 0; m = m->m_next)
  433                         bus_space_write_multi_1(iot, ioh, EL_BUF,
  434                             mtod(m, u_int8_t *), m->m_len);
  435                 for (i = 0;
  436                     i < ETHER_MIN_LEN - ETHER_CRC_LEN - m0->m_pkthdr.len; i++)
  437                         bus_space_write_1(iot, ioh, EL_BUF, 0);
  438 
  439                 m_freem(m0);
  440 
  441                 /* Now transmit the datagram. */
  442                 retries = 0;
  443                 for (;;) {
  444                         bus_space_write_1(iot, ioh, EL_GPBL, off & 0xff);
  445                         bus_space_write_1(iot, ioh, EL_GPBH, (off >> 8) & 0xff);
  446                         if (el_xmit(sc)) {
  447                                 ifp->if_oerrors++;
  448                                 break;
  449                         }
  450                         /* Check out status. */
  451                         i = bus_space_read_1(iot, ioh, EL_TXS);
  452                         DPRINTF(("tx status=0x%x\n", i));
  453                         if ((i & EL_TXS_READY) == 0) {
  454                                 DPRINTF(("el: err txs=%x\n", i));
  455                                 if (i & (EL_TXS_COLL | EL_TXS_COLL16)) {
  456                                         ifp->if_collisions++;
  457                                         if ((i & EL_TXC_DCOLL16) == 0 &&
  458                                             retries < 15) {
  459                                                 retries++;
  460                                                 bus_space_write_1(iot, ioh,
  461                                                     EL_AC, EL_AC_HOST);
  462                                         }
  463                                 } else {
  464                                         ifp->if_oerrors++;
  465                                         break;
  466                                 }
  467                         } else {
  468                                 ifp->if_opackets++;
  469                                 break;
  470                         }
  471                 }
  472 
  473                 /*
  474                  * Now give the card a chance to receive.
  475                  * Gotta love 3c501s...
  476                  */
  477                 (void)bus_space_read_1(iot, ioh, EL_AS);
  478                 bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
  479                 splx(s);
  480                 /* Interrupt here. */
  481                 s = splnet();
  482         }
  483 
  484         (void)bus_space_read_1(iot, ioh, EL_AS);
  485         bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
  486         ifp->if_flags &= ~IFF_OACTIVE;
  487         splx(s);
  488 }
  489 
  490 /*
  491  * This function actually attempts to transmit a datagram downloaded to the
  492  * board.  Call at splnet or interrupt, after downloading data!  Returns 0 on
  493  * success, non-0 on failure.
  494  */
  495 static int
  496 el_xmit(sc)
  497         struct el_softc *sc;
  498 {
  499         bus_space_tag_t iot = sc->sc_iot;
  500         bus_space_handle_t ioh = sc->sc_ioh;
  501         int i;
  502 
  503         /*
  504          * XXX
  505          * This busy-waits for the tx completion.  Can we get an interrupt
  506          * instead?
  507          */
  508 
  509         DPRINTF(("el: xmit..."));
  510         bus_space_write_1(iot, ioh, EL_AC, EL_AC_TXFRX);
  511         i = 20000;
  512         while ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_TXBUSY) && (i > 0))
  513                 i--;
  514         if (i == 0) {
  515                 DPRINTF(("tx not ready\n"));
  516                 return -1;
  517         }
  518         DPRINTF(("%d cycles.\n", 20000 - i));
  519         return 0;
  520 }
  521 
  522 /*
  523  * Controller interrupt.
  524  */
  525 int
  526 elintr(arg)
  527         void *arg;
  528 {
  529         struct el_softc *sc = arg;
  530         bus_space_tag_t iot = sc->sc_iot;
  531         bus_space_handle_t ioh = sc->sc_ioh;
  532         u_int8_t rxstat;
  533         int len;
  534 
  535         DPRINTF(("elintr: "));
  536 
  537         /* Check board status. */
  538         if ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_RXBUSY) != 0) {
  539                 (void)bus_space_read_1(iot, ioh, EL_RXC);
  540                 bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
  541                 return 0;
  542         }
  543 
  544         for (;;) {
  545                 rxstat = bus_space_read_1(iot, ioh, EL_RXS);
  546                 if (rxstat & EL_RXS_STALE)
  547                         break;
  548 
  549                 /* If there's an overflow, reinit the board. */
  550                 if ((rxstat & EL_RXS_NOFLOW) == 0) {
  551                         DPRINTF(("overflow.\n"));
  552                         el_hardreset(sc);
  553                         /* Put board back into receive mode. */
  554                         if (sc->sc_ethercom.ec_if.if_flags & IFF_PROMISC)
  555                                 bus_space_write_1(iot, ioh, EL_RXC,
  556                                     EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
  557                                     EL_RXC_DOFLOW | EL_RXC_PROMISC);
  558                         else
  559                                 bus_space_write_1(iot, ioh, EL_RXC,
  560                                     EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
  561                                     EL_RXC_DOFLOW | EL_RXC_ABROAD);
  562                         (void)bus_space_read_1(iot, ioh, EL_AS);
  563                         bus_space_write_1(iot, ioh, EL_RBC, 0);
  564                         break;
  565                 }
  566 
  567                 /* Incoming packet. */
  568                 len = bus_space_read_1(iot, ioh, EL_RBL);
  569                 len |= bus_space_read_1(iot, ioh, EL_RBH) << 8;
  570                 DPRINTF(("receive len=%d rxstat=%x ", len, rxstat));
  571                 bus_space_write_1(iot, ioh, EL_AC, EL_AC_HOST);
  572 
  573                 /* Pass data up to upper levels. */
  574                 elread(sc, len);
  575 
  576                 /* Is there another packet? */
  577                 if ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_RXBUSY) != 0)
  578                         break;
  579 
  580 #if NRND > 0
  581                 rnd_add_uint32(&sc->rnd_source, rxstat);
  582 #endif
  583 
  584                 DPRINTF(("<rescan> "));
  585         }
  586 
  587         (void)bus_space_read_1(iot, ioh, EL_RXC);
  588         bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
  589         return 1;
  590 }
  591 
  592 /*
  593  * Pass a packet to the higher levels.
  594  */
  595 void
  596 elread(sc, len)
  597         struct el_softc *sc;
  598         int len;
  599 {
  600         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  601         struct mbuf *m;
  602 
  603         if (len <= sizeof(struct ether_header) ||
  604             len > ETHER_MAX_LEN) {
  605                 printf("%s: invalid packet size %d; dropping\n",
  606                     sc->sc_dev.dv_xname, len);
  607                 ifp->if_ierrors++;
  608                 return;
  609         }
  610 
  611         /* Pull packet off interface. */
  612         m = elget(sc, len);
  613         if (m == 0) {
  614                 ifp->if_ierrors++;
  615                 return;
  616         }
  617 
  618         ifp->if_ipackets++;
  619 
  620 #if NBPFILTER > 0
  621         /*
  622          * Check if there's a BPF listener on this interface.
  623          * If so, hand off the raw packet to BPF.
  624          */
  625         if (ifp->if_bpf)
  626                 bpf_mtap(ifp->if_bpf, m);
  627 #endif
  628 
  629         (*ifp->if_input)(ifp, m);
  630 }
  631 
  632 /*
  633  * Pull read data off a interface.  Len is length of data, with local net
  634  * header stripped.  We copy the data into mbufs.  When full cluster sized
  635  * units are present we copy into clusters.
  636  */
  637 struct mbuf *
  638 elget(sc, totlen)
  639         struct el_softc *sc;
  640         int totlen;
  641 {
  642         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  643         bus_space_tag_t iot = sc->sc_iot;
  644         bus_space_handle_t ioh = sc->sc_ioh;
  645         struct mbuf *m, *m0, *newm;
  646         int len;
  647 
  648         MGETHDR(m0, M_DONTWAIT, MT_DATA);
  649         if (m0 == 0)
  650                 return (0);
  651         m0->m_pkthdr.rcvif = ifp;
  652         m0->m_pkthdr.len = totlen;
  653         len = MHLEN;
  654         m = m0;
  655 
  656         bus_space_write_1(iot, ioh, EL_GPBL, 0);
  657         bus_space_write_1(iot, ioh, EL_GPBH, 0);
  658 
  659         while (totlen > 0) {
  660                 if (totlen >= MINCLSIZE) {
  661                         MCLGET(m, M_DONTWAIT);
  662                         if ((m->m_flags & M_EXT) == 0)
  663                                 goto bad;
  664                         len = MCLBYTES;
  665                 }
  666 
  667                 m->m_len = len = min(totlen, len);
  668                 bus_space_read_multi_1(iot, ioh, EL_BUF, mtod(m, u_int8_t *), len);
  669 
  670                 totlen -= len;
  671                 if (totlen > 0) {
  672                         MGET(newm, M_DONTWAIT, MT_DATA);
  673                         if (newm == 0)
  674                                 goto bad;
  675                         len = MLEN;
  676                         m = m->m_next = newm;
  677                 }
  678         }
  679 
  680         bus_space_write_1(iot, ioh, EL_RBC, 0);
  681         bus_space_write_1(iot, ioh, EL_AC, EL_AC_RX);
  682 
  683         return (m0);
  684 
  685 bad:
  686         m_freem(m0);
  687         return (0);
  688 }
  689 
  690 /*
  691  * Process an ioctl request. This code needs some work - it looks pretty ugly.
  692  */
  693 int
  694 elioctl(ifp, cmd, data)
  695         struct ifnet *ifp;
  696         u_long cmd;
  697         caddr_t data;
  698 {
  699         struct el_softc *sc = ifp->if_softc;
  700         struct ifaddr *ifa = (struct ifaddr *)data;
  701         int s, error = 0;
  702 
  703         s = splnet();
  704 
  705         switch (cmd) {
  706 
  707         case SIOCSIFADDR:
  708                 ifp->if_flags |= IFF_UP;
  709 
  710                 switch (ifa->ifa_addr->sa_family) {
  711 #ifdef INET
  712                 case AF_INET:
  713                         elinit(sc);
  714                         arp_ifinit(ifp, ifa);
  715                         break;
  716 #endif
  717 #ifdef NS
  718                 /* XXX - This code is probably wrong. */
  719                 case AF_NS:
  720                     {
  721                         struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
  722 
  723                         if (ns_nullhost(*ina))
  724                                 ina->x_host =
  725                                     *(union ns_host *)LLADDR(ifp->if_sadl);
  726                         else
  727                                 memcpy(LLADDR(ifp->if_sadl), ina->x_host.c_host,
  728                                     ETHER_ADDR_LEN);
  729                         /* Set new address. */
  730                         elinit(sc);
  731                         break;
  732                     }
  733 #endif
  734                 default:
  735                         elinit(sc);
  736                         break;
  737                 }
  738                 break;
  739 
  740         case SIOCSIFFLAGS:
  741                 if ((ifp->if_flags & IFF_UP) == 0 &&
  742                     (ifp->if_flags & IFF_RUNNING) != 0) {
  743                         /*
  744                          * If interface is marked down and it is running, then
  745                          * stop it.
  746                          */
  747                         elstop(sc);
  748                         ifp->if_flags &= ~IFF_RUNNING;
  749                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
  750                            (ifp->if_flags & IFF_RUNNING) == 0) {
  751                         /*
  752                          * If interface is marked up and it is stopped, then
  753                          * start it.
  754                          */
  755                         elinit(sc);
  756                 } else {
  757                         /*
  758                          * Some other important flag might have changed, so
  759                          * reset.
  760                          */
  761                         elreset(sc);
  762                 }
  763                 break;
  764 
  765         default:
  766                 error = EINVAL;
  767                 break;
  768         }
  769 
  770         splx(s);
  771         return error;
  772 }
  773 
  774 /*
  775  * Device timeout routine.
  776  */
  777 void
  778 elwatchdog(ifp)
  779         struct ifnet *ifp;
  780 {
  781         struct el_softc *sc = ifp->if_softc;
  782 
  783         log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
  784         sc->sc_ethercom.ec_if.if_oerrors++;
  785 
  786         elreset(sc);
  787 }

Cache object: f1f5f5a8485293e4d63f7582d17661b5


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