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/smc90cx6.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: smc90cx6.c,v 1.45 2005/12/24 20:27:30 perry Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1994, 1995, 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Ignatios Souvatzis.
    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  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * Chip core driver for the SMC90c26 / SMC90c56 (and SMC90c66 in '56
   41  * compatibility mode) boards
   42  */
   43 
   44 #include <sys/cdefs.h>
   45 __KERNEL_RCSID(0, "$NetBSD: smc90cx6.c,v 1.45 2005/12/24 20:27:30 perry Exp $");
   46 
   47 /* #define BAHSOFTCOPY */
   48 #define BAHRETRANSMIT /**/
   49 
   50 #include "opt_inet.h"
   51 #include "bpfilter.h"
   52 
   53 #include <sys/param.h>
   54 #include <sys/systm.h>
   55 #include <sys/mbuf.h>
   56 #include <sys/buf.h>
   57 #include <sys/device.h>
   58 #include <sys/protosw.h>
   59 #include <sys/socket.h>
   60 #include <sys/syslog.h>
   61 #include <sys/ioctl.h>
   62 #include <sys/errno.h>
   63 
   64 #include <net/if.h>
   65 #include <net/if_dl.h>
   66 #include <net/if_types.h>
   67 #include <net/if_arc.h>
   68 
   69 #ifdef INET
   70 #include <netinet/in.h>
   71 #include <netinet/in_systm.h>
   72 #include <netinet/in_var.h>
   73 #include <netinet/ip.h>
   74 #include <netinet/if_inarp.h>
   75 #endif
   76 
   77 #if NBPFILTER > 0
   78 #include <net/bpf.h>
   79 #include <net/bpfdesc.h>
   80 #endif
   81 
   82 #include <sys/kernel.h>
   83 #include <machine/bus.h>
   84 #include <machine/cpu.h>
   85 #include <machine/intr.h>
   86 #include <machine/mtpr.h>
   87 
   88 #include <dev/ic/smc90cx6reg.h>
   89 #include <dev/ic/smc90cx6var.h>
   90 
   91 /* these should be elsewhere */
   92 
   93 #define ARC_MIN_LEN 1
   94 #define ARC_MIN_FORBID_LEN 254
   95 #define ARC_MAX_FORBID_LEN 256
   96 #define ARC_MAX_LEN 508
   97 #define ARC_ADDR_LEN 1
   98 
   99 /* for watchdog timer. This should be more than enough. */
  100 #define ARCTIMEOUT (5*IFNET_SLOWHZ)
  101 
  102 /*
  103  * This currently uses 2 bufs for tx, 2 for rx
  104  *
  105  * New rx protocol:
  106  *
  107  * rx has a fillcount variable. If fillcount > (NRXBUF-1),
  108  * rx can be switched off from rx hard int.
  109  * Else rx is restarted on the other receiver.
  110  * rx soft int counts down. if it is == (NRXBUF-1), it restarts
  111  * the receiver.
  112  * To ensure packet ordering (we need that for 1201 later), we have a counter
  113  * which is incremented modulo 256 on each receive and a per buffer
  114  * variable, which is set to the counter on filling. The soft int can
  115  * compare both values to determine the older packet.
  116  *
  117  * Transmit direction:
  118  *
  119  * bah_start checks tx_fillcount
  120  * case 2: return
  121  *
  122  * else fill tx_act ^ 1 && inc tx_fillcount
  123  *
  124  * check tx_fillcount again.
  125  * case 2: set IFF_OACTIVE to stop arc_output from filling us.
  126  * case 1: start tx
  127  *
  128  * tint clears IFF_OCATIVE, decrements and checks tx_fillcount
  129  * case 1: start tx on tx_act ^ 1, softcall bah_start
  130  * case 0: softcall bah_start
  131  *
  132  * #define fill(i) get mbuf && copy mbuf to chip(i)
  133  */
  134 
  135 void    bah_init(struct bah_softc *);
  136 void    bah_reset(struct bah_softc *);
  137 void    bah_stop(struct bah_softc *);
  138 void    bah_start(struct ifnet *);
  139 int     bahintr(void *);
  140 int     bah_ioctl(struct ifnet *, unsigned long, caddr_t);
  141 void    bah_watchdog(struct ifnet *);
  142 void    bah_srint(void *vsc);
  143 static  void bah_tint(struct bah_softc *, int);
  144 void    bah_reconwatch(void *);
  145 
  146 /* short notation */
  147 
  148 #define GETREG(off)     bus_space_read_1(bst_r, regs, (off))
  149 #define PUTREG(off, v)  bus_space_write_1(bst_r, regs, (off), (v))
  150 #define GETMEM(off)     bus_space_read_1(bst_m, mem, (off))
  151 #define PUTMEM(off, v)  bus_space_write_1(bst_m, mem, (off), (v))
  152 
  153 void
  154 bah_attach_subr(sc)
  155         struct bah_softc *sc;
  156 {
  157         struct ifnet *ifp = &sc->sc_arccom.ac_if;
  158         int s;
  159         u_int8_t linkaddress;
  160 
  161         bus_space_tag_t bst_r = sc->sc_bst_r;
  162         bus_space_tag_t bst_m = sc->sc_bst_m;
  163         bus_space_handle_t regs = sc->sc_regs;
  164         bus_space_handle_t mem = sc->sc_mem;
  165 
  166 #if (defined(BAH_DEBUG) && (BAH_DEBUG > 2))
  167         printf("\n%s: attach(0x%x, 0x%x, 0x%x)\n",
  168             sc->sc_dev.dv_xname, parent, self, aux);
  169 #endif
  170         s = splhigh();
  171 
  172         /*
  173          * read the arcnet address from the board
  174          */
  175 
  176         (*sc->sc_reset)(sc, 1);
  177 
  178         do {
  179                 delay(200);
  180         } while (!(GETREG(BAHSTAT) & BAH_POR));
  181 
  182         linkaddress = GETMEM(BAHMACOFF);
  183 
  184         printf(": link addr 0x%02x(%d)\n", linkaddress, linkaddress);
  185 
  186         /* clear the int mask... */
  187 
  188         sc->sc_intmask = 0;
  189         PUTREG(BAHSTAT, 0);
  190 
  191         PUTREG(BAHCMD, BAH_CONF(CONF_LONG));
  192         PUTREG(BAHCMD, BAH_CLR(CLR_POR|CLR_RECONFIG));
  193         sc->sc_recontime = sc->sc_reconcount = 0;
  194 
  195         /* and reenable kernel int level */
  196         splx(s);
  197 
  198         /*
  199          * set interface to stopped condition (reset)
  200          */
  201         bah_stop(sc);
  202 
  203         strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
  204         ifp->if_softc = sc;
  205         ifp->if_start = bah_start;
  206         ifp->if_ioctl = bah_ioctl;
  207         ifp->if_timer = 0;
  208         ifp->if_watchdog  = bah_watchdog;
  209         IFQ_SET_READY(&ifp->if_snd);
  210 
  211         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
  212 
  213         ifp->if_mtu = ARCMTU;
  214 
  215         arc_ifattach(ifp, linkaddress);
  216 
  217 #ifdef BAHSOFTCOPY
  218         sc->sc_rxcookie = softintr_establish(IPL_SOFTNET, bah_srint, sc);
  219         sc->sc_txcookie = softintr_establish(IPL_SOFTNET,
  220                 (void (*)(void *))bah_start, ifp);
  221 #endif
  222 
  223         callout_init(&sc->sc_recon_ch);
  224 }
  225 
  226 /*
  227  * Initialize device
  228  *
  229  */
  230 void
  231 bah_init(sc)
  232         struct bah_softc *sc;
  233 {
  234         struct ifnet *ifp;
  235         int s;
  236 
  237         ifp = &sc->sc_arccom.ac_if;
  238 
  239         if ((ifp->if_flags & IFF_RUNNING) == 0) {
  240                 s = splnet();
  241                 ifp->if_flags |= IFF_RUNNING;
  242                 bah_reset(sc);
  243                 bah_start(ifp);
  244                 splx(s);
  245         }
  246 }
  247 
  248 /*
  249  * Reset the interface...
  250  *
  251  * this assumes that it is called inside a critical section...
  252  *
  253  */
  254 void
  255 bah_reset(sc)
  256         struct bah_softc *sc;
  257 {
  258         struct ifnet *ifp;
  259         int linkaddress;
  260 
  261         bus_space_tag_t bst_r = sc->sc_bst_r;
  262         bus_space_tag_t bst_m = sc->sc_bst_m;
  263         bus_space_handle_t regs = sc->sc_regs;
  264         bus_space_handle_t mem = sc->sc_mem;
  265 
  266         ifp = &sc->sc_arccom.ac_if;
  267 
  268 #ifdef BAH_DEBUG
  269         printf("%s: reset\n", sc->sc_dev.dv_xname);
  270 #endif
  271         /* stop and restart hardware */
  272 
  273         (*sc->sc_reset)(sc, 1);
  274         do {
  275                 DELAY(200);
  276         } while (!(GETREG(BAHSTAT) & BAH_POR));
  277 
  278         linkaddress = GETMEM(BAHMACOFF);
  279 
  280 #if defined(BAH_DEBUG) && (BAH_DEBUG > 2)
  281         printf("%s: reset: card reset, link addr = 0x%02x (%ld)\n",
  282             sc->sc_dev.dv_xname, linkaddress, linkaddress);
  283 #endif
  284 
  285         /* tell the routing level about the (possibly changed) link address */
  286         arc_storelladdr(ifp, linkaddress);
  287 
  288         /* POR is NMI, but we need it below: */
  289         sc->sc_intmask = BAH_RECON|BAH_POR;
  290         PUTREG(BAHSTAT, sc->sc_intmask);
  291         PUTREG(BAHCMD, BAH_CONF(CONF_LONG));
  292 
  293 #ifdef BAH_DEBUG
  294         printf("%s: reset: chip configured, status=0x%02x\n",
  295             sc->sc_dev.dv_xname, GETREG(BAHSTAT));
  296 #endif
  297         PUTREG(BAHCMD, BAH_CLR(CLR_POR|CLR_RECONFIG));
  298 
  299 #ifdef BAH_DEBUG
  300         printf("%s: reset: bits cleared, status=0x%02x\n",
  301             sc->sc_dev.dv_xname, GETREG(BAHSTAT);
  302 #endif
  303 
  304         sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS;
  305 
  306         /* start receiver */
  307 
  308         sc->sc_intmask  |= BAH_RI;
  309         sc->sc_rx_fillcount = 0;
  310         sc->sc_rx_act = 2;
  311 
  312         PUTREG(BAHCMD, BAH_RXBC(2));
  313         PUTREG(BAHSTAT, sc->sc_intmask);
  314 
  315 #ifdef BAH_DEBUG
  316         printf("%s: reset: started receiver, status=0x%02x\n",
  317             sc->sc_dev.dv_xname, GETREG(BAHSTAT);
  318 #endif
  319 
  320         /* and init transmitter status */
  321         sc->sc_tx_act = 0;
  322         sc->sc_tx_fillcount = 0;
  323 
  324         ifp->if_flags |= IFF_RUNNING;
  325         ifp->if_flags &= ~IFF_OACTIVE;
  326 
  327         bah_start(ifp);
  328 }
  329 
  330 /*
  331  * Take interface offline
  332  */
  333 void
  334 bah_stop(sc)
  335         struct bah_softc *sc;
  336 {
  337         bus_space_tag_t bst_r = sc->sc_bst_r;
  338         bus_space_handle_t regs = sc->sc_regs;
  339 
  340         /* Stop the interrupts */
  341         PUTREG(BAHSTAT, 0);
  342 
  343         /* Stop the interface */
  344         (*sc->sc_reset)(sc, 0);
  345 
  346         /* Stop watchdog timer */
  347         sc->sc_arccom.ac_if.if_timer = 0;
  348 }
  349 
  350 /*
  351  * Start output on interface. Get another datagram to send
  352  * off the interface queue, and copy it to the
  353  * interface before starting the output
  354  *
  355  * this assumes that it is called inside a critical section...
  356  * XXX hm... does it still?
  357  *
  358  */
  359 void
  360 bah_start(ifp)
  361         struct ifnet *ifp;
  362 {
  363         struct bah_softc *sc = ifp->if_softc;
  364         struct mbuf *m,*mp;
  365 
  366         bus_space_tag_t bst_r = sc->sc_bst_r;
  367         bus_space_handle_t regs = sc->sc_regs;
  368         bus_space_tag_t bst_m = sc->sc_bst_m;
  369         bus_space_handle_t mem = sc->sc_mem;
  370 
  371         int bah_ram_ptr;
  372         int len, tlen, offset, s, buffer;
  373 #ifdef BAHTIMINGS
  374         u_long copystart, lencopy, perbyte;
  375 #endif
  376 
  377 #if defined(BAH_DEBUG) && (BAH_DEBUG > 3)
  378         printf("%s: start(0x%x)\n", sc->sc_dev.dv_xname, ifp);
  379 #endif
  380 
  381         if ((ifp->if_flags & IFF_RUNNING) == 0)
  382                 return;
  383 
  384         s = splnet();
  385 
  386         if (sc->sc_tx_fillcount >= 2) {
  387                 splx(s);
  388                 return;
  389         }
  390 
  391         IFQ_DEQUEUE(&ifp->if_snd, m);
  392         buffer = sc->sc_tx_act ^ 1;
  393 
  394         splx(s);
  395 
  396         if (m == 0)
  397                 return;
  398 
  399 #if NBPFILTER > 0
  400         /*
  401          * If bpf is listening on this interface, let it
  402          * see the packet before we commit it to the wire
  403          *
  404          * (can't give the copy in A2060 card RAM to bpf, because
  405          * that RAM is just accessed as on every other byte)
  406          */
  407         if (ifp->if_bpf)
  408                 bpf_mtap(ifp->if_bpf, m);
  409 #endif
  410 
  411 #ifdef BAH_DEBUG
  412         if (m->m_len < ARC_HDRLEN)
  413                 m = m_pullup(m, ARC_HDRLEN);/* gcc does structure padding */
  414         printf("%s: start: filling %ld from %ld to %ld type %ld\n",
  415             sc->sc_dev.dv_xname, buffer, mtod(m, u_char *)[0],
  416             mtod(m, u_char *)[1], mtod(m, u_char *)[2]);
  417 #else
  418         if (m->m_len < 2)
  419                 m = m_pullup(m, 2);
  420 #endif
  421         bah_ram_ptr = buffer*512;
  422 
  423         if (m == 0)
  424                 return;
  425 
  426         /* write the addresses to RAM and throw them away */
  427 
  428         /*
  429          * Hardware does this: Yet Another Microsecond Saved.
  430          * (btw, timing code says usually 2 microseconds)
  431          * PUTMEM(bah_ram_ptr + 0, mtod(m, u_char *)[0]);
  432          */
  433 
  434         PUTMEM(bah_ram_ptr + 1, mtod(m, u_char *)[1]);
  435         m_adj(m, 2);
  436 
  437         /* get total length left at this point */
  438         tlen = m->m_pkthdr.len;
  439         if (tlen < ARC_MIN_FORBID_LEN) {
  440                 offset = 256 - tlen;
  441                 PUTMEM(bah_ram_ptr + 2, offset);
  442         } else {
  443                 PUTMEM(bah_ram_ptr + 2, 0);
  444                 if (tlen <= ARC_MAX_FORBID_LEN)
  445                         offset = 255;           /* !!! */
  446                 else {
  447                         if (tlen > ARC_MAX_LEN)
  448                                 tlen = ARC_MAX_LEN;
  449                         offset = 512 - tlen;
  450                 }
  451                 PUTMEM(bah_ram_ptr + 3, offset);
  452 
  453         }
  454         bah_ram_ptr += offset;
  455 
  456         /* lets loop through the mbuf chain */
  457 
  458         for (mp = m; mp; mp = mp->m_next) {
  459                 if ((len = mp->m_len)) {                /* YAMS */
  460                         bus_space_write_region_1(bst_m, mem, bah_ram_ptr,
  461                             mtod(mp, caddr_t), len);
  462 
  463                         bah_ram_ptr += len;
  464                 }
  465         }
  466 
  467         sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0;
  468         sc->sc_retransmits[buffer] = (m->m_flags & M_BCAST) ? 1 : 5;
  469 
  470         /* actually transmit the packet */
  471         s = splnet();
  472 
  473         if (++sc->sc_tx_fillcount > 1) {
  474                 /*
  475                  * We are filled up to the rim. No more bufs for the moment,
  476                  * please.
  477                  */
  478                 ifp->if_flags |= IFF_OACTIVE;
  479         } else {
  480 #ifdef BAH_DEBUG
  481                 printf("%s: start: starting transmitter on buffer %d\n",
  482                     sc->sc_dev.dv_xname, buffer);
  483 #endif
  484                 /* Transmitter was off, start it */
  485                 sc->sc_tx_act = buffer;
  486 
  487                 /*
  488                  * We still can accept another buf, so don't:
  489                  * ifp->if_flags |= IFF_OACTIVE;
  490                  */
  491                 sc->sc_intmask |= BAH_TA;
  492                 PUTREG(BAHCMD, BAH_TX(buffer));
  493                 PUTREG(BAHSTAT, sc->sc_intmask);
  494 
  495                 sc->sc_arccom.ac_if.if_timer = ARCTIMEOUT;
  496         }
  497         splx(s);
  498         m_freem(m);
  499 
  500         /*
  501          * After 10 times reading the docs, I realized
  502          * that in the case the receiver NAKs the buffer request,
  503          * the hardware retries till shutdown.
  504          * This is integrated now in the code above.
  505          */
  506 
  507         return;
  508 }
  509 
  510 /*
  511  * Arcnet interface receiver soft interrupt:
  512  * get the stuff out of any filled buffer we find.
  513  */
  514 void
  515 bah_srint(vsc)
  516         void *vsc;
  517 {
  518         struct bah_softc *sc = (struct bah_softc *)vsc;
  519         int buffer, len, len1, amount, offset, s, type;
  520         int bah_ram_ptr;
  521         struct mbuf *m, *dst, *head;
  522         struct arc_header *ah;
  523         struct ifnet *ifp;
  524 
  525         bus_space_tag_t bst_r = sc->sc_bst_r;
  526         bus_space_tag_t bst_m = sc->sc_bst_m;
  527         bus_space_handle_t regs = sc->sc_regs;
  528         bus_space_handle_t mem = sc->sc_mem;
  529 
  530         ifp = &sc->sc_arccom.ac_if;
  531         head = 0;
  532 
  533         s = splnet();
  534         buffer = sc->sc_rx_act ^ 1;
  535         splx(s);
  536 
  537         /* Allocate header mbuf */
  538         MGETHDR(m, M_DONTWAIT, MT_DATA);
  539 
  540         if (m == 0) {
  541                 /*
  542                  * in case s.th. goes wrong with mem, drop it
  543                  * to make sure the receiver can be started again
  544                  * count it as input error (we dont have any other
  545                  * detectable)
  546                  */
  547                 ifp->if_ierrors++;
  548                 goto cleanup;
  549         }
  550 
  551         m->m_pkthdr.rcvif = ifp;
  552 
  553         /*
  554          * Align so that IP packet will be longword aligned. Here we
  555          * assume that m_data of new packet is longword aligned.
  556          * When implementing PHDS, we might have to change it to 2,
  557          * (2*sizeof(ulong) - ARC_HDRNEWLEN)), packet type dependent.
  558          */
  559 
  560         bah_ram_ptr = buffer*512;
  561         offset = GETMEM(bah_ram_ptr + 2);
  562         if (offset)
  563                 len = 256 - offset;
  564         else {
  565                 offset = GETMEM(bah_ram_ptr + 3);
  566                 len = 512 - offset;
  567         }
  568         if (len+2 >= MINCLSIZE)
  569                 MCLGET(m, M_DONTWAIT);
  570 
  571         if (m == 0) {
  572                 ifp->if_ierrors++;
  573                 goto cleanup;
  574         }
  575 
  576         type = GETMEM(bah_ram_ptr + offset);
  577         m->m_data += 1 + arc_isphds(type);
  578 
  579         head = m;
  580         ah = mtod(head, struct arc_header *);
  581 
  582         ah->arc_shost = GETMEM(bah_ram_ptr + 0);
  583         ah->arc_dhost = GETMEM(bah_ram_ptr + 1);
  584 
  585         m->m_pkthdr.len = len+2; /* whole packet length */
  586         m->m_len = 2;            /* mbuf filled with ARCnet addresses */
  587         bah_ram_ptr += offset;  /* ram buffer continues there */
  588 
  589         while (len > 0) {
  590 
  591                 len1 = len;
  592                 amount = M_TRAILINGSPACE(m);
  593 
  594                 if (amount == 0) {
  595                         dst = m;
  596                         MGET(m, M_DONTWAIT, MT_DATA);
  597 
  598                         if (m == 0) {
  599                                 ifp->if_ierrors++;
  600                                 goto cleanup;
  601                         }
  602 
  603                         if (len1 >= MINCLSIZE)
  604                                 MCLGET(m, M_DONTWAIT);
  605 
  606                         m->m_len = 0;
  607                         dst->m_next = m;
  608                         amount = M_TRAILINGSPACE(m);
  609                 }
  610 
  611                 if (amount < len1)
  612                         len1 = amount;
  613 
  614                 bus_space_read_region_1(bst_m, mem, bah_ram_ptr,
  615                     mtod(m, u_char *) + m->m_len, len1);
  616 
  617                 m->m_len += len1;
  618                 bah_ram_ptr += len1;
  619                 len -= len1;
  620         }
  621 
  622 #if NBPFILTER > 0
  623         if (ifp->if_bpf)
  624                 bpf_mtap(ifp->if_bpf, head);
  625 #endif
  626 
  627         (*sc->sc_arccom.ac_if.if_input)(&sc->sc_arccom.ac_if, head);
  628 
  629         head = NULL;
  630         ifp->if_ipackets++;
  631 
  632 cleanup:
  633 
  634         if (head != NULL)
  635                 m_freem(head);
  636 
  637         /* mark buffer as invalid by source id 0 */
  638         bus_space_write_1(bst_m, mem, buffer*512, 0);
  639         s = splnet();
  640 
  641         if (--sc->sc_rx_fillcount == 2 - 1) {
  642 
  643                 /* was off, restart it on buffer just emptied */
  644                 sc->sc_rx_act = buffer;
  645                 sc->sc_intmask |= BAH_RI;
  646 
  647                 /* this also clears the RI flag interrupt: */
  648                 PUTREG(BAHCMD, BAH_RXBC(buffer));
  649                 PUTREG(BAHSTAT, sc->sc_intmask);
  650 
  651 #ifdef BAH_DEBUG
  652                 printf("%s: srint: restarted rx on buf %ld\n",
  653                     sc->sc_dev.dv_xname, buffer);
  654 #endif
  655         }
  656         splx(s);
  657 }
  658 
  659 inline static void
  660 bah_tint(sc, isr)
  661         struct bah_softc *sc;
  662         int isr;
  663 {
  664         struct ifnet *ifp;
  665 
  666         bus_space_tag_t bst_r = sc->sc_bst_r;
  667         bus_space_handle_t regs = sc->sc_regs;
  668 
  669 
  670         int buffer;
  671 #ifdef BAHTIMINGS
  672         int clknow;
  673 #endif
  674 
  675         ifp = &(sc->sc_arccom.ac_if);
  676         buffer = sc->sc_tx_act;
  677 
  678         /*
  679          * retransmit code:
  680          * Normal situations first for fast path:
  681          * If acknowledgement received ok or broadcast, we're ok.
  682          * else if
  683          */
  684 
  685         if (isr & BAH_TMA || sc->sc_broadcast[buffer])
  686                 sc->sc_arccom.ac_if.if_opackets++;
  687 #ifdef BAHRETRANSMIT
  688         else if (ifp->if_flags & IFF_LINK2 && ifp->if_timer > 0
  689             && --sc->sc_retransmits[buffer] > 0) {
  690                 /* retransmit same buffer */
  691                 PUTREG(BAHCMD, BAH_TX(buffer));
  692                 return;
  693         }
  694 #endif
  695         else
  696                 ifp->if_oerrors++;
  697 
  698 
  699         /* We know we can accept another buffer at this point. */
  700         ifp->if_flags &= ~IFF_OACTIVE;
  701 
  702         if (--sc->sc_tx_fillcount > 0) {
  703 
  704                 /*
  705                  * start tx on other buffer.
  706                  * This also clears the int flag
  707                  */
  708                 buffer ^= 1;
  709                 sc->sc_tx_act = buffer;
  710 
  711                 /*
  712                  * already given:
  713                  * sc->sc_intmask |= BAH_TA;
  714                  * PUTREG(BAHSTAT, sc->sc_intmask);
  715                  */
  716                 PUTREG(BAHCMD, BAH_TX(buffer));
  717                 /* init watchdog timer */
  718                 ifp->if_timer = ARCTIMEOUT;
  719 
  720 #if defined(BAH_DEBUG) && (BAH_DEBUG > 1)
  721                 printf("%s: tint: starting tx on buffer %d, status 0x%02x\n",
  722                     sc->sc_dev.dv_xname, buffer, GETREG(BAHSTAT));
  723 #endif
  724         } else {
  725                 /* have to disable TX interrupt */
  726                 sc->sc_intmask &= ~BAH_TA;
  727                 PUTREG(BAHSTAT, sc->sc_intmask);
  728                 /* ... and watchdog timer */
  729                 ifp->if_timer = 0;
  730 
  731 #ifdef BAH_DEBUG
  732                 printf("%s: tint: no more buffers to send, status 0x%02x\n",
  733                     sc->sc_dev.dv_xname, GETREG(BAHSTAT));
  734 #endif
  735         }
  736 
  737         /* XXXX TODO */
  738 #ifdef BAHSOFTCOPY
  739         /* schedule soft int to fill a new buffer for us */
  740         softintr_schedule(sc->sc_txcookie);
  741 #else
  742         /* call it directly */
  743         bah_start(ifp);
  744 #endif
  745 }
  746 
  747 /*
  748  * Our interrupt routine
  749  */
  750 int
  751 bahintr(arg)
  752         void *arg;
  753 {
  754         struct bah_softc *sc = arg;
  755 
  756         bus_space_tag_t bst_r = sc->sc_bst_r;
  757         bus_space_tag_t bst_m = sc->sc_bst_m;
  758         bus_space_handle_t regs = sc->sc_regs;
  759         bus_space_handle_t mem = sc->sc_mem;
  760 
  761         u_char isr, maskedisr;
  762         int buffer;
  763         u_long newsec;
  764 
  765         isr = GETREG(BAHSTAT);
  766         maskedisr = isr & sc->sc_intmask;
  767         if (!maskedisr)
  768                 return (0);
  769         do {
  770 
  771 #if defined(BAH_DEBUG) && (BAH_DEBUG>1)
  772                 printf("%s: intr: status 0x%02x, intmask 0x%02x\n",
  773                     sc->sc_dev.dv_xname, isr, sc->sc_intmask);
  774 #endif
  775 
  776                 if (maskedisr & BAH_POR) {
  777                         /*
  778                          * XXX We should never see this. Don't bother to store
  779                          * the address.
  780                          * sc->sc_arccom.ac_anaddr = GETMEM(BAHMACOFF);
  781                          */
  782                         PUTREG(BAHCMD, BAH_CLR(CLR_POR));
  783                         log(LOG_WARNING,
  784                             "%s: intr: got spurious power on reset int\n",
  785                             sc->sc_dev.dv_xname);
  786                 }
  787 
  788                 if (maskedisr & BAH_RECON) {
  789                         /*
  790                          * we dont need to:
  791                          * PUTREG(BAHCMD, BAH_CONF(CONF_LONG));
  792                          */
  793                         PUTREG(BAHCMD, BAH_CLR(CLR_RECONFIG));
  794                         sc->sc_arccom.ac_if.if_collisions++;
  795 
  796                         /*
  797                          * If less than 2 seconds per reconfig:
  798                          *      If ARC_EXCESSIVE_RECONFIGS
  799                          *      since last burst, complain and set treshold for
  800                          *      warnings to ARC_EXCESSIVE_RECONS_REWARN.
  801                          *
  802                          * This allows for, e.g., new stations on the cable, or
  803                          * cable switching as long as it is over after
  804                          * (normally) 16 seconds.
  805                          *
  806                          * XXX TODO: check timeout bits in status word and
  807                          * double time if necessary.
  808                          */
  809 
  810                         callout_stop(&sc->sc_recon_ch);
  811                         newsec = time.tv_sec;
  812                         if ((newsec - sc->sc_recontime <= 2) &&
  813                             (++sc->sc_reconcount == ARC_EXCESSIVE_RECONS)) {
  814                                 log(LOG_WARNING,
  815                                     "%s: excessive token losses, "
  816                                     "cable problem?\n", sc->sc_dev.dv_xname);
  817                         }
  818                         sc->sc_recontime = newsec;
  819                         callout_reset(&sc->sc_recon_ch, 15 * hz,
  820                             bah_reconwatch, (void *)sc);
  821                 }
  822 
  823                 if (maskedisr & BAH_RI) {
  824 #if defined(BAH_DEBUG) && (BAH_DEBUG > 1)
  825                         printf("%s: intr: hard rint, act %ld\n",
  826                             sc->sc_dev.dv_xname, sc->sc_rx_act);
  827 #endif
  828 
  829                         buffer = sc->sc_rx_act;
  830                         /* look if buffer is marked invalid: */
  831                         if (GETMEM(buffer*512) == 0) {
  832                                 /*
  833                                  * invalid marked buffer (or illegally
  834                                  * configured sender)
  835                                  */
  836                                 log(LOG_WARNING,
  837                                     "%s: spurious RX interrupt or sender 0 "
  838                                     " (ignored)\n", sc->sc_dev.dv_xname);
  839                                 /*
  840                                  * restart receiver on same buffer.
  841                                  * XXX maybe better reset interface?
  842                                  */
  843                                 PUTREG(BAHCMD, BAH_RXBC(buffer));
  844                         } else {
  845                                 if (++sc->sc_rx_fillcount > 1) {
  846                                         sc->sc_intmask &= ~BAH_RI;
  847                                         PUTREG(BAHSTAT, sc->sc_intmask);
  848                                 } else {
  849                                         buffer ^= 1;
  850                                         sc->sc_rx_act = buffer;
  851 
  852                                         /*
  853                                          * Start receiver on other receive
  854                                          * buffer. This also clears the RI
  855                                          * interrupt flag.
  856                                          */
  857                                         PUTREG(BAHCMD, BAH_RXBC(buffer));
  858                                         /* in RX intr, so mask is ok for RX */
  859 
  860 #ifdef BAH_DEBUG
  861                                         printf("%s: strt rx for buf %ld, "
  862                                             "stat 0x%02x\n",
  863                                             sc->sc_dev.dv_xname, sc->sc_rx_act,
  864                                             GETREG(BAHSTAT);
  865 #endif
  866                                 }
  867 
  868 #ifdef BAHSOFTCOPY
  869                                 /*
  870                                  * this one starts a soft int to copy out
  871                                  * of the hw
  872                                  */
  873                                 softintr_schedule(sc->sc_rxcookie);
  874 #else
  875                                 /* this one does the copy here */
  876                                 bah_srint(sc);
  877 #endif
  878                         }
  879                 }
  880                 if (maskedisr & BAH_TA) {
  881                         bah_tint(sc, isr);
  882                 }
  883                 isr = GETREG(BAHSTAT);
  884                 maskedisr = isr & sc->sc_intmask;
  885         } while (maskedisr);
  886 
  887         return (1);
  888 }
  889 
  890 void
  891 bah_reconwatch(arg)
  892         void *arg;
  893 {
  894         struct bah_softc *sc = arg;
  895 
  896         if (sc->sc_reconcount >= ARC_EXCESSIVE_RECONS) {
  897                 sc->sc_reconcount = 0;
  898                 log(LOG_WARNING, "%s: token valid again.\n",
  899                     sc->sc_dev.dv_xname);
  900         }
  901         sc->sc_reconcount = 0;
  902 }
  903 
  904 
  905 /*
  906  * Process an ioctl request.
  907  * This code needs some work - it looks pretty ugly.
  908  */
  909 int
  910 bah_ioctl(ifp, command, data)
  911         struct ifnet *ifp;
  912         u_long command;
  913         caddr_t data;
  914 {
  915         struct bah_softc *sc;
  916         struct ifaddr *ifa;
  917         struct ifreq *ifr;
  918         int s, error;
  919 
  920         error = 0;
  921         sc = ifp->if_softc;
  922         ifa = (struct ifaddr *)data;
  923         ifr = (struct ifreq *)data;
  924         s = splnet();
  925 
  926 #if defined(BAH_DEBUG) && (BAH_DEBUG > 2)
  927         printf("%s: ioctl() called, cmd = 0x%x\n",
  928             sc->sc_dev.dv_xname, command);
  929 #endif
  930 
  931         switch (command) {
  932         case SIOCSIFADDR:
  933                 ifp->if_flags |= IFF_UP;
  934                 switch (ifa->ifa_addr->sa_family) {
  935 #ifdef INET
  936                 case AF_INET:
  937                         bah_init(sc);
  938                         arp_ifinit(ifp, ifa);
  939                         break;
  940 #endif
  941                 default:
  942                         bah_init(sc);
  943                         break;
  944                 }
  945 
  946         case SIOCSIFFLAGS:
  947                 if ((ifp->if_flags & IFF_UP) == 0 &&
  948                     (ifp->if_flags & IFF_RUNNING) != 0) {
  949                         /*
  950                          * If interface is marked down and it is running,
  951                          * then stop it.
  952                          */
  953                         bah_stop(sc);
  954                         ifp->if_flags &= ~IFF_RUNNING;
  955                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
  956                            (ifp->if_flags & IFF_RUNNING) == 0) {
  957                         /*
  958                          * If interface is marked up and it is stopped, then
  959                          * start it.
  960                          */
  961                         bah_init(sc);
  962                 }
  963                 break;
  964 
  965         case SIOCADDMULTI:
  966         case SIOCDELMULTI:
  967                 switch (ifr->ifr_addr.sa_family) {
  968                 case AF_INET:
  969                 case AF_INET6:
  970                         error = 0;
  971                         break;
  972                 default:
  973                         error = EAFNOSUPPORT;
  974                         break;
  975                 }
  976                 break;
  977 
  978         default:
  979                 error = EINVAL;
  980         }
  981 
  982         splx(s);
  983         return (error);
  984 }
  985 
  986 /*
  987  * watchdog routine for transmitter.
  988  *
  989  * We need this, because else a receiver whose hardware is alive, but whose
  990  * software has not enabled the Receiver, would make our hardware wait forever
  991  * Discovered this after 20 times reading the docs.
  992  *
  993  * Only thing we do is disable transmitter. We'll get an transmit timeout,
  994  * and the int handler will have to decide not to retransmit (in case
  995  * retransmission is implemented).
  996  *
  997  * This one assumes being called inside splnet()
  998  */
  999 
 1000 void
 1001 bah_watchdog(ifp)
 1002         struct ifnet *ifp;
 1003 {
 1004         struct bah_softc *sc = ifp->if_softc;
 1005 
 1006         bus_space_tag_t bst_r = sc->sc_bst_r;
 1007         bus_space_handle_t regs = sc->sc_regs;
 1008 
 1009         PUTREG(BAHCMD, BAH_TXDIS);
 1010         return;
 1011 }
 1012 

Cache object: 8cc20598001b67c659d8f61eae876750


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