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

Cache object: 23ef1133e55353010136cbcc6b346a13


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