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/le/am79900.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: am79900.c,v 1.17 2005/12/24 20:27:29 perry Exp $       */
    2 
    3 /*-
    4  * Copyright (c) 1997 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   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 THE FOUNDATION OR CONTRIBUTORS
   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  * Copyright (c) 1992, 1993
   34  *      The Regents of the University of California.  All rights reserved.
   35  *
   36  * This code is derived from software contributed to Berkeley by
   37  * Ralph Campbell and Rick Macklem.
   38  *
   39  * Redistribution and use in source and binary forms, with or without
   40  * modification, are permitted provided that the following conditions
   41  * are met:
   42  * 1. Redistributions of source code must retain the above copyright
   43  *    notice, this list of conditions and the following disclaimer.
   44  * 2. Redistributions in binary form must reproduce the above copyright
   45  *    notice, this list of conditions and the following disclaimer in the
   46  *    documentation and/or other materials provided with the distribution.
   47  * 3. Neither the name of the University nor the names of its contributors
   48  *    may be used to endorse or promote products derived from this software
   49  *    without specific prior written permission.
   50  *
   51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   61  * SUCH DAMAGE.
   62  *
   63  *      @(#)if_le.c     8.2 (Berkeley) 11/16/93
   64  */
   65 
   66 /*-
   67  * Copyright (c) 1998
   68  *      Matthias Drochner.  All rights reserved.
   69  * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
   70  *
   71  * This code is derived from software contributed to Berkeley by
   72  * Ralph Campbell and Rick Macklem.
   73  *
   74  * Redistribution and use in source and binary forms, with or without
   75  * modification, are permitted provided that the following conditions
   76  * are met:
   77  * 1. Redistributions of source code must retain the above copyright
   78  *    notice, this list of conditions and the following disclaimer.
   79  * 2. Redistributions in binary form must reproduce the above copyright
   80  *    notice, this list of conditions and the following disclaimer in the
   81  *    documentation and/or other materials provided with the distribution.
   82  * 3. All advertising materials mentioning features or use of this software
   83  *    must display the following acknowledgement:
   84  *      This product includes software developed by the University of
   85  *      California, Berkeley and its contributors.
   86  * 4. Neither the name of the University nor the names of its contributors
   87  *    may be used to endorse or promote products derived from this software
   88  *    without specific prior written permission.
   89  *
   90  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   91  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   92  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   93  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   94  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   95  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   96  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   97  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   98  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   99  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  100  * SUCH DAMAGE.
  101  *
  102  *      @(#)if_le.c     8.2 (Berkeley) 11/16/93
  103  */
  104 
  105 #include <sys/cdefs.h>
  106 __FBSDID("$FreeBSD$");
  107 
  108 #include <sys/param.h>
  109 #include <sys/bus.h>
  110 #include <sys/endian.h>
  111 #include <sys/lock.h>
  112 #include <sys/mbuf.h>
  113 #include <sys/mutex.h>
  114 #include <sys/socket.h>
  115 
  116 #include <net/bpf.h>
  117 #include <net/ethernet.h>
  118 #include <net/if.h>
  119 #include <net/if_arp.h>
  120 #include <net/if_dl.h>
  121 #include <net/if_media.h>
  122 #include <net/if_var.h>
  123 
  124 #include <machine/bus.h>
  125 
  126 #include <dev/le/lancereg.h>
  127 #include <dev/le/lancevar.h>
  128 #include <dev/le/am79900reg.h>
  129 #include <dev/le/am79900var.h>
  130 
  131 static void     am79900_meminit(struct lance_softc *);
  132 static void     am79900_rint(struct lance_softc *);
  133 static void     am79900_tint(struct lance_softc *);
  134 static void     am79900_start_locked(struct lance_softc *sc);
  135 
  136 #ifdef LEDEBUG
  137 static void     am79900_recv_print(struct lance_softc *, int);
  138 static void     am79900_xmit_print(struct lance_softc *, int);
  139 #endif
  140 
  141 int
  142 am79900_config(struct am79900_softc *sc, const char* name, int unit)
  143 {
  144         int error, mem;
  145 
  146         sc->lsc.sc_meminit = am79900_meminit;
  147         sc->lsc.sc_start_locked = am79900_start_locked;
  148 
  149         error = lance_config(&sc->lsc, name, unit);
  150         if (error != 0)
  151                 return (error);
  152 
  153         mem = 0;
  154         sc->lsc.sc_initaddr = mem;
  155         mem += sizeof(struct leinit);
  156         sc->lsc.sc_rmdaddr = mem;
  157         mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf;
  158         sc->lsc.sc_tmdaddr = mem;
  159         mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf;
  160         sc->lsc.sc_rbufaddr = mem;
  161         mem += LEBLEN * sc->lsc.sc_nrbuf;
  162         sc->lsc.sc_tbufaddr = mem;
  163         mem += LEBLEN * sc->lsc.sc_ntbuf;
  164 
  165         if (mem > sc->lsc.sc_memsize)
  166                 panic("%s: memsize", __func__);
  167 
  168         lance_attach(&sc->lsc);
  169 
  170         return (0);
  171 }
  172 
  173 void
  174 am79900_detach(struct am79900_softc *sc)
  175 {
  176 
  177         lance_detach(&sc->lsc);
  178 }
  179 
  180 /*
  181  * Set up the initialization block and the descriptor rings.
  182  */
  183 static void
  184 am79900_meminit(struct lance_softc *sc)
  185 {
  186         struct ifnet *ifp = sc->sc_ifp;
  187         struct leinit init;
  188         struct lermd rmd;
  189         struct letmd tmd;
  190         u_long a;
  191         int bix;
  192 
  193         LE_LOCK_ASSERT(sc, MA_OWNED);
  194 
  195         if (ifp->if_flags & IFF_PROMISC)
  196                 init.init_mode = LE_HTOLE32(LE_MODE_NORMAL | LE_MODE_PROM);
  197         else
  198                 init.init_mode = LE_HTOLE32(LE_MODE_NORMAL);
  199 
  200         init.init_mode |= LE_HTOLE32(((ffs(sc->sc_ntbuf) - 1) << 28) |
  201             ((ffs(sc->sc_nrbuf) - 1) << 20));
  202 
  203         init.init_padr[0] = LE_HTOLE32(sc->sc_enaddr[0] |
  204             (sc->sc_enaddr[1] << 8) | (sc->sc_enaddr[2] << 16) |
  205             (sc->sc_enaddr[3] << 24));
  206         init.init_padr[1] = LE_HTOLE32(sc->sc_enaddr[4] |
  207             (sc->sc_enaddr[5] << 8));
  208         lance_setladrf(sc, init.init_ladrf);
  209 
  210         sc->sc_last_rd = 0;
  211         sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
  212 
  213         a = sc->sc_addr + LE_RMDADDR(sc, 0);
  214         init.init_rdra = LE_HTOLE32(a);
  215 
  216         a = sc->sc_addr + LE_TMDADDR(sc, 0);
  217         init.init_tdra = LE_HTOLE32(a);
  218 
  219         (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
  220 
  221         /*
  222          * Set up receive ring descriptors.
  223          */
  224         for (bix = 0; bix < sc->sc_nrbuf; bix++) {
  225                 a = sc->sc_addr + LE_RBUFADDR(sc, bix);
  226                 rmd.rmd0 = LE_HTOLE32(a);
  227                 rmd.rmd1 = LE_HTOLE32(LE_R1_OWN | LE_R1_ONES |
  228                     (-LEBLEN & 0xfff));
  229                 rmd.rmd2 = 0;
  230                 rmd.rmd3 = 0;
  231                 (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
  232                     sizeof(rmd));
  233         }
  234 
  235         /*
  236          * Set up transmit ring descriptors.
  237          */
  238         for (bix = 0; bix < sc->sc_ntbuf; bix++) {
  239                 a = sc->sc_addr + LE_TBUFADDR(sc, bix);
  240                 tmd.tmd0 = LE_HTOLE32(a);
  241                 tmd.tmd1 = LE_HTOLE32(LE_T1_ONES);
  242                 tmd.tmd2 = 0;
  243                 tmd.tmd3 = 0;
  244                 (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
  245                     sizeof(tmd));
  246         }
  247 }
  248 
  249 static inline void
  250 am79900_rint(struct lance_softc *sc)
  251 {
  252         struct ifnet *ifp = sc->sc_ifp;
  253         struct mbuf *m;
  254         struct lermd rmd;
  255         uint32_t rmd1;
  256         int bix, rp;
  257 #if defined(__i386__) && !defined(PC98)
  258         struct ether_header *eh;
  259 #endif
  260 
  261         bix = sc->sc_last_rd;
  262 
  263         /* Process all buffers with valid data. */
  264         for (;;) {
  265                 rp = LE_RMDADDR(sc, bix);
  266                 (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
  267 
  268                 rmd1 = LE_LE32TOH(rmd.rmd1);
  269                 if (rmd1 & LE_R1_OWN)
  270                         break;
  271 
  272                 m = NULL;
  273                 if ((rmd1 & (LE_R1_ERR | LE_R1_STP | LE_R1_ENP)) !=
  274                     (LE_R1_STP | LE_R1_ENP)){
  275                         if (rmd1 & LE_R1_ERR) {
  276 #ifdef LEDEBUG
  277                                 if (rmd1 & LE_R1_ENP) {
  278                                         if ((rmd1 & LE_R1_OFLO) == 0) {
  279                                                 if (rmd1 & LE_R1_FRAM)
  280                                                         if_printf(ifp,
  281                                                             "framing error\n");
  282                                                 if (rmd1 & LE_R1_CRC)
  283                                                         if_printf(ifp,
  284                                                             "crc mismatch\n");
  285                                         }
  286                                 } else
  287                                         if (rmd1 & LE_R1_OFLO)
  288                                                 if_printf(ifp, "overflow\n");
  289 #endif
  290                                 if (rmd1 & LE_R1_BUFF)
  291                                         if_printf(ifp,
  292                                             "receive buffer error\n");
  293                         } else if ((rmd1 & (LE_R1_STP | LE_R1_ENP)) !=
  294                             (LE_R1_STP | LE_R1_ENP))
  295                                 if_printf(ifp, "dropping chained buffer\n");
  296                 } else {
  297 #ifdef LEDEBUG
  298                         if (sc->sc_flags & LE_DEBUG)
  299                                 am79900_recv_print(sc, bix);
  300 #endif
  301                         /* Pull the packet off the interface. */
  302                         m = lance_get(sc, LE_RBUFADDR(sc, bix),
  303                             (LE_LE32TOH(rmd.rmd2) & 0xfff) - ETHER_CRC_LEN);
  304                 }
  305 
  306                 rmd.rmd1 = LE_HTOLE32(LE_R1_OWN | LE_R1_ONES |
  307                     (-LEBLEN & 0xfff));
  308                 rmd.rmd2 = 0;
  309                 rmd.rmd3 = 0;
  310                 (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
  311 
  312                 if (++bix == sc->sc_nrbuf)
  313                         bix = 0;
  314 
  315                 if (m != NULL) {
  316                         ifp->if_ipackets++;
  317 
  318 #if defined(__i386__) && !defined(PC98)
  319                         /*
  320                          * The VMware LANCE does not present IFF_SIMPLEX
  321                          * behavior on multicast packets. Thus drop the
  322                          * packet if it is from ourselves.
  323                          */
  324                         eh = mtod(m, struct ether_header *);
  325                         if (!ether_cmp(eh->ether_shost, sc->sc_enaddr)) {
  326                                 m_freem(m);
  327                                 continue;
  328                         }
  329 #endif
  330 
  331                         /* Pass the packet up. */
  332                         LE_UNLOCK(sc);
  333                         (*ifp->if_input)(ifp, m);
  334                         LE_LOCK(sc);
  335                 } else
  336                         ifp->if_ierrors++;
  337         }
  338 
  339         sc->sc_last_rd = bix;
  340 }
  341 
  342 static inline void
  343 am79900_tint(struct lance_softc *sc)
  344 {
  345         struct ifnet *ifp = sc->sc_ifp;
  346         struct letmd tmd;
  347         uint32_t tmd1, tmd2;
  348         int bix;
  349 
  350         bix = sc->sc_first_td;
  351 
  352         for (;;) {
  353                 if (sc->sc_no_td <= 0)
  354                         break;
  355 
  356                 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
  357                     sizeof(tmd));
  358 
  359                 tmd1 = LE_LE32TOH(tmd.tmd1);
  360 
  361 #ifdef LEDEBUG
  362                 if (sc->sc_flags & LE_DEBUG)
  363                         if_printf(ifp, "trans tmd: "
  364                             "adr %08x, flags/blen %08x\n",
  365                             LE_LE32TOH(tmd.tmd0), tmd1);
  366 #endif
  367 
  368                 if (tmd1 & LE_T1_OWN)
  369                         break;
  370 
  371                 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  372 
  373                 if (tmd1 & LE_T1_ERR) {
  374                         tmd2 = LE_LE32TOH(tmd.tmd2);
  375                         if (tmd2 & LE_T2_BUFF)
  376                                 if_printf(ifp, "transmit buffer error\n");
  377                         else if (tmd2 & LE_T2_UFLO)
  378                                 if_printf(ifp, "underflow\n");
  379                         if (tmd2 & (LE_T2_BUFF | LE_T2_UFLO)) {
  380                                 lance_init_locked(sc);
  381                                 return;
  382                         }
  383                         if (tmd2 & LE_T2_LCAR) {
  384                                 if (sc->sc_flags & LE_CARRIER)
  385                                         if_link_state_change(ifp,
  386                                             LINK_STATE_DOWN);
  387                                 sc->sc_flags &= ~LE_CARRIER;
  388                                 if (sc->sc_nocarrier)
  389                                         (*sc->sc_nocarrier)(sc);
  390                                 else
  391                                         if_printf(ifp, "lost carrier\n");
  392                         }
  393                         if (tmd2 & LE_T2_LCOL)
  394                                 ifp->if_collisions++;
  395                         if (tmd2 & LE_T2_RTRY) {
  396 #ifdef LEDEBUG
  397                                 if_printf(ifp, "excessive collisions\n");
  398 #endif
  399                                 ifp->if_collisions += 16;
  400                         }
  401                         ifp->if_oerrors++;
  402                 } else {
  403                         if (tmd1 & LE_T1_ONE)
  404                                 ifp->if_collisions++;
  405                         else if (tmd1 & LE_T1_MORE)
  406                                 /* Real number is unknown. */
  407                                 ifp->if_collisions += 2;
  408                         ifp->if_opackets++;
  409                 }
  410 
  411                 if (++bix == sc->sc_ntbuf)
  412                         bix = 0;
  413 
  414                 --sc->sc_no_td;
  415         }
  416 
  417         sc->sc_first_td = bix;
  418 
  419         sc->sc_wdog_timer = sc->sc_no_td > 0 ? 5 : 0;
  420 }
  421 
  422 /*
  423  * Controller interrupt
  424  */
  425 void
  426 am79900_intr(void *arg)
  427 {
  428         struct lance_softc *sc = arg;
  429         struct ifnet *ifp = sc->sc_ifp;
  430         uint16_t isr;
  431 
  432         LE_LOCK(sc);
  433 
  434         if (sc->sc_hwintr && (*sc->sc_hwintr)(sc) == -1) {
  435                 ifp->if_ierrors++;
  436                 lance_init_locked(sc);
  437                 LE_UNLOCK(sc);
  438                 return;
  439         }
  440 
  441         isr = (*sc->sc_rdcsr)(sc, LE_CSR0);
  442 #if defined(LEDEBUG) && LEDEBUG > 1
  443         if (sc->sc_flags & LE_DEBUG)
  444                 if_printf(ifp, "%s: entering with isr=%04x\n", __func__, isr);
  445 #endif
  446         if ((isr & LE_C0_INTR) == 0) {
  447                 LE_UNLOCK(sc);
  448                 return;
  449         }
  450 
  451         /*
  452          * Clear interrupt source flags and turn off interrupts. If we
  453          * don't clear these flags before processing their sources we
  454          * could completely miss some interrupt events as the NIC can
  455          * change these flags while we're in this handler. We toggle
  456          * the interrupt enable bit in order to keep receiving them
  457          * (some chips work without this, some don't).
  458          */
  459         (*sc->sc_wrcsr)(sc, LE_CSR0, isr & ~(LE_C0_INEA | LE_C0_TDMD |
  460             LE_C0_STOP | LE_C0_STRT | LE_C0_INIT));
  461 
  462         if (isr & LE_C0_ERR) {
  463                 if (isr & LE_C0_BABL) {
  464 #ifdef LEDEBUG
  465                         if_printf(ifp, "babble\n");
  466 #endif
  467                         ifp->if_oerrors++;
  468                 }
  469 #if 0
  470                 if (isr & LE_C0_CERR) {
  471                         if_printf(ifp, "collision error\n");
  472                         ifp->if_collisions++;
  473                 }
  474 #endif
  475                 if (isr & LE_C0_MISS) {
  476 #ifdef LEDEBUG
  477                         if_printf(ifp, "missed packet\n");
  478 #endif
  479                         ifp->if_ierrors++;
  480                 }
  481                 if (isr & LE_C0_MERR) {
  482                         if_printf(ifp, "memory error\n");
  483                         lance_init_locked(sc);
  484                         LE_UNLOCK(sc);
  485                         return;
  486                 }
  487         }
  488 
  489         if ((isr & LE_C0_RXON) == 0) {
  490                 if_printf(ifp, "receiver disabled\n");
  491                 ifp->if_ierrors++;
  492                 lance_init_locked(sc);
  493                 LE_UNLOCK(sc);
  494                 return;
  495         }
  496         if ((isr & LE_C0_TXON) == 0) {
  497                 if_printf(ifp, "transmitter disabled\n");
  498                 ifp->if_oerrors++;
  499                 lance_init_locked(sc);
  500                 LE_UNLOCK(sc);
  501                 return;
  502         }
  503 
  504         /*
  505          * Pretend we have carrier; if we don't this will be cleared shortly.
  506          */
  507         if (!(sc->sc_flags & LE_CARRIER))
  508                 if_link_state_change(ifp, LINK_STATE_UP);
  509         sc->sc_flags |= LE_CARRIER;
  510 
  511         if (isr & LE_C0_RINT)
  512                 am79900_rint(sc);
  513         if (isr & LE_C0_TINT)
  514                 am79900_tint(sc);
  515 
  516         /* Enable interrupts again. */
  517         (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA);
  518 
  519         if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
  520                 am79900_start_locked(sc);
  521 
  522         LE_UNLOCK(sc);
  523 }
  524 
  525 /*
  526  * Set up output on interface.
  527  * Get another datagram to send off of the interface queue, and map it to the
  528  * interface before starting the output.
  529  */
  530 static void
  531 am79900_start_locked(struct lance_softc *sc)
  532 {
  533         struct ifnet *ifp = sc->sc_ifp;
  534         struct letmd tmd;
  535         struct mbuf *m;
  536         int bix, enq, len, rp;
  537 
  538         LE_LOCK_ASSERT(sc, MA_OWNED);
  539 
  540         if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
  541             IFF_DRV_RUNNING)
  542                 return;
  543 
  544         bix = sc->sc_last_td;
  545         enq = 0;
  546 
  547         for (; sc->sc_no_td < sc->sc_ntbuf &&
  548             !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) {
  549                 rp = LE_TMDADDR(sc, bix);
  550                 (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
  551 
  552                 if (LE_LE32TOH(tmd.tmd1) & LE_T1_OWN) {
  553                         ifp->if_drv_flags |= IFF_DRV_OACTIVE;
  554                         if_printf(ifp,
  555                             "missing buffer, no_td = %d, last_td = %d\n",
  556                             sc->sc_no_td, sc->sc_last_td);
  557                 }
  558 
  559                 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
  560                 if (m == 0)
  561                         break;
  562 
  563                 /*
  564                  * If BPF is listening on this interface, let it see the packet
  565                  * before we commit it to the wire.
  566                  */
  567                 BPF_MTAP(ifp, m);
  568 
  569                 /*
  570                  * Copy the mbuf chain into the transmit buffer.
  571                  */
  572                 len = lance_put(sc, LE_TBUFADDR(sc, bix), m);
  573 
  574 #ifdef LEDEBUG
  575                 if (len > ETHERMTU + ETHER_HDR_LEN)
  576                         if_printf(ifp, "packet length %d\n", len);
  577 #endif
  578 
  579                 /*
  580                  * Init transmit registers, and set transmit start flag.
  581                  */
  582                 tmd.tmd1 = LE_HTOLE32(LE_T1_OWN | LE_T1_STP | LE_T1_ENP |
  583                     LE_T1_ONES | (-len & 0xfff));
  584                 tmd.tmd2 = 0;
  585                 tmd.tmd3 = 0;
  586 
  587                 (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
  588 
  589 #ifdef LEDEBUG
  590                 if (sc->sc_flags & LE_DEBUG)
  591                         am79900_xmit_print(sc, bix);
  592 #endif
  593 
  594                 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
  595                 enq++;
  596 
  597                 if (++bix == sc->sc_ntbuf)
  598                         bix = 0;
  599 
  600                 if (++sc->sc_no_td == sc->sc_ntbuf) {
  601                         ifp->if_drv_flags |= IFF_DRV_OACTIVE;
  602                         break;
  603                 }
  604         }
  605 
  606         sc->sc_last_td = bix;
  607 
  608         if (enq > 0)
  609                 sc->sc_wdog_timer = 5;
  610 }
  611 
  612 #ifdef LEDEBUG
  613 static void
  614 am79900_recv_print(struct lance_softc *sc, int no)
  615 {
  616         struct ifnet *ifp = sc->sc_ifp;
  617         struct ether_header eh;
  618         struct lermd rmd;
  619         uint16_t len;
  620 
  621         (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
  622         len = LE_LE32TOH(rmd.rmd2) & 0xfff;
  623         if_printf(ifp, "receive buffer %d, len = %d\n", no, len);
  624         if_printf(ifp, "status %04x\n", (*sc->sc_rdcsr)(sc, LE_CSR0));
  625         if_printf(ifp, "adr %08x, flags/blen %08x\n", LE_LE32TOH(rmd.rmd0),
  626             LE_LE32TOH(rmd.rmd1));
  627         if (len - ETHER_CRC_LEN >= sizeof(eh)) {
  628                 (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
  629                 if_printf(ifp, "dst %s", ether_sprintf(eh.ether_dhost));
  630                 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
  631                     ntohs(eh.ether_type));
  632         }
  633 }
  634 
  635 static void
  636 am79900_xmit_print(struct lance_softc *sc, int no)
  637 {
  638         struct ifnet *ifp = sc->sc_ifp;
  639         struct ether_header eh;
  640         struct letmd tmd;
  641         uint16_t len;
  642 
  643         (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
  644         len = -(LE_LE32TOH(tmd.tmd1) & 0xfff);
  645         if_printf(ifp, "transmit buffer %d, len = %d\n", no, len);
  646         if_printf(ifp, "status %04x\n", (*sc->sc_rdcsr)(sc, LE_CSR0));
  647         if_printf(ifp, "adr %08x, flags/blen %08x\n", LE_LE32TOH(tmd.tmd0),
  648             LE_LE32TOH(tmd.tmd1));
  649         if (len >= sizeof(eh)) {
  650                 (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
  651                 if_printf(ifp, "dst %s", ether_sprintf(eh.ether_dhost));
  652                 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
  653                     ntohs(eh.ether_type));
  654         }
  655 }
  656 #endif /* LEDEBUG */

Cache object: ede752344fa775f809b9eb10bc559493


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