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

Cache object: ce47eacfa11af5c80d3919306bfc1f2b


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