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

Cache object: 308aadfcd6c42eb16519d20bc261224a


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