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/ic/i82596.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: i82596.c,v 1.8 2005/02/27 00:27:01 perry Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2003 Jochen Kunz.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. The name of Jochen Kunz may not be used to endorse or promote
   16  *    products derived from this software without specific prior
   17  *    written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY JOCHEN KUNZ
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL JOCHEN KUNZ
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Driver for the Intel i82596 10MBit/s Ethernet chip.
   34  * It operates the i82596 in 32-Bit Linear Mode, opposed to the old i82586
   35  * ie(4) driver (src/sys/dev/ic/i82586.c), that degrades the i82596 to
   36  * i82586 compatibility mode.
   37  * Documentation about this chip can be found on http://www.openpa.net/
   38  * file names 29021806.pdf and 29021906.pdf
   39  */
   40 
   41 #include <sys/cdefs.h>
   42 __KERNEL_RCSID(0, "$NetBSD: i82596.c,v 1.8 2005/02/27 00:27:01 perry Exp $");
   43 
   44 /* autoconfig and device stuff */
   45 #include <sys/param.h>
   46 #include <sys/device.h>
   47 #include <sys/conf.h>
   48 #include "locators.h"
   49 #include "ioconf.h"
   50 
   51 /* bus_space / bus_dma etc. */
   52 #include <machine/bus.h>
   53 #include <machine/intr.h>
   54 
   55 /* general system data and functions */
   56 #include <sys/systm.h>
   57 #include <sys/ioctl.h>
   58 
   59 /* tsleep / sleep / wakeup */
   60 #include <sys/proc.h>
   61 /* hz for above */
   62 #include <sys/kernel.h>
   63 
   64 /* network stuff */
   65 #include <net/if.h>
   66 #include <net/if_dl.h>
   67 #include <net/if_media.h>
   68 #include <net/if_ether.h>
   69 #include <sys/socket.h>
   70 #include <sys/mbuf.h>
   71 
   72 #include "bpfilter.h"
   73 #if NBPFILTER > 0
   74 #include <net/bpf.h>
   75 #endif
   76 
   77 #include <dev/ic/i82596reg.h>
   78 #include <dev/ic/i82596var.h>
   79 
   80 
   81 
   82 /* Supported chip variants */
   83 char *i82596_typenames[] = { "unknowen", "DX/SX", "CA" };
   84 
   85 
   86 
   87 /* media change and status callback */
   88 static int iee_mediachange(struct ifnet *);
   89 static void iee_mediastatus(struct ifnet *, struct ifmediareq *);
   90 
   91 /* interface routines to upper protocols */
   92 static void iee_start(struct ifnet *);                  /* initiate output */
   93 static int iee_ioctl(struct ifnet *, u_long, caddr_t);  /* ioctl routine */
   94 static int iee_init(struct ifnet *);                    /* init routine */
   95 static void iee_stop(struct ifnet *, int);              /* stop routine */
   96 static void iee_watchdog(struct ifnet *);               /* timer routine */
   97 static void iee_drain(struct ifnet *);                  /* release resources */
   98 
   99 /* internal helper functions */
  100 static void iee_cb_setup(struct iee_softc *, uint32_t);
  101 
  102 /*
  103 Things a MD frontend has to provide:
  104 
  105 The functions via function pointers in the softc:
  106         int (*sc_iee_cmd)(struct iee_softc *sc, uint32_t cmd);
  107         int (*sc_iee_reset)(struct iee_softc *sc);
  108         void (*sc_mediastatus)(struct ifnet *, struct ifmediareq *);
  109         int (*sc_mediachange)(struct ifnet *);
  110 
  111 sc_iee_cmd(): send a command to the i82596 by writing the cmd parameter
  112         to the SCP cmd word and issuing a Channel Attention.
  113 sc_iee_reset(): initiate a reset, supply the address of the SCP to the
  114         chip, wait for the chip to initialize and ACK interrupts that
  115         this may have caused by caling (sc->sc_iee_cmd)(sc, IEE_SCB_ACK);
  116 This functions must carefully bus_dmamap_sync() all data they have touched!
  117 
  118 sc_mediastatus() and  sc_mediachange() are just MD hooks to the according
  119 MI functions. The MD frontend may set this pointers to NULL when they
  120 are not needed.
  121 
  122 sc->sc_type has to be set to I82596_UNKNOWN or I82596_DX or I82596_CA.
  123 This is for printing out the correct chip type at attach time only. The
  124 MI backend doesn't distinguish different chip types when programming
  125 the chip.
  126 
  127 sc->sc_flags has to be set to 0 on litle endian hardware and to
  128 IEE_NEED_SWAP on big endian hardware, when endianes conversion is not
  129 done by the bus attachment. Usually you need to set IEE_NEED_SWAP
  130 when IEE_SYSBUS_BE is set in the sysbus byte.
  131 
  132 sc->sc_cl_align bust be set to 1 or to the cache line size. When set to
  133 1 no special alignment of DMA descriptors is done. If sc->sc_cl_align != 1
  134 it forces alignment of the data structres in the shared memory to a multiple
  135 of sc->sc_cl_align. This is needed on archs like hp700 that have non DMA
  136 I/O coherent caches and are unable to map the shared memory uncachable.
  137 (At least pre PA7100LC CPUs are unable to map memory uncachable.)
  138 
  139 sc->sc_cl_align MUST BE INITIALIZED BEFORE THE FOLOWING MACROS ARE USED:
  140 SC_* IEE_*_SZ IEE_*_OFF IEE_SHMEM_MAX (shell style glob(3) pattern)
  141 
  142 The MD frontend has to allocate a piece of DMA memory at least of
  143 IEE_SHMEM_MAX bytes size. All communication with the chip is done via
  144 this shared memory. If possible map this memory non-cachable on
  145 archs with non DMA I/O coherent caches. The base of the memory needs
  146 to be aligend to an even address if sc->sc_cl_align == 1 and aligend
  147 to a cache line if sc->sc_cl_align != 1.
  148 
  149 An interrupt with iee_intr() as handler must be established.
  150 
  151 Call void iee_attach(struct iee_softc *sc, uint8_t *ether_address,
  152 int *media, int nmedia, int defmedia); when everything is set up. First
  153 parameter is a pointer to the MI softc, ether_address is an array that
  154 contains the ethernet address. media is an array of the media types
  155 provided by the hardware. The members of this array are supplied to
  156 ifmedia_add() in sequence. nmedia is the count of elements in media.
  157 defmedia is the default media that is set via ifmedia_set().
  158 nmedia and defmedia are ignored when media == NULL.
  159 
  160 The MD backend may call iee_detach() to detach the device.
  161 
  162 See sys/arch/hp700/gsc/if_iee.c for an example.
  163 */
  164 
  165 
  166 /*
  167 How frame reception is done:
  168 Each Recieve Frame Descriptor has one associated Recieve Buffer Descriptor.
  169 Each RBD points to the data area of a mbuf cluster. The RFDs are linked
  170 together in a circular list. sc->sc_rx_done is the count of RFDs in the
  171 list already processed / the number of the RFD that has to be checked for
  172 a new frame first at the next RX interrupt. Upon successful reception of
  173 a frame the mbuf cluster is handled to upper protocol layers, a new mbuf
  174 cluster is allocated and the RFD / RBD are reinitialized accordingly.
  175 
  176 When a RFD list overrun occured the whole RFD and RBD lists are reinitialized
  177 and frame reception is started again.
  178 */
  179 int
  180 iee_intr(void *intarg)
  181 {
  182         struct iee_softc *sc = intarg;
  183         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  184         struct iee_rfd *rfd;
  185         struct iee_rbd *rbd;
  186         bus_dmamap_t rx_map;
  187         struct mbuf *rx_mbuf;
  188         struct mbuf *new_mbuf;
  189         int scb_status;
  190         int scb_cmd;
  191         int n, col;
  192 
  193         if ((ifp->if_flags & IFF_RUNNING) == 0) {
  194                 (sc->sc_iee_cmd)(sc, IEE_SCB_ACK);
  195                 return(1);
  196         }
  197         bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, 0, IEE_SHMEM_MAX,
  198             BUS_DMASYNC_POSTREAD);
  199         scb_status = SC_SCB->scb_status;
  200         scb_cmd = SC_SCB->scb_cmd;
  201         rfd = SC_RFD(sc->sc_rx_done);
  202         while ((rfd->rfd_status & IEE_RFD_C) != 0) {
  203                 /* At least one packet was received. */
  204                 rbd = SC_RBD(sc->sc_rx_done);
  205                 rx_map = sc->sc_rx_map[sc->sc_rx_done];
  206                 rx_mbuf = sc->sc_rx_mbuf[sc->sc_rx_done];
  207                 SC_RBD((sc->sc_rx_done + IEE_NRFD - 1) % IEE_NRFD)->rbd_size
  208                     &= ~IEE_RBD_EL;
  209                 if ((rfd->rfd_status & IEE_RFD_OK) == 0
  210                     || (rbd->rbd_count & IEE_RBD_EOF) == 0
  211                     || (rbd->rbd_count & IEE_RBD_F) == 0){
  212                         /* Receive error, skip frame and reuse buffer. */
  213                         rfd->rfd_status = 0;
  214                         rbd->rbd_count = 0;
  215                         rbd->rbd_size = IEE_RBD_EL | rx_map->dm_segs[0].ds_len;
  216                         printf("%s: iee_intr: receive error %d, rfd_status="
  217                             "0x%.4x, rfd_count=0x%.4x\n", sc->sc_dev.dv_xname,
  218                             ++sc->sc_rx_err, rfd->rfd_status, rbd->rbd_count);
  219                         sc->sc_rx_done = (sc->sc_rx_done + 1) % IEE_NRFD;
  220                         continue;
  221                 }
  222                 rfd->rfd_status = 0;
  223                 bus_dmamap_sync(sc->sc_dmat, rx_map, 0, rx_mbuf->m_ext.ext_size,
  224                     BUS_DMASYNC_POSTREAD);
  225                 rx_mbuf->m_pkthdr.len = rx_mbuf->m_len =
  226                     rbd->rbd_count & IEE_RBD_COUNT;
  227                 rx_mbuf->m_pkthdr.rcvif = ifp;
  228                 MGETHDR(new_mbuf, M_DONTWAIT, MT_DATA);
  229                 if (new_mbuf == NULL) {
  230                         printf("%s: iee_intr: can't allocate mbuf\n",
  231                             sc->sc_dev.dv_xname);
  232                         break;
  233                 }
  234                 MCLAIM(new_mbuf, &sc->sc_ethercom.ec_rx_mowner);
  235                 MCLGET(new_mbuf, M_DONTWAIT);
  236                 if ((new_mbuf->m_flags & M_EXT) == 0) {
  237                         printf("%s: iee_intr: can't alloc mbuf cluster\n",
  238                             sc->sc_dev.dv_xname);
  239                         m_freem(new_mbuf);
  240                         break;
  241                 }
  242                 bus_dmamap_unload(sc->sc_dmat, rx_map);
  243                 if (bus_dmamap_load(sc->sc_dmat, rx_map,
  244                     new_mbuf->m_ext.ext_buf, new_mbuf->m_ext.ext_size,
  245                     NULL, BUS_DMA_READ | BUS_DMA_NOWAIT) != 0)
  246                         panic("%s: iee_intr: can't load RX DMA map\n",
  247                             sc->sc_dev.dv_xname);
  248                 bus_dmamap_sync(sc->sc_dmat, rx_map, 0,
  249                     new_mbuf->m_ext.ext_size, BUS_DMASYNC_PREREAD);
  250 #if NBPFILTER > 0
  251                 if (ifp->if_bpf != 0)
  252                         bpf_mtap(ifp->if_bpf, rx_mbuf);
  253 #endif /* NBPFILTER > 0 */
  254                 (*ifp->if_input)(ifp, rx_mbuf);
  255                 ifp->if_ipackets++;
  256                 sc->sc_rx_mbuf[sc->sc_rx_done] = new_mbuf;
  257                 rbd->rbd_count = 0;
  258                 rbd->rbd_size = IEE_RBD_EL | rx_map->dm_segs[0].ds_len;
  259                 rbd->rbd_rb_addr = rx_map->dm_segs[0].ds_addr;
  260                 sc->sc_rx_done = (sc->sc_rx_done + 1) % IEE_NRFD;
  261                 rfd = SC_RFD(sc->sc_rx_done);
  262         }
  263         if ((scb_status & IEE_SCB_RUS) == IEE_SCB_RUS_NR1
  264             || (scb_status & IEE_SCB_RUS) == IEE_SCB_RUS_NR2
  265             || (scb_status & IEE_SCB_RUS) == IEE_SCB_RUS_NR3) {
  266                 /* Receive Overrun, reinit receive ring buffer. */
  267                 for (n = 0 ; n < IEE_NRFD ; n++) {
  268                         SC_RFD(n)->rfd_cmd = IEE_RFD_SF;
  269                         SC_RFD(n)->rfd_link_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF
  270                             + IEE_RFD_SZ * ((n + 1) % IEE_NRFD));
  271                         SC_RBD(n)->rbd_next_rbd = IEE_PHYS_SHMEM(IEE_RBD_OFF
  272                             + IEE_RBD_SZ * ((n + 1) % IEE_NRFD));
  273                         SC_RBD(n)->rbd_size = IEE_RBD_EL |
  274                             sc->sc_rx_map[n]->dm_segs[0].ds_len;
  275                         SC_RBD(n)->rbd_rb_addr =
  276                             sc->sc_rx_map[n]->dm_segs[0].ds_addr;
  277                 }
  278                 SC_RFD(0)->rfd_rbd_addr = IEE_PHYS_SHMEM(IEE_RBD_OFF);
  279                 sc->sc_rx_done = 0;
  280                 bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, IEE_RFD_OFF,
  281                     IEE_RFD_LIST_SZ + IEE_RBD_LIST_SZ, BUS_DMASYNC_PREWRITE);
  282                 (sc->sc_iee_cmd)(sc, IEE_SCB_RUC_ST);
  283                 printf("%s: iee_intr: receive ring buffer overrun\n",
  284                     sc->sc_dev.dv_xname);
  285         }
  286 
  287         if (sc->sc_next_cb != 0
  288             && (SC_CB(sc->sc_next_cb - 1)->cb_status & IEE_CB_C) != 0) {
  289                 /* CMD list finished */
  290                 ifp->if_timer = 0;
  291                 if (sc->sc_next_tbd != 0) {
  292                         /* A TX CMD list finished, clenup */
  293                         for (n = 0 ; n < sc->sc_next_cb ; n++) {
  294                                 m_freem(sc->sc_tx_mbuf[n]);
  295                                 sc->sc_tx_mbuf[n] = NULL;
  296                                 bus_dmamap_unload(sc->sc_dmat,sc->sc_tx_map[n]);
  297                                 if ((SC_CB(n)->cb_status & IEE_CB_COL) != 0 &&
  298                                     (SC_CB(n)->cb_status & IEE_CB_MAXCOL) == 0)
  299                                         col = 16;
  300                                 else
  301                                         col = SC_CB(n)->cb_status
  302                                             & IEE_CB_MAXCOL;
  303                                 sc->sc_tx_col += col;
  304                                 if ((SC_CB(n)->cb_status & IEE_CB_OK) != 0) {
  305                                         ifp->if_opackets++;
  306                                         ifp->if_collisions += col;
  307                                 }
  308                         }
  309                         sc->sc_next_tbd = 0;
  310                         ifp->if_flags &= ~IFF_OACTIVE;
  311                 }
  312                 for (n = 0 ; n < sc->sc_next_cb ; n++) {
  313                         /* Check if a CMD failed, but ignore TX errors. */
  314                         if ((SC_CB(n)->cb_cmd & IEE_CB_CMD) != IEE_CB_CMD_TR
  315                             && ((SC_CB(n)->cb_status & IEE_CB_OK) == 0))
  316                                 printf("%s: iee_intr: scb_status=0x%x "
  317                                     "scb_cmd=0x%x failed command %d: "
  318                                     "cb_status[%d]=0x%.4x cb_cmd[%d]=0x%.4x\n",
  319                                     sc->sc_dev.dv_xname, scb_status, scb_cmd,
  320                                     ++sc->sc_cmd_err, n, SC_CB(n)->cb_status,
  321                                     n, SC_CB(n)->cb_cmd);
  322                 }
  323                 sc->sc_next_cb = 0;
  324                 if ((sc->sc_flags & IEE_WANT_MCAST) != 0) {
  325                         iee_cb_setup(sc, IEE_CB_CMD_MCS | IEE_CB_S | IEE_CB_EL
  326                             | IEE_CB_I);
  327                         (sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE);
  328                 } else
  329                         /* Try to get defered packets going. */
  330                         iee_start(ifp);
  331         }
  332         if (IEE_SWAP(SC_SCB->scb_crc_err) != sc->sc_crc_err) {
  333                 sc->sc_crc_err = IEE_SWAP(SC_SCB->scb_crc_err);
  334                 printf("%s: iee_intr: crc_err=%d\n", sc->sc_dev.dv_xname,
  335                     sc->sc_crc_err);
  336         }
  337         if (IEE_SWAP(SC_SCB->scb_align_err) != sc->sc_align_err) {
  338                 sc->sc_align_err = IEE_SWAP(SC_SCB->scb_align_err);
  339                 printf("%s: iee_intr: align_err=%d\n", sc->sc_dev.dv_xname,
  340                     sc->sc_align_err);
  341         }
  342         if (IEE_SWAP(SC_SCB->scb_resource_err) != sc->sc_resource_err) {
  343                 sc->sc_resource_err = IEE_SWAP(SC_SCB->scb_resource_err);
  344                 printf("%s: iee_intr: resource_err=%d\n", sc->sc_dev.dv_xname,
  345                     sc->sc_resource_err);
  346         }
  347         if (IEE_SWAP(SC_SCB->scb_overrun_err) != sc->sc_overrun_err) {
  348                 sc->sc_overrun_err = IEE_SWAP(SC_SCB->scb_overrun_err);
  349                 printf("%s: iee_intr: overrun_err=%d\n", sc->sc_dev.dv_xname,
  350                     sc->sc_overrun_err);
  351         }
  352         if (IEE_SWAP(SC_SCB->scb_rcvcdt_err) != sc->sc_rcvcdt_err) {
  353                 sc->sc_rcvcdt_err = IEE_SWAP(SC_SCB->scb_rcvcdt_err);
  354                 printf("%s: iee_intr: rcvcdt_err=%d\n", sc->sc_dev.dv_xname,
  355                     sc->sc_rcvcdt_err);
  356         }
  357         if (IEE_SWAP(SC_SCB->scb_short_fr_err) != sc->sc_short_fr_err) {
  358                 sc->sc_short_fr_err = IEE_SWAP(SC_SCB->scb_short_fr_err);
  359                 printf("%s: iee_intr: short_fr_err=%d\n", sc->sc_dev.dv_xname,
  360                     sc->sc_short_fr_err);
  361         }
  362         bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, 0, IEE_SHMEM_MAX,
  363             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  364         (sc->sc_iee_cmd)(sc, IEE_SCB_ACK);
  365         return(1);
  366 }
  367 
  368 
  369 
  370 /*
  371 How Command Block List Processing is done.
  372 
  373 A runing CBL is never manipulated. If there is a CBL already runing,
  374 further CMDs are deferd until the current list is done. A new list is
  375 setup when the old has finished.
  376 This eases programming. To manipulate a runing CBL it is neccesary to
  377 suspend the Command Unit to avoid race conditions. After a suspend
  378 is sent we have to wait for an interrupt that ACKs the suspend. Then
  379 we can manipulate the CBL and resume operation. I am not sure that this
  380 is more effective then the current, much simpler approach. => KISS
  381 See i82596CA data sheet page 26.
  382 
  383 A CBL is runing or on the way to be set up when (sc->sc_next_cb != 0).
  384 
  385 A CBL may consist of TX CMDs, and _only_ TX CMDs.
  386 A TX CBL is runing or on the way to be set up when
  387 ((sc->sc_next_cb != 0) && (sc->sc_next_tbd != 0)).
  388 
  389 A CBL may consist of other non-TX CMDs like IAS or CONF, and _only_
  390 non-TX CMDs.
  391 
  392 This comes mostly through the way how an Ethernet driver works and
  393 because runing CBLs are not manipulated when they are on the way. If
  394 if_start() is called there will be TX CMDs enqueued so we have a runing
  395 CBL and other CMDs from e.g. if_ioctl() will be deferd and vice versa.
  396 
  397 The Multicast Setup Command is special. A MCS needs more space then
  398 a single CB has. Actual space requiement depends on the length of the
  399 multicast list. So we allways defer MCS until other CBLs are finished,
  400 then we setup a CONF CMD in the first CB. The CONF CMD is needed to
  401 turn ALLMULTI on the hardware on or off. The MCS is the 2nd CB and may
  402 use all the remaining space in the CBL and the Transmit Buffer Descriptor
  403 List. (Therefore CBL and TBDL must be continious in pysical and virtual
  404 memory. This is guaranteed through the definitions of the list offsets
  405 in i82596reg.h and because it is only a single DMA segment used for all
  406 lists.) When ALLMULTI is enabled via the CONF CMD, the MCS is run with
  407 a multicast list length of 0, thus disabling the multicast filter.
  408 A defered MCS is signaled via ((sc->sc_flags & IEE_WANT_MCAST) != 0)
  409 */
  410 void
  411 iee_cb_setup(struct iee_softc *sc, uint32_t cmd)
  412 {
  413         struct iee_cb *cb = SC_CB(sc->sc_next_cb);
  414         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  415         struct ether_multistep step;
  416         struct ether_multi *enm;
  417 
  418         memset(cb, 0, IEE_CB_SZ);
  419         cb->cb_cmd = cmd;
  420         switch(cmd & IEE_CB_CMD) {
  421         case IEE_CB_CMD_NOP:    /* NOP CMD */
  422                 break;
  423         case IEE_CB_CMD_IAS:    /* Individual Address Setup */
  424                 memcpy((void*)cb->cb_ind_addr, LLADDR(ifp->if_sadl),
  425                     ETHER_ADDR_LEN);
  426                 break;
  427         case IEE_CB_CMD_CONF:   /* Configure */
  428                 memcpy((void*)cb->cb_cf, sc->sc_cf, sc->sc_cf[0]
  429                     & IEE_CF_0_CNT_M);
  430                 break;
  431         case IEE_CB_CMD_MCS:    /* Multicast Setup */
  432                 if (sc->sc_next_cb != 0) {
  433                         sc->sc_flags |= IEE_WANT_MCAST;
  434                         return;
  435                 }
  436                 sc->sc_flags &= ~IEE_WANT_MCAST;
  437                 if ((sc->sc_cf[8] & IEE_CF_8_PRM) != 0) {
  438                         /* Need no multicast filter in promisc mode. */
  439                         iee_cb_setup(sc, IEE_CB_CMD_CONF | IEE_CB_S | IEE_CB_EL
  440                             | IEE_CB_I);
  441                         return;
  442                 }
  443                 /* Leave room for a CONF CMD to en/dis-able ALLMULTI mode */
  444                 cb = SC_CB(sc->sc_next_cb + 1);
  445                 cb->cb_cmd = cmd;
  446                 cb->cb_mcast.mc_size = 0;
  447                 ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm);
  448                 while (enm != NULL) {
  449                         if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
  450                             ETHER_ADDR_LEN) != 0 || cb->cb_mcast.mc_size
  451                             * ETHER_ADDR_LEN + 2 * IEE_CB_SZ
  452                             > IEE_CB_LIST_SZ + IEE_TBD_LIST_SZ) {
  453                                 cb->cb_mcast.mc_size = 0;
  454                                 break;
  455                         }
  456                         memcpy((void*) &cb->cb_mcast.mc_addrs[
  457                             cb->cb_mcast.mc_size * ETHER_ADDR_LEN],
  458                             enm->enm_addrlo, ETHER_ADDR_LEN);
  459                         ETHER_NEXT_MULTI(step, enm);
  460                         cb->cb_mcast.mc_size++;
  461                 }
  462                 if (cb->cb_mcast.mc_size == 0) {
  463                         /* Can't do exact mcast filtering, do ALLMULTI mode. */
  464                         ifp->if_flags |= IFF_ALLMULTI;
  465                         sc->sc_cf[11] &= ~IEE_CF_11_MCALL;
  466                 } else {
  467                         /* disable ALLMULTI and load mcast list */
  468                         ifp->if_flags &= ~IFF_ALLMULTI;
  469                         sc->sc_cf[11] |= IEE_CF_11_MCALL;
  470                         /* Mcast setup may need more then IEE_CB_SZ bytes. */
  471                         bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map,
  472                             IEE_CB_OFF, IEE_CB_LIST_SZ + IEE_TBD_LIST_SZ,
  473                             BUS_DMASYNC_PREWRITE);
  474                 }
  475                 iee_cb_setup(sc, IEE_CB_CMD_CONF);
  476                 break;
  477         case IEE_CB_CMD_TR:     /* Transmit */
  478                 cb->cb_transmit.tx_tbd_addr = IEE_PHYS_SHMEM(IEE_TBD_OFF
  479                     + IEE_TBD_SZ * sc->sc_next_tbd);
  480                 cb->cb_cmd |= IEE_CB_SF; /* Allways use Flexible Mode. */
  481                 break;
  482         case IEE_CB_CMD_TDR:    /* Time Domain Reflectometry */
  483                 break;
  484         case IEE_CB_CMD_DUMP:   /* Dump */
  485                 break;
  486         case IEE_CB_CMD_DIAG:   /* Diagnose */
  487                 break;
  488         default:
  489                 /* can't happen */
  490                 break;
  491         }
  492         cb->cb_link_addr = IEE_PHYS_SHMEM(IEE_CB_OFF + IEE_CB_SZ *
  493             (sc->sc_next_cb + 1));
  494         bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, IEE_CB_OFF
  495             + IEE_CB_SZ * sc->sc_next_cb, IEE_CB_SZ, BUS_DMASYNC_PREWRITE);
  496         sc->sc_next_cb++;
  497         ifp->if_timer = 5;
  498         return;
  499 }
  500 
  501 
  502 
  503 void
  504 iee_attach(struct iee_softc *sc, uint8_t *eth_addr, int *media, int nmedia,
  505     int defmedia)
  506 {
  507         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  508         int n;
  509 
  510         /* Set pointer to Intermediate System Configuration Pointer. */
  511         /* Phys. addr. in big endian order. (Big endian as defined by Intel.) */
  512         SC_SCP->scp_iscp_addr = IEE_SWAP(IEE_PHYS_SHMEM(IEE_ISCP_OFF));
  513         /* Set pointer to System Control Block. */
  514         /* Phys. addr. in big endian order. (Big endian as defined by Intel.) */
  515         SC_ISCP->iscp_scb_addr = IEE_SWAP(IEE_PHYS_SHMEM(IEE_SCB_OFF));
  516         /* Set pointer to Receive Frame Area. (physical address) */
  517         SC_SCB->scb_rfa_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF);
  518         /* Set pointer to Command Block. (physical address) */
  519         SC_SCB->scb_cmd_blk_addr = IEE_PHYS_SHMEM(IEE_CB_OFF);
  520 
  521         ifmedia_init(&sc->sc_ifmedia, 0, iee_mediachange, iee_mediastatus);
  522         if (media != NULL) {
  523                 for (n = 0 ; n < nmedia ; n++)
  524                         ifmedia_add(&sc->sc_ifmedia, media[n], 0, NULL);
  525                 ifmedia_set(&sc->sc_ifmedia, defmedia);
  526         } else {
  527                 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_NONE, 0, NULL);
  528                 ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_NONE);
  529         }
  530 
  531         ifp->if_softc = sc;
  532         strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
  533         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  534         ifp->if_start = iee_start;      /* initiate output routine */
  535         ifp->if_ioctl = iee_ioctl;      /* ioctl routine */
  536         ifp->if_init = iee_init;        /* init routine */
  537         ifp->if_stop = iee_stop;        /* stop routine */
  538         ifp->if_watchdog = iee_watchdog;        /* timer routine */
  539         ifp->if_drain = iee_drain;      /* routine to release resources */
  540         IFQ_SET_READY(&ifp->if_snd);
  541         /* iee supports IEEE 802.1Q Virtual LANs, see vlan(4). */
  542         sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
  543 
  544         if_attach(ifp);
  545         ether_ifattach(ifp, eth_addr);
  546 
  547         aprint_normal(": Intel 82596%s address %s\n",
  548             i82596_typenames[ sc->sc_type], ether_sprintf(eth_addr));
  549 
  550         for (n = 0 ; n < IEE_NCB ; n++)
  551                 sc->sc_tx_map[n] = NULL;
  552         for (n = 0 ; n < IEE_NRFD ; n++) {
  553                 sc->sc_rx_mbuf[n] = NULL;
  554                 sc->sc_rx_map[n] = NULL;
  555         }
  556         sc->sc_tx_timeout = 0;
  557         sc->sc_setup_timeout = 0;
  558         (sc->sc_iee_reset)(sc);
  559         return;
  560 }
  561 
  562 
  563 
  564 void
  565 iee_detach(struct iee_softc *sc, int flags)
  566 {
  567         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  568 
  569         if ((ifp->if_flags & IFF_RUNNING) != 0)
  570                 iee_stop(ifp, 1);
  571         ether_ifdetach(ifp);
  572         if_detach(ifp);
  573         return;
  574 }
  575 
  576 
  577 
  578 /* media change and status callback */
  579 int
  580 iee_mediachange(struct ifnet *ifp)
  581 {
  582         struct iee_softc *sc = ifp->if_softc;
  583 
  584         if (sc->sc_mediachange != NULL)
  585                 return ((sc->sc_mediachange)(ifp));
  586         return(0);
  587 }
  588 
  589 
  590 
  591 void
  592 iee_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmreq)
  593 {
  594         struct iee_softc *sc = ifp->if_softc;
  595 
  596         if (sc->sc_mediastatus != NULL)
  597                 return ((sc->sc_mediastatus)(ifp, ifmreq));
  598         return;
  599 }
  600 
  601 
  602 
  603 /* initiate output routine */
  604 void
  605 iee_start(struct ifnet *ifp)
  606 {
  607         struct iee_softc *sc = ifp->if_softc;
  608         struct mbuf *m = NULL;
  609         int t;
  610         int n;
  611 
  612         if (sc->sc_next_cb != 0)
  613                 /* There is already a CMD runing. Defer packet enqueueing. */
  614                 return;
  615         for (t = 0 ; t < IEE_NCB ; t++) {
  616                 IFQ_DEQUEUE(&ifp->if_snd, sc->sc_tx_mbuf[t]);
  617                 if (sc->sc_tx_mbuf[t] == NULL)
  618                         break;
  619                 if (bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_tx_map[t],
  620                     sc->sc_tx_mbuf[t], BUS_DMA_WRITE | BUS_DMA_NOWAIT) != 0) {
  621                         /*
  622                          * The packet needs more TBD then we support.
  623                          * Copy the packet into a mbuf cluster to get it out.
  624                          */
  625                         printf("%s: iee_start: failed to load DMA map\n",
  626                             sc->sc_dev.dv_xname);
  627                         MGETHDR(m, M_DONTWAIT, MT_DATA);
  628                         if (m == NULL) {
  629                                 printf("%s: iee_start: can't allocate mbuf\n",
  630                                     sc->sc_dev.dv_xname);
  631                                 m_freem(sc->sc_tx_mbuf[t]);
  632                                 t--;
  633                                 continue;
  634                         }
  635                         MCLAIM(m, &sc->sc_ethercom.ec_rx_mowner);
  636                         MCLGET(m, M_DONTWAIT);
  637                         if ((m->m_flags & M_EXT) == 0) {
  638                                 printf("%s: iee_start: can't allocate mbuf "
  639                                     "cluster\n", sc->sc_dev.dv_xname);
  640                                 m_freem(sc->sc_tx_mbuf[t]);
  641                                 m_freem(m);
  642                                 t--;
  643                                 continue;
  644                         }
  645                         m_copydata(sc->sc_tx_mbuf[t], 0,
  646                             sc->sc_tx_mbuf[t]->m_pkthdr.len, mtod(m, caddr_t));
  647                         m->m_pkthdr.len = sc->sc_tx_mbuf[t]->m_pkthdr.len;
  648                         m->m_len = sc->sc_tx_mbuf[t]->m_pkthdr.len;
  649                         m_freem(sc->sc_tx_mbuf[t]);
  650                         sc->sc_tx_mbuf[t] = m;
  651                         if(bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_tx_map[t],
  652                             m, BUS_DMA_WRITE | BUS_DMA_NOWAIT) != 0) {
  653                                 printf("%s: iee_start: can't load TX DMA map\n",
  654                                     sc->sc_dev.dv_xname);
  655                                 m_freem(sc->sc_tx_mbuf[t]);
  656                                 t--;
  657                                 continue;
  658                         }
  659                 }
  660                 for (n = 0 ; n < sc->sc_tx_map[t]->dm_nsegs ; n++) {
  661                         SC_TBD(sc->sc_next_tbd + n)->tbd_tb_addr =
  662                             sc->sc_tx_map[t]->dm_segs[n].ds_addr;
  663                         SC_TBD(sc->sc_next_tbd + n)->tbd_size =
  664                             sc->sc_tx_map[t]->dm_segs[n].ds_len;
  665                         SC_TBD(sc->sc_next_tbd + n)->tbd_link_addr =
  666                             IEE_PHYS_SHMEM(IEE_TBD_OFF + IEE_TBD_SZ
  667                             * (sc->sc_next_tbd + n + 1));
  668                 }
  669                 SC_TBD(sc->sc_next_tbd + n - 1)->tbd_size |= IEE_CB_EL;
  670                 bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_map[t], 0,
  671                     sc->sc_tx_map[t]->dm_mapsize, BUS_DMASYNC_PREWRITE);
  672                 IFQ_POLL(&ifp->if_snd, m);
  673                 if (m == NULL)
  674                         iee_cb_setup(sc, IEE_CB_CMD_TR | IEE_CB_S | IEE_CB_EL
  675                             | IEE_CB_I);
  676                 else
  677                         iee_cb_setup(sc, IEE_CB_CMD_TR);
  678                 sc->sc_next_tbd += n;
  679 #if NBPFILTER > 0
  680                 /* Pass packet to bpf if someone listens. */
  681                 if (ifp->if_bpf)
  682                         bpf_mtap(ifp->if_bpf, sc->sc_tx_mbuf[t]);
  683 #endif
  684         }
  685         if (t == 0)
  686                 /* No packets got set up for TX. */
  687                 return;
  688         if (t == IEE_NCB)
  689                 ifp->if_flags |= IFF_OACTIVE;
  690         bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, IEE_CB_SZ,
  691             IEE_CB_LIST_SZ + IEE_TBD_LIST_SZ, BUS_DMASYNC_PREWRITE);
  692         (sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE);
  693         return;
  694 }
  695 
  696 
  697 
  698 /* ioctl routine */
  699 int
  700 iee_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  701 {
  702         struct iee_softc *sc = ifp->if_softc;
  703         int s;
  704         int err;
  705 
  706         s = splnet();
  707         switch (cmd) {
  708         case SIOCSIFMEDIA:
  709         case SIOCGIFMEDIA:
  710                 err = ifmedia_ioctl(ifp, (struct ifreq *) data,
  711                     &sc->sc_ifmedia, cmd);
  712                 break;
  713 
  714         default:
  715                 err = ether_ioctl(ifp, cmd, data);
  716                 if (err == ENETRESET) {
  717                         /*
  718                          * Multicast list as changed; set the hardware filter
  719                          * accordingly.
  720                          */
  721                         if (ifp->if_flags & IFF_RUNNING) {
  722                                 iee_cb_setup(sc, IEE_CB_CMD_MCS | IEE_CB_S |
  723                                     IEE_CB_EL | IEE_CB_I);
  724                                 if ((sc->sc_flags & IEE_WANT_MCAST) == 0)
  725                                         (*sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE);
  726                         }
  727                         err = 0;
  728                 }
  729                 break;
  730         }
  731         splx(s);
  732         return(err);
  733 }
  734 
  735 
  736 
  737 /* init routine */
  738 int
  739 iee_init(struct ifnet *ifp)
  740 {
  741         struct iee_softc *sc = ifp->if_softc;
  742         int r;
  743         int t;
  744         int n;
  745         int err;
  746 
  747         sc->sc_next_cb = 0;
  748         sc->sc_next_tbd = 0;
  749         sc->sc_flags &= ~IEE_WANT_MCAST;
  750         sc->sc_rx_done = 0;
  751         SC_SCB->scb_crc_err = 0;
  752         SC_SCB->scb_align_err = 0;
  753         SC_SCB->scb_resource_err = 0;
  754         SC_SCB->scb_overrun_err = 0;
  755         SC_SCB->scb_rcvcdt_err = 0;
  756         SC_SCB->scb_short_fr_err = 0;
  757         sc->sc_crc_err = 0;
  758         sc->sc_align_err = 0;
  759         sc->sc_resource_err = 0;
  760         sc->sc_overrun_err = 0;
  761         sc->sc_rcvcdt_err = 0;
  762         sc->sc_short_fr_err = 0;
  763         sc->sc_tx_col = 0;
  764         sc->sc_rx_err = 0;
  765         sc->sc_cmd_err = 0;
  766         /* Create Transmit DMA maps. */
  767         for (t = 0 ; t < IEE_NCB ; t++) {
  768                 if (sc->sc_tx_map[t] == NULL && bus_dmamap_create(sc->sc_dmat,
  769                     MCLBYTES, IEE_NTBD, MCLBYTES, 0, BUS_DMA_NOWAIT,
  770                     &sc->sc_tx_map[t]) != 0) {
  771                         printf("%s: iee_init: can't create TX DMA map\n",
  772                             sc->sc_dev.dv_xname);
  773                         for (n = 0 ; n < t ; n++)
  774                                 bus_dmamap_destroy(sc->sc_dmat,
  775                                     sc->sc_tx_map[n]);
  776                         return(ENOBUFS);
  777                 }
  778         }
  779         /* Initialize Receive Frame and Receive Buffer Descriptors */
  780         err = 0;
  781         memset(SC_RFD(0), 0, IEE_RFD_LIST_SZ);
  782         memset(SC_RBD(0), 0, IEE_RBD_LIST_SZ);
  783         for (r = 0 ; r < IEE_NRFD ; r++) {
  784                 SC_RFD(r)->rfd_cmd = IEE_RFD_SF;
  785                 SC_RFD(r)->rfd_link_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF
  786                     + IEE_RFD_SZ * ((r + 1) % IEE_NRFD));
  787 
  788                 SC_RBD(r)->rbd_next_rbd = IEE_PHYS_SHMEM(IEE_RBD_OFF
  789                     + IEE_RBD_SZ * ((r + 1) % IEE_NRFD));
  790                 if (sc->sc_rx_mbuf[r] == NULL) {
  791                         MGETHDR(sc->sc_rx_mbuf[r], M_DONTWAIT, MT_DATA);
  792                         if (sc->sc_rx_mbuf[r] == NULL) {
  793                                 printf("%s: iee_init: can't allocate mbuf\n",
  794                                     sc->sc_dev.dv_xname);
  795                                 err = 1;
  796                                 break;
  797                         }
  798                         MCLAIM(sc->sc_rx_mbuf[r],&sc->sc_ethercom.ec_rx_mowner);
  799                         MCLGET(sc->sc_rx_mbuf[r], M_DONTWAIT);
  800                         if ((sc->sc_rx_mbuf[r]->m_flags & M_EXT) == 0) {
  801                                 printf("%s: iee_init: can't allocate mbuf"
  802                                     " cluster\n", sc->sc_dev.dv_xname);
  803                                 m_freem(sc->sc_rx_mbuf[r]);
  804                                 err = 1;
  805                                 break;
  806                         }
  807                 }
  808                 if (sc->sc_rx_map[r] == NULL && bus_dmamap_create(sc->sc_dmat,
  809                     MCLBYTES, 1, MCLBYTES , 0, BUS_DMA_NOWAIT,
  810                     &sc->sc_rx_map[r]) != 0) {
  811                                 printf("%s: iee_init: can't create RX "
  812                                     "DMA map\n", sc->sc_dev.dv_xname);
  813                                 m_freem(sc->sc_rx_mbuf[r]);
  814                                 err = 1;
  815                                 break;
  816                         }
  817                 if (bus_dmamap_load(sc->sc_dmat, sc->sc_rx_map[r],
  818                     sc->sc_rx_mbuf[r]->m_ext.ext_buf,
  819                     sc->sc_rx_mbuf[r]->m_ext.ext_size, NULL,
  820                     BUS_DMA_READ | BUS_DMA_NOWAIT) != 0) {
  821                         printf("%s: iee_init: can't load RX DMA map\n",
  822                             sc->sc_dev.dv_xname);
  823                         bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_map[r]);
  824                         m_freem(sc->sc_rx_mbuf[r]);
  825                         err = 1;
  826                         break;
  827                 }
  828                 bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_map[r], 0,
  829                     sc->sc_rx_mbuf[r]->m_ext.ext_size, BUS_DMASYNC_PREREAD);
  830                 SC_RBD(r)->rbd_size = sc->sc_rx_map[r]->dm_segs[0].ds_len;
  831                 SC_RBD(r)->rbd_rb_addr= sc->sc_rx_map[r]->dm_segs[0].ds_addr;
  832         }
  833         SC_RFD(0)->rfd_rbd_addr = IEE_PHYS_SHMEM(IEE_RBD_OFF);
  834         if (err != 0) {
  835                 for (n = 0 ; n < r; n++) {
  836                         m_freem(sc->sc_rx_mbuf[n]);
  837                         sc->sc_rx_mbuf[n] = NULL;
  838                         bus_dmamap_unload(sc->sc_dmat, sc->sc_rx_map[n]);
  839                         bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_map[n]);
  840                         sc->sc_rx_map[n] = NULL;
  841                 }
  842                 for (n = 0 ; n < t ; n++) {
  843                         bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_map[n]);
  844                         sc->sc_tx_map[n] = NULL;
  845                 }
  846                 return(ENOBUFS);
  847         }
  848 
  849         (sc->sc_iee_reset)(sc);
  850         iee_cb_setup(sc, IEE_CB_CMD_IAS);
  851         sc->sc_cf[0] = IEE_CF_0_DEF | IEE_CF_0_PREF;
  852         sc->sc_cf[1] = IEE_CF_1_DEF;
  853         sc->sc_cf[2] = IEE_CF_2_DEF;
  854         sc->sc_cf[3] = IEE_CF_3_ADDRLEN_DEF | IEE_CF_3_NSAI
  855             | IEE_CF_3_PREAMLEN_DEF;
  856         sc->sc_cf[4] = IEE_CF_4_DEF;
  857         sc->sc_cf[5] = IEE_CF_5_DEF;
  858         sc->sc_cf[6] = IEE_CF_6_DEF;
  859         sc->sc_cf[7] = IEE_CF_7_DEF;
  860         sc->sc_cf[8] = IEE_CF_8_DEF;
  861         sc->sc_cf[9] = IEE_CF_9_DEF;
  862         sc->sc_cf[10] = IEE_CF_10_DEF;
  863         sc->sc_cf[11] = IEE_CF_11_DEF & ~IEE_CF_11_LNGFLD;
  864         sc->sc_cf[12] = IEE_CF_12_DEF;
  865         sc->sc_cf[13] = IEE_CF_13_DEF;
  866         iee_cb_setup(sc, IEE_CB_CMD_CONF | IEE_CB_S | IEE_CB_EL);
  867         SC_SCB->scb_rfa_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF);
  868         bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, 0, IEE_SHMEM_MAX,
  869             BUS_DMASYNC_PREWRITE);
  870         (sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE | IEE_SCB_RUC_ST);
  871         /* Issue a Channel Attention to ACK interrupts we may have caused. */
  872         (sc->sc_iee_cmd)(sc, IEE_SCB_ACK);
  873 
  874         /* Mark the interface as running and ready to RX/TX packets. */
  875         ifp->if_flags |= IFF_RUNNING;
  876         ifp->if_flags &= ~IFF_OACTIVE;
  877         return(0);
  878 }
  879 
  880 
  881 
  882 /* stop routine */
  883 void
  884 iee_stop(struct ifnet *ifp, int disable)
  885 {
  886         struct iee_softc *sc = ifp->if_softc;
  887         int n;
  888 
  889         ifp->if_flags &= ~IFF_RUNNING;
  890         ifp->if_flags |= IFF_OACTIVE;
  891         ifp->if_timer = 0;
  892         /* Reset the chip to get it quiet. */
  893         (sc->sc_iee_reset)(ifp->if_softc);
  894         /* Issue a Channel Attention to ACK interrupts we may have caused. */
  895         (sc->sc_iee_cmd)(ifp->if_softc, IEE_SCB_ACK);
  896         /* Release any dynamically allocated ressources. */
  897         for (n = 0 ; n < IEE_NCB ; n++) {
  898                 if (sc->sc_tx_map[n] != NULL)
  899                         bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_map[n]);
  900                 sc->sc_tx_map[n] = NULL;
  901         }
  902         for (n = 0 ; n < IEE_NRFD ; n++) {
  903                 if (sc->sc_rx_mbuf[n] != NULL)
  904                         m_freem(sc->sc_rx_mbuf[n]);
  905                 sc->sc_rx_mbuf[n] = NULL;
  906                 if (sc->sc_rx_map[n] != NULL) {
  907                         bus_dmamap_unload(sc->sc_dmat, sc->sc_rx_map[n]);
  908                         bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_map[n]);
  909                 }
  910                 sc->sc_rx_map[n] = NULL;
  911         }
  912         return;
  913 }
  914 
  915 
  916 
  917 /* timer routine */
  918 void
  919 iee_watchdog(struct ifnet *ifp)
  920 {
  921         struct iee_softc *sc = ifp->if_softc;
  922 
  923         (sc->sc_iee_reset)(sc);
  924         if (sc->sc_next_tbd != 0)
  925                 printf("%s: iee_watchdog: transmit timeout %d\n",
  926                     sc->sc_dev.dv_xname, ++sc->sc_tx_timeout);
  927         else
  928                 printf("%s: iee_watchdog: setup timeout %d\n",
  929                     sc->sc_dev.dv_xname, ++sc->sc_setup_timeout);
  930         iee_init(ifp);
  931         return;
  932 }
  933 
  934 
  935 
  936 /* routine to release res. */
  937 void
  938 iee_drain(struct ifnet *ifp)
  939 {
  940         iee_stop(ifp, 0);
  941         return;
  942 }
  943 
  944 
  945 

Cache object: 7586f9cd3951eef41b631703eb4e1517


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