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/netif/ep/if_ep.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by Herb Peyerl.
   16  * 4. The name of Herb Peyerl may not be used to endorse or promote products
   17  *    derived from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  *
   30  *      if_ep.c,v 1.19 1995/01/24 20:53:45 davidg Exp
   31  */
   32 
   33 /*
   34  *      Modified from the FreeBSD 1.1.5.1 version by:
   35  *                      Andres Vega Garcia
   36  *                      INRIA - Sophia Antipolis, France
   37  *                      avega@sophia.inria.fr
   38  */
   39 
   40 /*
   41  * $FreeBSD: src/sys/dev/ep/if_ep.c,v 1.95.2.3 2002/03/06 07:26:35 imp Exp $
   42  *
   43  *  Promiscuous mode added and interrupt logic slightly changed
   44  *  to reduce the number of adapter failures. Transceiver select
   45  *  logic changed to use value from EEPROM. Autoconfiguration
   46  *  features added.
   47  *  Done by:
   48  *          Serge Babkin
   49  *          Chelindbank (Chelyabinsk, Russia)
   50  *          babkin@hq.icb.chel.su
   51  */
   52 
   53 /*
   54  * Pccard support for 3C589 by:
   55  *              HAMADA Naoki
   56  *              nao@tom-yam.or.jp
   57  */
   58 
   59 /*
   60  * MAINTAINER: Matthew N. Dodd <winter@jurai.net>
   61  *                             <mdodd@FreeBSD.org>
   62  */
   63 
   64 #include <sys/param.h>
   65 #include <sys/kernel.h>
   66 #include <sys/systm.h>
   67 #include <sys/malloc.h>
   68 #include <sys/mbuf.h>
   69 #include <sys/socket.h>
   70 #include <sys/sockio.h>
   71 #include <sys/module.h>
   72 #include <sys/bus.h>
   73 #include <sys/rman.h> 
   74 #include <sys/thread2.h>
   75 
   76 #include <net/if.h>
   77 #include <net/ifq_var.h>
   78 #include <net/if_arp.h>
   79 #include <net/if_media.h> 
   80 #include <net/ethernet.h>
   81 #include <net/bpf.h>
   82 
   83 #include <netinet/in.h>
   84 #include <netinet/if_ether.h>
   85 
   86 #include <machine/clock.h>
   87 
   88 #include "if_epreg.h"
   89 #include "if_epvar.h"
   90 #include "../elink_layer/elink.h"
   91 
   92 /* Exported variables */
   93 devclass_t ep_devclass;
   94 
   95 #if 0
   96 static char *   ep_conn_type[] = {"UTP", "AUI", "???", "BNC"};
   97 static int      if_media2ep_media[] = { 0, 0, 0, UTP, BNC, AUI };
   98 #endif
   99 
  100 static int      ep_media2if_media[] =
  101         { IFM_10_T, IFM_10_5, IFM_NONE, IFM_10_2, IFM_NONE };
  102 
  103 /* if functions */
  104 static void     ep_if_init      (void *);
  105 static int      ep_if_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
  106 static void     ep_if_start     (struct ifnet *, struct ifaltq_subque *);
  107 static void     ep_if_watchdog  (struct ifnet *);
  108 
  109 /* if_media functions */
  110 static int      ep_ifmedia_upd  (struct ifnet *);
  111 static void     ep_ifmedia_sts  (struct ifnet *, struct ifmediareq *);
  112 
  113 static void     epstop          (struct ep_softc *);
  114 static void     epread          (struct ep_softc *);
  115 static int      eeprom_rdy      (struct ep_softc *);
  116 
  117 DECLARE_DUMMY_MODULE(if_ep);
  118 
  119 #define EP_FTST(sc, f)  (sc->stat &   (f))
  120 #define EP_FSET(sc, f)  (sc->stat |=  (f))
  121 #define EP_FRST(sc, f)  (sc->stat &= ~(f))
  122 
  123 static int
  124 eeprom_rdy(struct ep_softc *sc)
  125 {
  126     int i;
  127 
  128     for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++) {
  129         DELAY(100);
  130     }
  131     if (i >= MAX_EEPROMBUSY) {
  132         if_printf(&sc->arpcom.ac_if, "eeprom failed to come ready.\n");
  133         return (0);
  134     }
  135     return (1);
  136 }
  137 
  138 /*
  139  * get_e: gets a 16 bits word from the EEPROM. we must have set the window
  140  * before
  141  */
  142 u_int16_t
  143 get_e(struct ep_softc *sc, int offset)
  144 {
  145     if (!eeprom_rdy(sc))
  146         return (0);
  147     outw(BASE + EP_W0_EEPROM_COMMAND, (EEPROM_CMD_RD << sc->epb.cmd_off) | offset);
  148     if (!eeprom_rdy(sc))
  149         return (0);
  150     return (inw(BASE + EP_W0_EEPROM_DATA));
  151 }
  152 
  153 void
  154 ep_get_macaddr(struct ep_softc *sc, uint8_t *addr)
  155 {
  156         int                     i;
  157         u_int16_t *             macaddr = (u_int16_t *)addr;
  158 
  159         GO_WINDOW(0);
  160         for(i = EEPROM_NODE_ADDR_0; i <= EEPROM_NODE_ADDR_2; i++) {
  161                 macaddr[i] = htons(get_e(sc, i));
  162         }
  163 
  164         return;
  165 }
  166 
  167 int
  168 ep_alloc(device_t dev)
  169 {
  170         struct ep_softc *       sc = device_get_softc(dev);
  171         int                     rid;
  172         int                     error = 0;
  173 
  174         rid = 0;
  175         sc->iobase = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
  176             RF_ACTIVE);
  177         if (!sc->iobase) {
  178                 device_printf(dev, "No I/O space?!\n");
  179                 error = ENXIO;
  180                 goto bad;
  181         }
  182 
  183         rid = 0;
  184         sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
  185         if (!sc->irq) {
  186                 device_printf(dev, "No irq?!\n");
  187                 error = ENXIO;
  188                 goto bad;
  189         }
  190 
  191         if_initname(&sc->arpcom.ac_if,
  192                     device_get_name(dev), device_get_unit(dev));
  193         sc->stat = 0;   /* 16 bit access */
  194 
  195         sc->ep_io_addr = rman_get_start(sc->iobase);
  196 
  197         sc->ep_btag = rman_get_bustag(sc->iobase);
  198         sc->ep_bhandle = rman_get_bushandle(sc->iobase);
  199 
  200         sc->ep_connectors = 0;
  201         sc->ep_connector = 0;
  202 
  203         GO_WINDOW(0);
  204         sc->epb.cmd_off = 0;
  205         sc->epb.prod_id = get_e(sc, EEPROM_PROD_ID);
  206         sc->epb.res_cfg = get_e(sc, EEPROM_RESOURCE_CFG);
  207 
  208 bad:
  209         return (error);
  210 }
  211 
  212 void
  213 ep_get_media(struct ep_softc *sc)
  214 {
  215         u_int16_t               config;
  216         
  217         GO_WINDOW(0);
  218         config = inw(BASE + EP_W0_CONFIG_CTRL);
  219         if (config & IS_AUI)
  220                 sc->ep_connectors |= AUI;
  221         if (config & IS_BNC)
  222                 sc->ep_connectors |= BNC;
  223         if (config & IS_UTP)
  224                 sc->ep_connectors |= UTP;
  225 
  226         if (!(sc->ep_connectors & 7)) {
  227                 if (bootverbose)
  228                         if_printf(&sc->arpcom.ac_if, "no connectors!\n");
  229         }
  230 
  231         /*
  232          * This works for most of the cards so we'll do it here.
  233          * The cards that require something different can override
  234          * this later on.
  235          */
  236         sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS;
  237 
  238         return;
  239 }
  240 
  241 void
  242 ep_free(device_t dev)
  243 {
  244         struct ep_softc *       sc = device_get_softc(dev);
  245 
  246         if (sc->iobase)
  247                 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->iobase);
  248         if (sc->irq)
  249                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
  250 
  251         return;
  252 }
  253         
  254 int
  255 ep_attach(struct ep_softc *sc)
  256 {
  257         struct ifnet *          ifp = NULL;
  258         struct ifmedia *        ifm = NULL;
  259         u_short *               p;
  260         uint8_t                 ether_addr[ETHER_ADDR_LEN];
  261         int                     i;
  262 
  263         sc->gone = 0;
  264 
  265         ep_get_macaddr(sc, ether_addr);
  266 
  267         /*
  268          * Setup the station address
  269          */
  270         p = (u_short*)ether_addr;
  271         GO_WINDOW(2);
  272         for (i = 0; i < 3; i++) {
  273                 outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i]));
  274         }
  275   
  276         ifp = &sc->arpcom.ac_if;
  277 
  278         ifp->if_softc = sc;
  279         ifp->if_mtu = ETHERMTU;
  280         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  281         ifp->if_start = ep_if_start;
  282         ifp->if_ioctl = ep_if_ioctl;
  283         ifp->if_watchdog = ep_if_watchdog;
  284         ifp->if_init = ep_if_init;
  285         ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
  286         ifq_set_ready(&ifp->if_snd);
  287 
  288         if (!sc->epb.mii_trans) {
  289                 ifmedia_init(&sc->ifmedia, 0, ep_ifmedia_upd, ep_ifmedia_sts);
  290 
  291                 if (sc->ep_connectors & AUI)
  292                         ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL);
  293                 if (sc->ep_connectors & UTP)
  294                         ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
  295                 if (sc->ep_connectors & BNC)
  296                         ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_2, 0, NULL);
  297                 if (!sc->ep_connectors)
  298                         ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_NONE, 0, NULL);
  299         
  300                 ifmedia_set(&sc->ifmedia, IFM_ETHER|ep_media2if_media[sc->ep_connector]);
  301         
  302                 ifm = &sc->ifmedia;
  303                 ifm->ifm_media = ifm->ifm_cur->ifm_media;
  304                 ep_ifmedia_upd(ifp);
  305         }
  306 
  307         ether_ifattach(ifp, ether_addr, NULL);
  308 
  309 #ifdef EP_LOCAL_STATS
  310         sc->rx_no_first = sc->rx_no_mbuf = sc->rx_bpf_disc =
  311                 sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0;
  312 #endif
  313         EP_FSET(sc, F_RX_FIRST);
  314         sc->top = sc->mcur = 0;
  315 
  316         return 0;
  317 }
  318 
  319 /*
  320  * The order in here seems important. Otherwise we may not receive
  321  * interrupts. ?!
  322  */
  323 static void
  324 ep_if_init(void *xsc)
  325 {
  326     struct ep_softc *sc = xsc;
  327     struct ifnet *ifp = &sc->arpcom.ac_if;
  328     int i;
  329 
  330     if (sc->gone)
  331         return;
  332 
  333     crit_enter();
  334 
  335     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
  336 
  337     GO_WINDOW(0);
  338     outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
  339     GO_WINDOW(4);
  340     outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP);
  341     GO_WINDOW(0);
  342 
  343     /* Disable the card */
  344     outw(BASE + EP_W0_CONFIG_CTRL, 0);
  345 
  346     /* Enable the card */
  347     outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
  348 
  349     GO_WINDOW(2);
  350 
  351     /* Reload the ether_addr. */
  352     for (i = 0; i < 6; i++)
  353         outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);
  354 
  355     outw(BASE + EP_COMMAND, RX_RESET);
  356     outw(BASE + EP_COMMAND, TX_RESET);
  357     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
  358 
  359     /* Window 1 is operating window */
  360     GO_WINDOW(1);
  361     for (i = 0; i < 31; i++)
  362         inb(BASE + EP_W1_TX_STATUS);
  363 
  364     /* get rid of stray intr's */
  365     outw(BASE + EP_COMMAND, ACK_INTR | 0xff);
  366 
  367     outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS);
  368 
  369     outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);
  370 
  371     if (ifp->if_flags & IFF_PROMISC)
  372         outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
  373          FIL_GROUP | FIL_BRDCST | FIL_ALL);
  374     else
  375         outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
  376          FIL_GROUP | FIL_BRDCST);
  377 
  378     if (!sc->epb.mii_trans) {
  379         ep_ifmedia_upd(ifp);
  380     }
  381 
  382     outw(BASE + EP_COMMAND, RX_ENABLE);
  383     outw(BASE + EP_COMMAND, TX_ENABLE);
  384 
  385     ifp->if_flags |= IFF_RUNNING;
  386     ifq_clr_oactive(&ifp->if_snd);      /* just in case */
  387 
  388 #ifdef EP_LOCAL_STATS
  389     sc->rx_no_first = sc->rx_no_mbuf =
  390         sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0;
  391 #endif
  392     EP_FSET(sc, F_RX_FIRST);
  393     if (sc->top) {
  394         m_freem(sc->top);
  395         sc->top = sc->mcur = 0;
  396     }
  397     outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
  398     outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16);
  399 
  400     /*
  401      * Store up a bunch of mbuf's for use later. (MAX_MBS). First we free up
  402      * any that we had in case we're being called from intr or somewhere
  403      * else.
  404      */
  405 
  406     GO_WINDOW(1);
  407 
  408     if_devstart(ifp);
  409 
  410     crit_exit();
  411 }
  412 
  413 static const char padmap[] = {0, 3, 2, 1};
  414 
  415 static void
  416 ep_if_start(struct ifnet *ifp, struct ifaltq_subque *ifsq)
  417 {
  418     struct ep_softc *sc = ifp->if_softc;
  419     u_int len;
  420     struct mbuf *m;
  421     struct mbuf *top;
  422     int pad;
  423 
  424     ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);
  425 
  426     if (sc->gone) {
  427         ifq_purge(&ifp->if_snd);
  428         return;
  429     }
  430 
  431     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
  432     if (ifq_is_oactive(&ifp->if_snd)) {
  433         return;
  434     }
  435 
  436     crit_enter();
  437 
  438 startagain:
  439     /* Sneak a peek at the next packet */
  440     m = ifq_dequeue(&ifp->if_snd);
  441     if (m == NULL) {
  442         crit_exit();
  443         return;
  444     }
  445 
  446     for (len = 0, top = m; m; m = m->m_next)
  447         len += m->m_len;
  448     m = top;
  449 
  450     pad = padmap[len & 3];
  451 
  452     /*
  453      * The 3c509 automatically pads short packets to minimum ethernet length,
  454      * but we drop packets that are too large. Perhaps we should truncate
  455      * them instead?
  456      */
  457     if (len + pad > ETHER_MAX_LEN) {
  458         /* packet is obviously too large: toss it */
  459         IFNET_STAT_INC(ifp, oerrors, 1);
  460         m_freem(m);
  461         goto readcheck;
  462     }
  463     if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
  464         /* no room in FIFO */
  465         outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4));
  466         /* make sure */
  467         if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
  468             ifq_set_oactive(&ifp->if_snd);
  469             ifq_prepend(&ifp->if_snd, top);
  470             crit_exit();
  471             return;
  472         }
  473     } else {
  474         outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | EP_THRESH_DISABLE);
  475     }
  476 
  477     outw(BASE + EP_W1_TX_PIO_WR_1, len); 
  478     outw(BASE + EP_W1_TX_PIO_WR_1, 0x0);        /* Second dword meaningless */
  479 
  480     if (EP_FTST(sc, F_ACCESS_32_BITS)) {
  481         for (top = m; m != NULL; m = m->m_next) {
  482             outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t),
  483                   m->m_len / 4);
  484             if (m->m_len & 3)
  485                 outsb(BASE + EP_W1_TX_PIO_WR_1,
  486                       mtod(m, caddr_t) + (m->m_len & (~3)),
  487                       m->m_len & 3);
  488         }
  489     } else {
  490         for (top = m; m != NULL; m = m->m_next) {
  491             outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 2);
  492             if (m->m_len & 1)
  493                 outb(BASE + EP_W1_TX_PIO_WR_1,
  494                      *(mtod(m, caddr_t) + m->m_len - 1));
  495         }
  496     }
  497 
  498     while (pad--)
  499         outb(BASE + EP_W1_TX_PIO_WR_1, 0);      /* Padding */
  500 
  501     BPF_MTAP(ifp, top);
  502 
  503     ifp->if_timer = 2;
  504     IFNET_STAT_INC(ifp, opackets, 1);
  505     m_freem(top);
  506 
  507     /*
  508      * Is another packet coming in? We don't want to overflow the tiny RX
  509      * fifo.
  510      */
  511 readcheck:
  512     if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) {
  513         /*
  514          * we check if we have packets left, in that case we prepare to come
  515          * back later
  516          */
  517         if (!ifq_is_empty(&ifp->if_snd))
  518             outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8);
  519 
  520         crit_exit();
  521         return;
  522     }
  523     goto startagain;
  524 }
  525 
  526 void
  527 ep_intr(void *arg)
  528 {
  529     struct ep_softc *sc = arg;
  530     struct ifnet *ifp = &sc->arpcom.ac_if;
  531     int status;
  532 
  533      /*
  534       * quick fix: Try to detect an interrupt when the card goes away.
  535       */
  536     if (sc->gone || inw(BASE + EP_STATUS) == 0xffff) {
  537             return;
  538     }
  539 
  540     outw(BASE + EP_COMMAND, SET_INTR_MASK); /* disable all Ints */
  541 
  542 rescan:
  543 
  544     while ((status = inw(BASE + EP_STATUS)) & S_5_INTS) {
  545 
  546         /* first acknowledge all interrupt sources */
  547         outw(BASE + EP_COMMAND, ACK_INTR | (status & S_MASK));
  548 
  549         if (status & (S_RX_COMPLETE | S_RX_EARLY))
  550             epread(sc);
  551         if (status & S_TX_AVAIL) {
  552             /* we need ACK */
  553             ifp->if_timer = 0;
  554             ifq_clr_oactive(&ifp->if_snd);
  555             GO_WINDOW(1);
  556             inw(BASE + EP_W1_FREE_TX);
  557             if_devstart(ifp);
  558         }
  559         if (status & S_CARD_FAILURE) {
  560             ifp->if_timer = 0;
  561 #ifdef EP_LOCAL_STATS
  562             kprintf("\n");
  563             if_printf(ifp, "\n\tStatus: %x\n", status);
  564             GO_WINDOW(4);
  565             kprintf("\tFIFO Diagnostic: %x\n", inw(BASE + EP_W4_FIFO_DIAG));
  566             kprintf("\tStat: %x\n", sc->stat);
  567             kprintf("\tIpackets=%d, Opackets=%d\n",
  568                 ifp->if_ipackets, ifp->if_opackets);
  569             kprintf("\tNOF=%d, NOMB=%d, RXOF=%d, RXOL=%d, TXU=%d\n",
  570                    sc->rx_no_first, sc->rx_no_mbuf, sc->rx_overrunf,
  571                    sc->rx_overrunl, sc->tx_underrun);
  572 #else
  573 
  574 #ifdef DIAGNOSTIC
  575             if_printf(ifp, "Status: %x (input buffer overflow)\n", status);
  576 #else
  577             IFNET_STAT_INC(ifp, ierrors, 1);
  578 #endif
  579 
  580 #endif
  581             ep_if_init(sc);
  582             return;
  583         }
  584         if (status & S_TX_COMPLETE) {
  585             ifp->if_timer = 0;
  586             /* we  need ACK. we do it at the end */
  587             /*
  588              * We need to read TX_STATUS until we get a 0 status in order to
  589              * turn off the interrupt flag.
  590              */
  591             while ((status = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) {
  592                 if (status & TXS_SUCCES_INTR_REQ);
  593                 else if (status & (TXS_UNDERRUN | TXS_JABBER | TXS_MAX_COLLISION)) {
  594                     outw(BASE + EP_COMMAND, TX_RESET);
  595                     if (status & TXS_UNDERRUN) {
  596 #ifdef EP_LOCAL_STATS
  597                         sc->tx_underrun++;
  598 #endif
  599                     } else {
  600                         if (status & TXS_JABBER);
  601                         else    /* TXS_MAX_COLLISION - we shouldn't get here */
  602                             IFNET_STAT_INC(ifp, collisions, 1);
  603                     }
  604                     IFNET_STAT_INC(ifp, oerrors, 1);
  605                     outw(BASE + EP_COMMAND, TX_ENABLE);
  606                     /*
  607                      * To have a tx_avail_int but giving the chance to the
  608                      * Reception
  609                      */
  610                     if (!ifq_is_empty(&ifp->if_snd))
  611                         outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8);
  612                 }
  613                 outb(BASE + EP_W1_TX_STATUS, 0x0);      /* pops up the next
  614                                                          * status */
  615             }                   /* while */
  616             ifq_clr_oactive(&ifp->if_snd);
  617             GO_WINDOW(1);
  618             inw(BASE + EP_W1_FREE_TX);
  619             if_devstart(ifp);
  620         }                       /* end TX_COMPLETE */
  621     }
  622 
  623     outw(BASE + EP_COMMAND, C_INTR_LATCH);      /* ACK int Latch */
  624 
  625     if ((status = inw(BASE + EP_STATUS)) & S_5_INTS)
  626         goto rescan;
  627 
  628     /* re-enable Ints */
  629     outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);
  630 }
  631 
  632 static void
  633 epread(struct ep_softc *sc)
  634 {
  635     struct mbuf *top, *mcur, *m;
  636     struct ifnet *ifp;
  637     int lenthisone;
  638 
  639     short rx_fifo2, status;
  640     short rx_fifo;
  641 
  642     ifp = &sc->arpcom.ac_if;
  643     status = inw(BASE + EP_W1_RX_STATUS);
  644 
  645 read_again:
  646 
  647     if (status & ERR_RX) {
  648         IFNET_STAT_INC(ifp, ierrors, 1);
  649         if (status & ERR_RX_OVERRUN) {
  650             /*
  651              * we can think the rx latency is actually greather than we
  652              * expect
  653              */
  654 #ifdef EP_LOCAL_STATS
  655             if (EP_FTST(sc, F_RX_FIRST))
  656                 sc->rx_overrunf++;
  657             else
  658                 sc->rx_overrunl++;
  659 #endif
  660         }
  661         goto out;
  662     }
  663     rx_fifo = rx_fifo2 = status & RX_BYTES_MASK;
  664 
  665     if (EP_FTST(sc, F_RX_FIRST)) {
  666         m = m_getl(rx_fifo, MB_DONTWAIT, MT_DATA, M_PKTHDR, NULL);
  667         if (!m)
  668             goto out;
  669         sc->top = sc->mcur = top = m;
  670 #define EROUND  ((sizeof(struct ether_header) + 3) & ~3)
  671 #define EOFF    (EROUND - sizeof(struct ether_header))
  672         top->m_data += EOFF;
  673 
  674         /* Read what should be the header. */
  675         insw(BASE + EP_W1_RX_PIO_RD_1,
  676              mtod(top, caddr_t), sizeof(struct ether_header) / 2);
  677         top->m_len = sizeof(struct ether_header);
  678         rx_fifo -= sizeof(struct ether_header);
  679         sc->cur_len = rx_fifo2;
  680     } else {
  681         /* come here if we didn't have a complete packet last time */
  682         top = sc->top;
  683         m = sc->mcur;
  684         sc->cur_len += rx_fifo2;
  685     }
  686 
  687     /* Reads what is left in the RX FIFO */
  688     while (rx_fifo > 0) {
  689         lenthisone = min(rx_fifo, M_TRAILINGSPACE(m));
  690         if (lenthisone == 0) {  /* no room in this one */
  691             mcur = m;
  692             m = m_getl(rx_fifo, MB_DONTWAIT, MT_DATA, 0, NULL);
  693             if (!m)
  694                 goto out;
  695             m->m_len = 0;
  696             mcur->m_next = m;
  697             lenthisone = min(rx_fifo, M_TRAILINGSPACE(m));
  698         }
  699         if (EP_FTST(sc, F_ACCESS_32_BITS)) { /* default for EISA configured cards*/
  700             insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
  701                  lenthisone / 4);
  702             m->m_len += (lenthisone & ~3);
  703             if (lenthisone & 3)
  704                 insb(BASE + EP_W1_RX_PIO_RD_1,
  705                      mtod(m, caddr_t) + m->m_len,
  706                      lenthisone & 3);
  707             m->m_len += (lenthisone & 3);
  708         } else {
  709             insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
  710                  lenthisone / 2);
  711             m->m_len += lenthisone;
  712             if (lenthisone & 1)
  713                 *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
  714         }
  715         rx_fifo -= lenthisone;
  716     }
  717 
  718     if (status & ERR_RX_INCOMPLETE) {   /* we haven't received the complete
  719                                          * packet */
  720         sc->mcur = m;
  721 #ifdef EP_LOCAL_STATS
  722         sc->rx_no_first++;      /* to know how often we come here */
  723 #endif
  724         EP_FRST(sc, F_RX_FIRST);
  725         if (!((status = inw(BASE + EP_W1_RX_STATUS)) & ERR_RX_INCOMPLETE)) {
  726             /* we see if by now, the packet has completly arrived */
  727             goto read_again;
  728         }
  729         outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_NEXT_EARLY_THRESH);
  730         return;
  731     }
  732     outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
  733     IFNET_STAT_INC(ifp, ipackets, 1);
  734     EP_FSET(sc, F_RX_FIRST);
  735     top->m_pkthdr.rcvif = &sc->arpcom.ac_if;
  736     top->m_pkthdr.len = sc->cur_len;
  737 
  738     ifp->if_input(ifp, top);
  739     sc->top = 0;
  740     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
  741     outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
  742     return;
  743 
  744 out:
  745     outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
  746     if (sc->top) {
  747         m_freem(sc->top);
  748         sc->top = 0;
  749 #ifdef EP_LOCAL_STATS
  750         sc->rx_no_mbuf++;
  751 #endif
  752     }
  753     EP_FSET(sc, F_RX_FIRST);
  754     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
  755     outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
  756 }
  757 
  758 static int 
  759 ep_ifmedia_upd(struct ifnet *ifp)
  760 {
  761         struct ep_softc *       sc = ifp->if_softc;
  762         int                     i = 0, j;
  763 
  764         GO_WINDOW(0);
  765         outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
  766         GO_WINDOW(4);
  767         outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP);
  768         GO_WINDOW(0);
  769 
  770         switch (IFM_SUBTYPE(sc->ifmedia.ifm_media)) {
  771                 case IFM_10_T:
  772                         if (sc->ep_connectors & UTP) {
  773                                 i = ACF_CONNECTOR_UTP;
  774                                 GO_WINDOW(4);
  775                                 outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
  776                         }
  777                         break;
  778                 case IFM_10_2:
  779                         if (sc->ep_connectors & BNC) {
  780                                 i = ACF_CONNECTOR_BNC;
  781                                 outw(BASE + EP_COMMAND, START_TRANSCEIVER);
  782                                 DELAY(DELAY_MULTIPLE * 1000);
  783                         }
  784                         break;
  785                 case IFM_10_5:
  786                         if (sc->ep_connectors & AUI)
  787                                 i = ACF_CONNECTOR_AUI;
  788                         break;
  789                 default:
  790                         i = sc->ep_connector;
  791                         if_printf(ifp, "strange connector type in EEPROM: "
  792                                   "assuming AUI\n");
  793                         break;
  794         }
  795 
  796         GO_WINDOW(0);
  797         j = inw(BASE + EP_W0_ADDRESS_CFG) & 0x3fff;
  798         outw(BASE + EP_W0_ADDRESS_CFG, j | (i << ACF_CONNECTOR_BITS));
  799 
  800         return (0);
  801 }
  802 
  803 static void
  804 ep_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
  805 {
  806         struct ep_softc *       sc = ifp->if_softc;
  807 
  808         ifmr->ifm_active = sc->ifmedia.ifm_media;
  809 
  810         return;
  811 }
  812 
  813 static int
  814 ep_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
  815 {
  816         struct ep_softc *       sc = ifp->if_softc;
  817         struct ifreq *          ifr = (struct ifreq *)data;
  818         int error = 0;
  819 
  820         crit_enter();
  821 
  822         switch (cmd) {
  823         case SIOCSIFFLAGS:
  824                 if (((ifp->if_flags & IFF_UP) == 0) &&
  825                     (ifp->if_flags & IFF_RUNNING)) {
  826                         ifp->if_flags &= ~IFF_RUNNING;
  827                         epstop(sc);
  828                 } else {
  829                         /* reinitialize card on any parameter change */
  830                         ep_if_init(sc);
  831                 }
  832                 break;
  833 #ifdef notdef
  834         case SIOCGHWADDR:
  835                 bcopy((caddr_t) sc->sc_addr, (caddr_t) & ifr->ifr_data,
  836                       sizeof(sc->sc_addr));
  837                 break;
  838 #endif
  839         case SIOCADDMULTI:
  840         case SIOCDELMULTI:
  841                 /*
  842                  * The Etherlink III has no programmable multicast
  843                  * filter.  We always initialize the card to be
  844                  * promiscuous to multicast, since we're always a
  845                  * member of the ALL-SYSTEMS group, so there's no
  846                  * need to process SIOC*MULTI requests.
  847                  */
  848                 error = 0;
  849                 break;
  850         case SIOCSIFMEDIA:
  851         case SIOCGIFMEDIA:
  852                 if (!sc->epb.mii_trans) {
  853                         error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd);
  854                 } else {
  855                         error = EINVAL;
  856                 }
  857                 break;
  858         default:
  859                 error = ether_ioctl(ifp, cmd, data);
  860                 break;
  861         }
  862 
  863         crit_exit();
  864 
  865         return (error);
  866 }
  867 
  868 static void
  869 ep_if_watchdog(struct ifnet *ifp)
  870 {
  871     struct ep_softc *sc = ifp->if_softc;
  872 
  873     /*
  874     if_printf(ifp, "watchdog\n");
  875 
  876     log(LOG_ERR, "%s: watchdog\n", ifp->if_xname);
  877     ifp->if_oerrors++;
  878     */
  879 
  880     if (sc->gone) {
  881         return;
  882     }
  883 
  884     ifq_clr_oactive(&ifp->if_snd);
  885     if_devstart(ifp);
  886     ep_intr(ifp->if_softc);
  887 }
  888 
  889 static void
  890 epstop(struct ep_softc *sc)
  891 {
  892     if (sc->gone) {
  893         return;
  894     }
  895 
  896     outw(BASE + EP_COMMAND, RX_DISABLE);
  897     outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
  898     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
  899     outw(BASE + EP_COMMAND, TX_DISABLE);
  900     outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
  901     outw(BASE + EP_COMMAND, RX_RESET);
  902     outw(BASE + EP_COMMAND, TX_RESET);
  903     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
  904     outw(BASE + EP_COMMAND, C_INTR_LATCH);
  905     outw(BASE + EP_COMMAND, SET_RD_0_MASK);
  906     outw(BASE + EP_COMMAND, SET_INTR_MASK);
  907     outw(BASE + EP_COMMAND, SET_RX_FILTER);
  908 }

Cache object: 95da8b74db151ab4b68d3031ca0930e7


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