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

Cache object: 77b8da74e4a2748c25dad9b38b4487c8


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