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

Cache object: 36b5f57e4eceb7f50086042d2938f68b


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