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/patm/if_patm_tx.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 /*-
    2  * Copyright (c) 2003
    3  *      Fraunhofer Institute for Open Communication Systems (FhG Fokus).
    4  *      All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * The TST allocation algorithm is from the IDT driver which is:
   28  *
   29  *      Copyright (c) 2000, 2001 Richard Hodges and Matriplex, inc.
   30  *      All rights reserved.
   31  *
   32  *      Copyright (c) 1996, 1997, 1998, 1999 Mark Tinguely
   33  *      All rights reserved.
   34  *
   35  * Author: Hartmut Brandt <harti@freebsd.org>
   36  *
   37  * Driver for IDT77252 based cards like ProSum's.
   38  */
   39 
   40 #include <sys/cdefs.h>
   41 __FBSDID("$FreeBSD: releng/6.0/sys/dev/patm/if_patm_tx.c 149443 2005-08-25 05:01:24Z rwatson $");
   42 
   43 #include "opt_inet.h"
   44 #include "opt_natm.h"
   45 
   46 #include <sys/types.h>
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/malloc.h>
   50 #include <sys/kernel.h>
   51 #include <sys/bus.h>
   52 #include <sys/errno.h>
   53 #include <sys/conf.h>
   54 #include <sys/module.h>
   55 #include <sys/lock.h>
   56 #include <sys/mutex.h>
   57 #include <sys/sysctl.h>
   58 #include <sys/queue.h>
   59 #include <sys/condvar.h>
   60 #include <sys/endian.h>
   61 #include <vm/uma.h>
   62 
   63 #include <sys/sockio.h>
   64 #include <sys/mbuf.h>
   65 #include <sys/socket.h>
   66 
   67 #include <net/if.h>
   68 #include <net/if_media.h>
   69 #include <net/if_atm.h>
   70 #include <net/route.h>
   71 #ifdef ENABLE_BPF
   72 #include <net/bpf.h>
   73 #endif
   74 #include <netinet/in.h>
   75 #include <netinet/if_atm.h>
   76 
   77 #include <machine/bus.h>
   78 #include <machine/resource.h>
   79 #include <sys/bus.h>
   80 #include <sys/rman.h>
   81 #include <sys/mbpool.h>
   82 
   83 #include <dev/utopia/utopia.h>
   84 #include <dev/patm/idt77252reg.h>
   85 #include <dev/patm/if_patmvar.h>
   86 
   87 static struct mbuf *patm_tx_pad(struct patm_softc *sc, struct mbuf *m0);
   88 static void patm_launch(struct patm_softc *sc, struct patm_scd *scd);
   89 
   90 static struct patm_txmap *patm_txmap_get(struct patm_softc *);
   91 static void patm_load_txbuf(void *, bus_dma_segment_t *, int,
   92     bus_size_t, int);
   93 
   94 static void patm_tst_alloc(struct patm_softc *sc, struct patm_vcc *vcc);
   95 static void patm_tst_free(struct patm_softc *sc, struct patm_vcc *vcc);
   96 static void patm_tst_timer(void *p);
   97 static void patm_tst_update(struct patm_softc *);
   98 
   99 static void patm_tct_start(struct patm_softc *sc, struct patm_vcc *);
  100 
  101 static const char *dump_scd(struct patm_softc *sc, struct patm_scd *scd)
  102     __unused;
  103 static void patm_tct_print(struct patm_softc *sc, u_int cid) __unused;
  104 
  105 /*
  106  * Structure for communication with the loader function for transmission
  107  */
  108 struct txarg {
  109         struct patm_softc *sc;
  110         struct patm_scd *scd;           /* scheduling channel */
  111         struct patm_vcc *vcc;           /* the VCC of this PDU */
  112         struct mbuf     *mbuf;
  113         u_int           hdr;            /* cell header */
  114 };
  115 
  116 static __inline u_int
  117 cbr2slots(struct patm_softc *sc, struct patm_vcc *vcc)
  118 {
  119         /* compute the number of slots we need, make sure to get at least
  120          * the specified PCR */
  121         return ((u_int)(((uint64_t)(sc->mmap->tst_size - 1) *
  122             vcc->vcc.tparam.pcr + IFP2IFATM(sc->ifp)->mib.pcr - 1) / IFP2IFATM(sc->ifp)->mib.pcr));
  123 }
  124 
  125 static __inline u_int
  126 slots2cr(struct patm_softc *sc, u_int slots)
  127 {
  128         return ((slots * IFP2IFATM(sc->ifp)->mib.pcr + sc->mmap->tst_size - 2) /
  129             (sc->mmap->tst_size - 1));
  130 }
  131 
  132 /* check if we can open this one */
  133 int
  134 patm_tx_vcc_can_open(struct patm_softc *sc, struct patm_vcc *vcc)
  135 {
  136 
  137         /* check resources */
  138         switch (vcc->vcc.traffic) {
  139 
  140           case ATMIO_TRAFFIC_CBR:
  141             {
  142                 u_int slots = cbr2slots(sc, vcc);
  143 
  144                 if (slots > sc->tst_free + sc->tst_reserve)
  145                         return (EINVAL);
  146                 break;
  147             }
  148 
  149           case ATMIO_TRAFFIC_VBR:
  150                 if (vcc->vcc.tparam.scr > sc->bwrem)
  151                         return (EINVAL);
  152                 if (vcc->vcc.tparam.pcr > IFP2IFATM(sc->ifp)->mib.pcr)
  153                         return (EINVAL);
  154                 if (vcc->vcc.tparam.scr > vcc->vcc.tparam.pcr ||
  155                     vcc->vcc.tparam.mbs == 0)
  156                         return (EINVAL);
  157                 break;
  158 
  159           case ATMIO_TRAFFIC_ABR:
  160                 if (vcc->vcc.tparam.tbe == 0 ||
  161                     vcc->vcc.tparam.nrm == 0)
  162                         /* needed to compute CRM */
  163                         return (EINVAL);
  164                 if (vcc->vcc.tparam.pcr > IFP2IFATM(sc->ifp)->mib.pcr ||
  165                     vcc->vcc.tparam.icr > vcc->vcc.tparam.pcr ||
  166                     vcc->vcc.tparam.mcr > vcc->vcc.tparam.icr)
  167                         return (EINVAL);
  168                 if (vcc->vcc.tparam.mcr > sc->bwrem ||
  169                     vcc->vcc.tparam.icr > sc->bwrem)
  170                         return (EINVAL);
  171                 break;
  172         }
  173 
  174         return (0);
  175 }
  176 
  177 #define NEXT_TAG(T) do {                                \
  178         (T) = ((T) + 1) % IDT_TSQE_TAG_SPACE;           \
  179     } while (0)
  180 
  181 /*
  182  * open it
  183  */
  184 void
  185 patm_tx_vcc_open(struct patm_softc *sc, struct patm_vcc *vcc)
  186 {
  187         struct patm_scd *scd;
  188 
  189         if (vcc->vcc.traffic == ATMIO_TRAFFIC_UBR) {
  190                 /* we use UBR0 */
  191                 vcc->scd = sc->scd0;
  192                 vcc->vflags |= PATM_VCC_TX_OPEN;
  193                 return;
  194         }
  195 
  196         /* get an SCD */
  197         scd = patm_scd_alloc(sc);
  198         if (scd == NULL) {
  199                 /* should not happen */
  200                 patm_printf(sc, "out of SCDs\n");
  201                 return;
  202         }
  203         vcc->scd = scd;
  204         patm_scd_setup(sc, scd);
  205         patm_tct_setup(sc, scd, vcc);
  206 
  207         if (vcc->vcc.traffic != ATMIO_TRAFFIC_CBR)
  208                 patm_tct_start(sc, vcc);
  209 
  210         vcc->vflags |= PATM_VCC_TX_OPEN;
  211 }
  212 
  213 /*
  214  * close the given vcc for transmission
  215  */
  216 void
  217 patm_tx_vcc_close(struct patm_softc *sc, struct patm_vcc *vcc)
  218 {
  219         struct patm_scd *scd;
  220         struct mbuf *m;
  221 
  222         vcc->vflags |= PATM_VCC_TX_CLOSING;
  223 
  224         if (vcc->vcc.traffic == ATMIO_TRAFFIC_UBR) {
  225                 /* let the queue PDUs go out */
  226                 vcc->scd = NULL;
  227                 vcc->vflags &= ~(PATM_VCC_TX_OPEN | PATM_VCC_TX_CLOSING);
  228                 return;
  229         }
  230         scd = vcc->scd;
  231 
  232         /* empty the waitq */
  233         for (;;) {
  234                 _IF_DEQUEUE(&scd->q, m);
  235                 if (m == NULL)
  236                         break;
  237                 m_freem(m);
  238         }
  239 
  240         if (scd->num_on_card == 0) {
  241                 /* we are idle */
  242                 vcc->vflags &= ~PATM_VCC_TX_OPEN;
  243 
  244                 if (vcc->vcc.traffic == ATMIO_TRAFFIC_CBR)
  245                         patm_tst_free(sc, vcc);
  246 
  247                 patm_sram_write4(sc, scd->sram + 0, 0, 0, 0, 0);
  248                 patm_sram_write4(sc, scd->sram + 4, 0, 0, 0, 0);
  249                 patm_scd_free(sc, scd);
  250 
  251                 vcc->scd = NULL;
  252                 vcc->vflags &= ~PATM_VCC_TX_CLOSING;
  253 
  254                 return;
  255         }
  256 
  257         /* speed up transmission */
  258         patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_UIER(vcc->cid, 0xff));
  259         patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_ULACR(vcc->cid, 0xff));
  260 
  261         /* wait for the interrupt to drop the number to 0 */
  262         patm_debug(sc, VCC, "%u buffers still on card", scd->num_on_card);
  263 }
  264 
  265 /* transmission side finally closed */
  266 void
  267 patm_tx_vcc_closed(struct patm_softc *sc, struct patm_vcc *vcc)
  268 {
  269 
  270         patm_debug(sc, VCC, "%u.%u TX closed", vcc->vcc.vpi, vcc->vcc.vci);
  271 
  272         if (vcc->vcc.traffic == ATMIO_TRAFFIC_VBR)
  273                 sc->bwrem += vcc->vcc.tparam.scr;
  274 }
  275 
  276 /*
  277  * Pull off packets from the interface queue and try to transmit them.
  278  * If the transmission fails because of a full transmit channel, we drop
  279  * packets for CBR and queue them for other channels up to limit.
  280  * This limit should depend on the CDVT for VBR and ABR, but it doesn't.
  281  */
  282 void
  283 patm_start(struct ifnet *ifp)
  284 {
  285         struct patm_softc *sc = ifp->if_softc;
  286         struct mbuf *m;
  287         struct atm_pseudohdr *aph;
  288         u_int vpi, vci, cid;
  289         struct patm_vcc *vcc;
  290 
  291         mtx_lock(&sc->mtx);
  292         if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
  293                 mtx_unlock(&sc->mtx);
  294                 return;
  295         }
  296 
  297         while (1) {
  298                 /* get a new mbuf */
  299                 IF_DEQUEUE(&ifp->if_snd, m);
  300                 if (m == NULL)
  301                         break;
  302 
  303                 /* split of pseudo header */
  304                 if (m->m_len < sizeof(*aph) &&
  305                     (m = m_pullup(m, sizeof(*aph))) == NULL) {
  306                         sc->ifp->if_oerrors++;
  307                         continue;
  308                 }
  309 
  310                 aph = mtod(m, struct atm_pseudohdr *);
  311                 vci = ATM_PH_VCI(aph);
  312                 vpi = ATM_PH_VPI(aph);
  313                 m_adj(m, sizeof(*aph));
  314 
  315                 /* reject empty packets */
  316                 if (m->m_pkthdr.len == 0) {
  317                         m_freem(m);
  318                         sc->ifp->if_oerrors++;
  319                         continue;
  320                 }
  321 
  322                 /* check whether this is a legal vcc */
  323                 if (!LEGAL_VPI(sc, vpi) || !LEGAL_VCI(sc, vci) || vci == 0) {
  324                         m_freem(m);
  325                         sc->ifp->if_oerrors++;
  326                         continue;
  327                 }
  328                 cid = PATM_CID(sc, vpi, vci);
  329                 vcc = sc->vccs[cid];
  330                 if (vcc == NULL) {
  331                         m_freem(m);
  332                         sc->ifp->if_oerrors++;
  333                         continue;
  334                 }
  335 
  336                 /* must be multiple of 48 if not AAL5 */
  337                 if (vcc->vcc.aal == ATMIO_AAL_0 ||
  338                     vcc->vcc.aal == ATMIO_AAL_34) {
  339                         /* XXX AAL3/4 format? */
  340                         if (m->m_pkthdr.len % 48 != 0 &&
  341                             (m = patm_tx_pad(sc, m)) == NULL) {
  342                                 sc->ifp->if_oerrors++;
  343                                 continue;
  344                         }
  345                 } else if (vcc->vcc.aal == ATMIO_AAL_RAW) {
  346                         switch (vcc->vflags & PATM_RAW_FORMAT) {
  347 
  348                           default:
  349                           case PATM_RAW_CELL:
  350                                 if (m->m_pkthdr.len != 53) {
  351                                         sc->ifp->if_oerrors++;
  352                                         m_freem(m);
  353                                         continue;
  354                                 }
  355                                 break;
  356 
  357                           case PATM_RAW_NOHEC:
  358                                 if (m->m_pkthdr.len != 52) {
  359                                         sc->ifp->if_oerrors++;
  360                                         m_freem(m);
  361                                         continue;
  362                                 }
  363                                 break;
  364 
  365                           case PATM_RAW_CS:
  366                                 if (m->m_pkthdr.len != 64) {
  367                                         sc->ifp->if_oerrors++;
  368                                         m_freem(m);
  369                                         continue;
  370                                 }
  371                                 break;
  372                         }
  373                 }
  374 
  375                 /* save data */
  376                 m->m_pkthdr.header = vcc;
  377 
  378                 /* try to put it on the channels queue */
  379                 if (_IF_QFULL(&vcc->scd->q)) {
  380                         sc->ifp->if_oerrors++;
  381                         sc->stats.tx_qfull++;
  382                         m_freem(m);
  383                         continue;
  384                 }
  385                 _IF_ENQUEUE(&vcc->scd->q, m);
  386 
  387 #ifdef ENABLE_BPF
  388                 if (!(vcc->vcc.flags & ATMIO_FLAG_NG) &&
  389                     (vcc->vcc.aal == ATMIO_AAL_5) &&
  390                     (vcc->vcc.flags & ATM_PH_LLCSNAP))
  391                         BPF_MTAP(ifp, m);
  392 #endif
  393 
  394                 /* kick the channel to life */
  395                 patm_launch(sc, vcc->scd);
  396 
  397         }
  398         mtx_unlock(&sc->mtx);
  399 }
  400 
  401 /*
  402  * Pad non-AAL5 packet to a multiple of 48-byte.
  403  * We assume AAL0 only. We have still to decide on the format of AAL3/4.
  404  */
  405 static struct mbuf *
  406 patm_tx_pad(struct patm_softc *sc, struct mbuf *m0)
  407 {
  408         struct mbuf *last, *m;
  409         u_int plen, pad, space;
  410 
  411         plen = m_length(m0, &last);
  412         if (plen != m0->m_pkthdr.len) {
  413                 patm_printf(sc, "%s: mbuf length mismatch %d %u\n", __func__,
  414                     m0->m_pkthdr.len, plen);
  415                 m0->m_pkthdr.len = plen;
  416                 if (plen == 0) {
  417                         m_freem(m0);
  418                         sc->ifp->if_oerrors++;
  419                         return (NULL);
  420                 }
  421                 if (plen % 48 == 0)
  422                         return (m0);
  423         }
  424         pad = 48 - plen % 48;
  425         m0->m_pkthdr.len += pad;
  426         if (M_WRITABLE(last)) {
  427                 if (M_TRAILINGSPACE(last) >= pad) {
  428                         bzero(last->m_data + last->m_len, pad);
  429                         last->m_len += pad;
  430                         return (m0);
  431                 }
  432                 space = M_LEADINGSPACE(last);
  433                 if (space + M_TRAILINGSPACE(last) >= pad) {
  434                         bcopy(last->m_data, last->m_data + space, last->m_len);
  435                         last->m_data -= space;
  436                         bzero(last->m_data + last->m_len, pad);
  437                         last->m_len += pad;
  438                         return (m0);
  439                 }
  440         }
  441         MGET(m, M_DONTWAIT, MT_DATA);
  442         if (m == 0) {
  443                 m_freem(m0);
  444                 sc->ifp->if_oerrors++;
  445                 return (NULL);
  446         }
  447         bzero(mtod(m, u_char *), pad);
  448         m->m_len = pad;
  449         last->m_next = m;
  450 
  451         return (m0);
  452 }
  453 
  454 /*
  455  * Try to put as many packets from the channels queue onto the channel
  456  */
  457 static void
  458 patm_launch(struct patm_softc *sc, struct patm_scd *scd)
  459 {
  460         struct txarg a;
  461         struct mbuf *m, *tmp;
  462         u_int segs;
  463         struct patm_txmap *map;
  464         int error;
  465 
  466         a.sc = sc;
  467         a.scd = scd;
  468 
  469         /* limit the number of outstanding packets to the tag space */
  470         while (scd->num_on_card < IDT_TSQE_TAG_SPACE) {
  471                 /* get the next packet */
  472                 _IF_DEQUEUE(&scd->q, m);
  473                 if (m == NULL)
  474                         break;
  475 
  476                 a.vcc = m->m_pkthdr.header;
  477 
  478                 /* we must know the number of segments beforehand - count
  479                  * this may actually give a wrong number of segments for
  480                  * AAL_RAW where we still need to remove the cell header */
  481                 segs = 0;
  482                 for (tmp = m; tmp != NULL; tmp = tmp->m_next)
  483                         if (tmp->m_len != 0)
  484                                 segs++;
  485 
  486                 /* check whether there is space in the queue */
  487                 if (segs >= scd->space) {
  488                         /* put back */
  489                         _IF_PREPEND(&scd->q, m);
  490                         sc->stats.tx_out_of_tbds++;
  491                         break;
  492                 }
  493 
  494                 /* get a DMA map */
  495                 if ((map = patm_txmap_get(sc)) == NULL) {
  496                         _IF_PREPEND(&scd->q, m);
  497                         sc->stats.tx_out_of_maps++;
  498                         break;
  499                 }
  500 
  501                 /* load the map */
  502                 m->m_pkthdr.header = map;
  503                 a.mbuf = m;
  504 
  505                 /* handle AAL_RAW */
  506                 if (a.vcc->vcc.aal == ATMIO_AAL_RAW) {
  507                         u_char hdr[4];
  508 
  509                         m_copydata(m, 0, 4, hdr);
  510                         a.hdr = (hdr[0] << 24) | (hdr[1] << 16) |
  511                             (hdr[2] << 8) | hdr[3];
  512 
  513                         switch (a.vcc->vflags & PATM_RAW_FORMAT) {
  514 
  515                           default:
  516                           case PATM_RAW_CELL:
  517                                 m_adj(m, 5);
  518                                 break;
  519 
  520                           case PATM_RAW_NOHEC:
  521                                 m_adj(m, 4);
  522                                 break;
  523 
  524                           case PATM_RAW_CS:
  525                                 m_adj(m, 16);
  526                                 break;
  527                         }
  528                 } else
  529                         a.hdr = IDT_TBD_HDR(a.vcc->vcc.vpi, a.vcc->vcc.vci,
  530                             0, 0);
  531 
  532                 error = bus_dmamap_load_mbuf(sc->tx_tag, map->map, m,
  533                     patm_load_txbuf, &a, BUS_DMA_NOWAIT);
  534                 if (error == EFBIG) {
  535                         if ((m = m_defrag(m, M_DONTWAIT)) == NULL) {
  536                                 sc->ifp->if_oerrors++;
  537                                 continue;
  538                         }
  539                         error = bus_dmamap_load_mbuf(sc->tx_tag, map->map, m,
  540                             patm_load_txbuf, &a, BUS_DMA_NOWAIT);
  541                 }
  542                 if (error != 0) {
  543                         sc->stats.tx_load_err++;
  544                         sc->ifp->if_oerrors++;
  545                         SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link);
  546                         m_freem(m);
  547                         continue;
  548                 }
  549 
  550                 sc->ifp->if_opackets++;
  551         }
  552 }
  553 
  554 /*
  555  * Load the DMA segments into the scheduling channel
  556  */
  557 static void
  558 patm_load_txbuf(void *uarg, bus_dma_segment_t *segs, int nseg,
  559     bus_size_t mapsize, int error)
  560 {
  561         struct txarg *a= uarg;
  562         struct patm_scd *scd = a->scd;
  563         u_int w1, w3, cnt;
  564         struct idt_tbd *tbd = NULL;
  565         u_int rest = mapsize;
  566 
  567         if (error != 0)
  568                 return;
  569 
  570         cnt = 0;
  571         while (nseg > 0) {
  572                 if (segs->ds_len == 0) {
  573                         /* transmit buffer length must be > 0 */
  574                         nseg--;
  575                         segs++;
  576                         continue;
  577                 }
  578                 /* rest after this buffer */
  579                 rest -= segs->ds_len;
  580 
  581                 /* put together status word */
  582                 w1 = 0;
  583                 if (rest < 48 /* && a->vcc->vcc.aal != ATMIO_AAL_5 */)
  584                         /* last cell is in this buffer */
  585                         w1 |= IDT_TBD_EPDU;
  586 
  587                 if (a->vcc->vcc.aal == ATMIO_AAL_5)
  588                         w1 |= IDT_TBD_AAL5;
  589                 else if (a->vcc->vcc.aal == ATMIO_AAL_34)
  590                         w1 |= IDT_TBD_AAL34;
  591                 else
  592                         w1 |= IDT_TBD_AAL0;
  593 
  594                 w1 |= segs->ds_len;
  595 
  596                 /* AAL5 PDU length (unpadded) */
  597                 if (a->vcc->vcc.aal == ATMIO_AAL_5)
  598                         w3 = mapsize;
  599                 else
  600                         w3 = 0;
  601 
  602                 if (rest == 0)
  603                         w1 |= IDT_TBD_TSIF | IDT_TBD_GTSI |
  604                             (scd->tag << IDT_TBD_TAG_SHIFT);
  605 
  606                 tbd = &scd->scq[scd->tail];
  607 
  608                 tbd->flags = htole32(w1);
  609                 tbd->addr = htole32(segs->ds_addr);
  610                 tbd->aal5 = htole32(w3);
  611                 tbd->hdr = htole32(a->hdr);
  612 
  613                 patm_debug(a->sc, TX, "TBD(%u): %08x %08x %08x %08x",
  614                     scd->tail, w1, segs->ds_addr, w3, a->hdr);
  615 
  616                 /* got to next entry */
  617                 if (++scd->tail == IDT_SCQ_SIZE)
  618                         scd->tail = 0;
  619                 cnt++;
  620                 nseg--;
  621                 segs++;
  622         }
  623         scd->space -= cnt;
  624         scd->num_on_card++;
  625 
  626         KASSERT(rest == 0, ("bad mbuf"));
  627         KASSERT(cnt > 0, ("no segs"));
  628         KASSERT(scd->space > 0, ("scq full"));
  629 
  630         KASSERT(scd->on_card[scd->tag] == NULL,
  631             ("scd on_card wedged %u%s", scd->tag, dump_scd(a->sc, scd)));
  632         scd->on_card[scd->tag] = a->mbuf;
  633         a->mbuf->m_pkthdr.csum_data = cnt;
  634 
  635         NEXT_TAG(scd->tag);
  636 
  637         patm_debug(a->sc, TX, "SCD tail %u (%lx:%lx)", scd->tail,
  638             (u_long)scd->phy, (u_long)scd->phy + (scd->tail << IDT_TBD_SHIFT));
  639         patm_sram_write(a->sc, scd->sram,
  640             scd->phy + (scd->tail << IDT_TBD_SHIFT));
  641 
  642         if (patm_sram_read(a->sc, a->vcc->cid * 8 + 3) & IDT_TCT_IDLE) {
  643                 /*
  644                  * if the connection is idle start it. We cannot rely
  645                  * on a flag set by patm_tx_idle() here, because sometimes
  646                  * the card seems to place an idle TSI into the TSQ but
  647                  * forgets to raise an interrupt.
  648                  */
  649                 patm_nor_write(a->sc, IDT_NOR_TCMDQ,
  650                     IDT_TCMDQ_START(a->vcc->cid));
  651         }
  652 }
  653 
  654 /*
  655  * packet transmitted
  656  */
  657 void
  658 patm_tx(struct patm_softc *sc, u_int stamp, u_int status)
  659 {
  660         u_int cid, tag, last;
  661         struct mbuf *m;
  662         struct patm_vcc *vcc;
  663         struct patm_scd *scd;
  664         struct patm_txmap *map;
  665 
  666         /* get the connection */
  667         cid = PATM_CID(sc, IDT_TBD_VPI(status), IDT_TBD_VCI(status));
  668         if ((vcc = sc->vccs[cid]) == NULL) {
  669                 /* closed UBR connection */
  670                 return;
  671         }
  672         scd = vcc->scd;
  673 
  674         tag = IDT_TSQE_TAG(stamp);
  675 
  676         last = scd->last_tag;
  677         if (tag == last) {
  678                 patm_printf(sc, "same tag %u\n", tag);
  679                 return;
  680         }
  681 
  682         /* Errata 12 requests us to free all entries up to the one
  683          * with the given tag. */
  684         do {
  685                 /* next tag to try */
  686                 NEXT_TAG(last);
  687 
  688                 m = scd->on_card[last];
  689                 KASSERT(m != NULL, ("%stag=%u", dump_scd(sc, scd), tag));
  690                 scd->on_card[last] = NULL;
  691                 patm_debug(sc, TX, "ok tag=%x", last);
  692 
  693                 map = m->m_pkthdr.header;
  694                 scd->space += m->m_pkthdr.csum_data;
  695 
  696                 bus_dmamap_sync(sc->tx_tag, map->map,
  697                     BUS_DMASYNC_POSTWRITE);
  698                 bus_dmamap_unload(sc->tx_tag, map->map);
  699                 m_freem(m);
  700                 SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link);
  701                 scd->num_on_card--;
  702 
  703                 if (vcc->vflags & PATM_VCC_TX_CLOSING) {
  704                         if (scd->num_on_card == 0) {
  705                                 /* done with this VCC */
  706                                 if (vcc->vcc.traffic == ATMIO_TRAFFIC_CBR)
  707                                         patm_tst_free(sc, vcc);
  708 
  709                                 patm_sram_write4(sc, scd->sram + 0, 0, 0, 0, 0);
  710                                 patm_sram_write4(sc, scd->sram + 4, 0, 0, 0, 0);
  711                                 patm_scd_free(sc, scd);
  712 
  713                                 vcc->scd = NULL;
  714                                 vcc->vflags &= ~PATM_VCC_TX_CLOSING;
  715 
  716                                 if (vcc->vcc.flags & ATMIO_FLAG_ASYNC) {
  717                                         patm_tx_vcc_closed(sc, vcc);
  718                                         if (!(vcc->vflags & PATM_VCC_OPEN))
  719                                                 patm_vcc_closed(sc, vcc);
  720                                 } else
  721                                         cv_signal(&sc->vcc_cv);
  722                                 return;
  723                         }
  724                         patm_debug(sc, VCC, "%u buffers still on card",
  725                             scd->num_on_card);
  726 
  727                         if (vcc->vcc.traffic == ATMIO_TRAFFIC_ABR) {
  728                                 /* insist on speeding up transmission for ABR */
  729                                 patm_nor_write(sc, IDT_NOR_TCMDQ,
  730                                     IDT_TCMDQ_UIER(vcc->cid, 0xff));
  731                                 patm_nor_write(sc, IDT_NOR_TCMDQ,
  732                                     IDT_TCMDQ_ULACR(vcc->cid, 0xff));
  733                         }
  734                 }
  735 
  736         } while (last != tag);
  737         scd->last_tag = tag;
  738 
  739         if (vcc->vcc.traffic == ATMIO_TRAFFIC_ABR) {
  740                 u_int acri, cps;
  741 
  742                 acri = (patm_sram_read(sc, 8 * cid + 2) >> IDT_TCT_ACRI_SHIFT)
  743                     & 0x3fff;
  744                 cps = IFP2IFATM(sc->ifp)->mib.pcr * 32 /
  745                     ((1 << (acri >> 10)) * (acri & 0x3ff));
  746 
  747                 if (cps != vcc->cps) {
  748                         patm_debug(sc, VCC, "ACRI=%04x CPS=%u", acri, cps);
  749                         ATMEV_SEND_ACR_CHANGED(IFP2IFATM(sc->ifp), vcc->vcc.vpi,
  750                             vcc->vcc.vci, cps);
  751                         vcc->cps = cps;
  752                 }
  753         }
  754 
  755         patm_launch(sc, scd);
  756 }
  757 
  758 /*
  759  * VBR/ABR connection went idle
  760  * Either restart it or set the idle flag.
  761  */
  762 void
  763 patm_tx_idle(struct patm_softc *sc, u_int cid)
  764 {
  765         struct patm_vcc *vcc;
  766 
  767         patm_debug(sc, VCC, "idle %u", cid);
  768 
  769         if ((vcc = sc->vccs[cid]) != NULL &&
  770             (vcc->vflags & (PATM_VCC_TX_OPEN | PATM_VCC_TX_CLOSING)) != 0 &&
  771             vcc->scd != NULL && (vcc->scd->num_on_card != 0 ||
  772             _IF_QLEN(&vcc->scd->q) != 0)) {
  773                 /*
  774                  * If there is any packet outstanding in the SCD re-activate
  775                  * the channel and kick it.
  776                  */
  777                 patm_nor_write(sc, IDT_NOR_TCMDQ,
  778                     IDT_TCMDQ_START(vcc->cid));
  779 
  780                 patm_launch(sc, vcc->scd);
  781         }
  782 }
  783 
  784 /*
  785  * Convert a (24bit) rate to the atm-forum form
  786  * Our rate is never larger than 19 bit.
  787  */
  788 static u_int
  789 cps2atmf(u_int cps)
  790 {
  791         u_int e;
  792 
  793         if (cps == 0)
  794                 return (0);
  795         cps <<= 9;
  796         e = 0;
  797         while (cps > (1024 - 1)) {
  798                 e++;
  799                 cps >>= 1;
  800         }
  801         return ((1 << 14) | (e << 9) | (cps & 0x1ff));
  802 }
  803 
  804 /*
  805  * Do a binary search on the log2rate table to convert the rate
  806  * to its log form. This assumes that the ATM-Forum form is monotonically
  807  * increasing with the plain cell rate.
  808  */
  809 static u_int
  810 rate2log(struct patm_softc *sc, u_int rate)
  811 {
  812         const uint32_t *tbl;
  813         u_int lower, upper, mid, done, val, afr;
  814 
  815         afr = cps2atmf(rate);
  816 
  817         if (sc->flags & PATM_25M)
  818                 tbl = patm_rtables25;
  819         else
  820                 tbl = patm_rtables155;
  821 
  822         lower = 0;
  823         upper = 255;
  824         done = 0;
  825         while (!done) {
  826                 mid = (lower + upper) / 2;
  827                 val = tbl[mid] >> 17;
  828                 if (val == afr || upper == lower)
  829                         break;
  830                 if (afr > val)
  831                         lower = mid + 1;
  832                 else
  833                         upper = mid - 1;
  834         }
  835         if (val > afr && mid > 0)
  836                 mid--;
  837         return (mid);
  838 }
  839 
  840 /*
  841  * Return the table index for an increase table. The increase table
  842  * must be selected not by the RIF itself, but by PCR/2^RIF. Each table
  843  * represents an additive increase of a cell rate that can be computed
  844  * from the first table entry (the value in this entry will not be clamped
  845  * by the link rate).
  846  */
  847 static u_int
  848 get_air_table(struct patm_softc *sc, u_int rif, u_int pcr)
  849 {
  850         const uint32_t *tbl;
  851         u_int increase, base, lair0, ret, t, cps;
  852 
  853 #define GET_ENTRY(TAB, IDX) (0xffff & ((IDX & 1) ?                      \
  854         (tbl[512 + (IDX / 2) + 128 * (TAB)] >> 16) :                    \
  855         (tbl[512 + (IDX / 2) + 128 * (TAB)])))
  856 
  857 #define MANT_BITS       10
  858 #define FRAC_BITS       16
  859 
  860 #define DIFF_TO_FP(D)   (((D) & ((1 << MANT_BITS) - 1)) << ((D) >> MANT_BITS))
  861 #define AFR_TO_INT(A)   ((1 << (((A) >> 9) & 0x1f)) * \
  862                             (512 + ((A) & 0x1ff)) / 512 * ((A) >> 14))
  863 
  864         if (sc->flags & PATM_25M)
  865                 tbl = patm_rtables25;
  866         else
  867                 tbl = patm_rtables155;
  868         if (rif >= patm_rtables_ntab)
  869                 rif = patm_rtables_ntab - 1;
  870         increase = pcr >> rif;
  871 
  872         ret = 0;
  873         for (t = 0; t < patm_rtables_ntab; t++) {
  874                 /* get base rate of this table */
  875                 base = GET_ENTRY(t, 0);
  876                 /* convert this to fixed point */
  877                 lair0 = DIFF_TO_FP(base) >> FRAC_BITS;
  878 
  879                 /* get the CPS from the log2rate table */
  880                 cps = AFR_TO_INT(tbl[lair0] >> 17) - 10;
  881 
  882                 if (increase >= cps)
  883                         break;
  884 
  885                 ret = t;
  886         }
  887         return (ret + 4);
  888 }
  889 
  890 /*
  891  * Setup the TCT
  892  */
  893 void
  894 patm_tct_setup(struct patm_softc *sc, struct patm_scd *scd,
  895     struct patm_vcc *vcc)
  896 {
  897         uint32_t tct[8];
  898         u_int sram;
  899         u_int mbs, token;
  900         u_int tmp, crm, rdf, cdf, air, mcr;
  901 
  902         bzero(tct, sizeof(tct));
  903         if (vcc == NULL) {
  904                 /* special case for UBR0 */
  905                 sram = 0;
  906                 tct[0] = IDT_TCT_UBR | scd->sram;
  907                 tct[7] = IDT_TCT_UBR_FLG;
  908 
  909         } else {
  910                 sram = vcc->cid * 8;
  911                 switch (vcc->vcc.traffic) {
  912 
  913                   case ATMIO_TRAFFIC_CBR:
  914                         patm_tst_alloc(sc, vcc);
  915                         tct[0] = IDT_TCT_CBR | scd->sram;
  916                         /* must account for what was really allocated */
  917                         break;
  918 
  919                   case ATMIO_TRAFFIC_VBR:
  920                         /* compute parameters for the TCT */
  921                         scd->init_er = rate2log(sc, vcc->vcc.tparam.pcr);
  922                         scd->lacr = rate2log(sc, vcc->vcc.tparam.scr);
  923 
  924                         /* get the 16-bit fraction of SCR/PCR
  925                          * both a 24 bit. Do it the simple way. */
  926                         token = (uint64_t)(vcc->vcc.tparam.scr << 16) /
  927                             vcc->vcc.tparam.pcr;
  928 
  929                         patm_debug(sc, VCC, "VBR: init_er=%u lacr=%u "
  930                             "token=0x%04x\n", scd->init_er, scd->lacr, token);
  931 
  932                         tct[0] = IDT_TCT_VBR | scd->sram;
  933                         tct[2] = IDT_TCT_TSIF;
  934                         tct[3] = IDT_TCT_IDLE | IDT_TCT_HALT;
  935                         tct[4] = IDT_TCT_MAXIDLE;
  936                         tct[5] = 0x01000000;
  937                         if ((mbs = vcc->vcc.tparam.mbs) > 0xff)
  938                                 mbs = 0xff;
  939                         tct[6] = (mbs << 16) | token;
  940                         sc->bwrem -= vcc->vcc.tparam.scr;
  941                         break;
  942 
  943                   case ATMIO_TRAFFIC_ABR:
  944                         scd->init_er = rate2log(sc, vcc->vcc.tparam.pcr);
  945                         scd->lacr = rate2log(sc, vcc->vcc.tparam.icr);
  946                         mcr = rate2log(sc, vcc->vcc.tparam.mcr);
  947 
  948                         /* compute CRM */
  949                         tmp = vcc->vcc.tparam.tbe / vcc->vcc.tparam.nrm;
  950                         if (tmp * vcc->vcc.tparam.nrm < vcc->vcc.tparam.tbe)
  951                                 tmp++;
  952                         for (crm = 1; tmp > (1 << crm); crm++)
  953                                 ;
  954                         if (crm > 0x7)
  955                                 crm = 7;
  956 
  957                         air = get_air_table(sc, vcc->vcc.tparam.rif,
  958                             vcc->vcc.tparam.pcr);
  959 
  960                         if ((rdf = vcc->vcc.tparam.rdf) >= patm_rtables_ntab)
  961                                 rdf = patm_rtables_ntab - 1;
  962                         rdf += patm_rtables_ntab + 4;
  963 
  964                         if ((cdf = vcc->vcc.tparam.cdf) >= patm_rtables_ntab)
  965                                 cdf = patm_rtables_ntab - 1;
  966                         cdf += patm_rtables_ntab + 4;
  967 
  968                         patm_debug(sc, VCC, "ABR: init_er=%u lacr=%u mcr=%u "
  969                             "crm=%u air=%u rdf=%u cdf=%u\n", scd->init_er,
  970                             scd->lacr, mcr, crm, air, rdf, cdf);
  971 
  972                         tct[0] = IDT_TCT_ABR | scd->sram;
  973                         tct[1] = crm << IDT_TCT_CRM_SHIFT;
  974                         tct[3] = IDT_TCT_HALT | IDT_TCT_IDLE |
  975                             (4 << IDT_TCT_NAGE_SHIFT);
  976                         tct[4] = mcr << IDT_TCT_LMCR_SHIFT;
  977                         tct[5] = (cdf << IDT_TCT_CDF_SHIFT) |
  978                             (rdf << IDT_TCT_RDF_SHIFT) |
  979                             (air << IDT_TCT_AIR_SHIFT);
  980 
  981                         sc->bwrem -= vcc->vcc.tparam.mcr;
  982                         break;
  983                 }
  984         }
  985 
  986         patm_sram_write4(sc, sram + 0, tct[0], tct[1], tct[2], tct[3]);
  987         patm_sram_write4(sc, sram + 4, tct[4], tct[5], tct[6], tct[7]);
  988 
  989         patm_debug(sc, VCC, "TCT[%u]: %08x %08x %08x %08x  %08x %08x %08x %08x",
  990             sram / 8, patm_sram_read(sc, sram + 0),
  991             patm_sram_read(sc, sram + 1), patm_sram_read(sc, sram + 2),
  992             patm_sram_read(sc, sram + 3), patm_sram_read(sc, sram + 4),
  993             patm_sram_read(sc, sram + 5), patm_sram_read(sc, sram + 6),
  994             patm_sram_read(sc, sram + 7));
  995 }
  996 
  997 /*
  998  * Start a channel
  999  */
 1000 static void
 1001 patm_tct_start(struct patm_softc *sc, struct patm_vcc *vcc)
 1002 {
 1003 
 1004         patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_UIER(vcc->cid,
 1005             vcc->scd->init_er));
 1006         patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_SLACR(vcc->cid,
 1007             vcc->scd->lacr));
 1008 }
 1009 
 1010 static void
 1011 patm_tct_print(struct patm_softc *sc, u_int cid)
 1012 {
 1013 #ifdef PATM_DEBUG
 1014         u_int sram = cid * 8;
 1015 #endif
 1016 
 1017         patm_debug(sc, VCC, "TCT[%u]: %08x %08x %08x %08x  %08x %08x %08x %08x",
 1018             sram / 8, patm_sram_read(sc, sram + 0),
 1019             patm_sram_read(sc, sram + 1), patm_sram_read(sc, sram + 2),
 1020             patm_sram_read(sc, sram + 3), patm_sram_read(sc, sram + 4),
 1021             patm_sram_read(sc, sram + 5), patm_sram_read(sc, sram + 6),
 1022             patm_sram_read(sc, sram + 7));
 1023 }
 1024 
 1025 /*
 1026  * Setup the SCD
 1027  */
 1028 void
 1029 patm_scd_setup(struct patm_softc *sc, struct patm_scd *scd)
 1030 {
 1031         patm_sram_write4(sc, scd->sram + 0,
 1032             scd->phy, 0, 0xffffffff, 0);
 1033         patm_sram_write4(sc, scd->sram + 4,
 1034             0, 0, 0, 0);
 1035 
 1036         patm_debug(sc, VCC, "SCD(%x): %08x %08x %08x %08x %08x %08x %08x %08x",
 1037             scd->sram,
 1038             patm_sram_read(sc, scd->sram + 0),
 1039             patm_sram_read(sc, scd->sram + 1),
 1040             patm_sram_read(sc, scd->sram + 2),
 1041             patm_sram_read(sc, scd->sram + 3),
 1042             patm_sram_read(sc, scd->sram + 4),
 1043             patm_sram_read(sc, scd->sram + 5),
 1044             patm_sram_read(sc, scd->sram + 6),
 1045             patm_sram_read(sc, scd->sram + 7));
 1046 }
 1047 
 1048 /*
 1049  * Grow the TX map table if possible
 1050  */
 1051 static void
 1052 patm_txmaps_grow(struct patm_softc *sc)
 1053 {
 1054         u_int i;
 1055         struct patm_txmap *map;
 1056         int err;
 1057 
 1058         if (sc->tx_nmaps >= sc->tx_maxmaps)
 1059                 return;
 1060 
 1061         for (i = sc->tx_nmaps; i < sc->tx_nmaps + PATM_CFG_TXMAPS_STEP; i++) {
 1062                 map = uma_zalloc(sc->tx_mapzone, M_NOWAIT);
 1063                 err = bus_dmamap_create(sc->tx_tag, 0, &map->map);
 1064                 if (err) {
 1065                         uma_zfree(sc->tx_mapzone, map);
 1066                         break;
 1067                 }
 1068                 SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link);
 1069         }
 1070 
 1071         sc->tx_nmaps = i;
 1072 }
 1073 
 1074 /*
 1075  * Allocate a transmission map
 1076  */
 1077 static struct patm_txmap *
 1078 patm_txmap_get(struct patm_softc *sc)
 1079 {
 1080         struct patm_txmap *map;
 1081 
 1082         if ((map = SLIST_FIRST(&sc->tx_maps_free)) == NULL) {
 1083                 patm_txmaps_grow(sc);
 1084                 if ((map = SLIST_FIRST(&sc->tx_maps_free)) == NULL)
 1085                         return (NULL);
 1086         }
 1087         SLIST_REMOVE_HEAD(&sc->tx_maps_free, link);
 1088         return (map);
 1089 }
 1090 
 1091 /*
 1092  * Look whether we are in the process of updating the TST on the chip.
 1093  * If we are set the flag that we need another update.
 1094  * If we are not start the update.
 1095  */
 1096 static __inline void
 1097 patm_tst_start(struct patm_softc *sc)
 1098 {
 1099 
 1100         if (!(sc->tst_state & TST_PENDING)) {
 1101                 sc->tst_state |= TST_PENDING;
 1102                 if (!(sc->tst_state & TST_WAIT)) {
 1103                         /* timer not running */
 1104                         patm_tst_update(sc);
 1105                 }
 1106         }
 1107 }
 1108 
 1109 /*
 1110  * Allocate TST entries to a CBR connection
 1111  */
 1112 static void
 1113 patm_tst_alloc(struct patm_softc *sc, struct patm_vcc *vcc)
 1114 {
 1115         u_int slots;
 1116         u_int qptr, pptr;
 1117         u_int qmax, pmax;
 1118         u_int pspc, last;
 1119 
 1120         mtx_lock(&sc->tst_lock);
 1121 
 1122         /* compute the number of slots we need, make sure to get at least
 1123          * the specified PCR */
 1124         slots = cbr2slots(sc, vcc);
 1125         vcc->scd->slots = slots;
 1126         sc->bwrem -= slots2cr(sc, slots);
 1127 
 1128         patm_debug(sc, TST, "tst_alloc: cbr=%u link=%u tst=%u slots=%u",
 1129             vcc->vcc.tparam.pcr, IFP2IFATM(sc->ifp)->mib.pcr, sc->mmap->tst_size, slots);
 1130 
 1131         qmax = sc->mmap->tst_size - 1;
 1132         pmax = qmax << 8;
 1133 
 1134         pspc = pmax / slots;
 1135 
 1136         pptr = pspc >> 1;       /* starting point */
 1137         qptr = pptr >> 8;
 1138 
 1139         last = qptr;
 1140 
 1141         while (slots > 0) {
 1142                 if (qptr >= qmax)
 1143                         qptr -= qmax;
 1144                 if (sc->tst_soft[qptr] != IDT_TST_VBR) {
 1145                         /* used - try next */
 1146                         qptr++;
 1147                         continue;
 1148                 }
 1149                 patm_debug(sc, TST, "slot[%u] = %u.%u diff=%d", qptr,
 1150                     vcc->vcc.vpi, vcc->vcc.vci, (int)qptr - (int)last);
 1151                 last = qptr;
 1152 
 1153                 sc->tst_soft[qptr] = IDT_TST_CBR | vcc->cid | TST_BOTH;
 1154                 sc->tst_free--;
 1155 
 1156                 if ((pptr += pspc) >= pmax)
 1157                         pptr -= pmax;
 1158                 qptr = pptr >> 8;
 1159 
 1160                 slots--;
 1161         }
 1162         patm_tst_start(sc);
 1163         mtx_unlock(&sc->tst_lock);
 1164 }
 1165 
 1166 /*
 1167  * Free a CBR connection's TST entries
 1168  */
 1169 static void
 1170 patm_tst_free(struct patm_softc *sc, struct patm_vcc *vcc)
 1171 {
 1172         u_int i;
 1173 
 1174         mtx_lock(&sc->tst_lock);
 1175         for (i = 0; i < sc->mmap->tst_size - 1; i++) {
 1176                 if ((sc->tst_soft[i] & IDT_TST_MASK) == vcc->cid) {
 1177                         sc->tst_soft[i] = IDT_TST_VBR | TST_BOTH;
 1178                         sc->tst_free++;
 1179                 }
 1180         }
 1181         sc->bwrem += slots2cr(sc, vcc->scd->slots);
 1182         patm_tst_start(sc);
 1183         mtx_unlock(&sc->tst_lock);
 1184 }
 1185 
 1186 /*
 1187  * Write the soft TST into the idle incore TST and start the wait timer.
 1188  * We assume that we hold the tst lock.
 1189  */
 1190 static void
 1191 patm_tst_update(struct patm_softc *sc)
 1192 {
 1193         u_int flag;             /* flag to clear from soft TST */
 1194         u_int idle;             /* the idle TST */
 1195         u_int act;              /* the active TST */
 1196         u_int i;
 1197 
 1198         if (sc->tst_state & TST_ACT1) {
 1199                 act = 1;
 1200                 idle = 0;
 1201                 flag = TST_CH0;
 1202         } else {
 1203                 act = 0;
 1204                 idle = 1;
 1205                 flag = TST_CH1;
 1206         }
 1207         /* update the idle one */
 1208         for (i = 0; i < sc->mmap->tst_size - 1; i++)
 1209                 if (sc->tst_soft[i] & flag) {
 1210                         patm_sram_write(sc, sc->tst_base[idle] + i,
 1211                             sc->tst_soft[i] & ~TST_BOTH);
 1212                         sc->tst_soft[i] &= ~flag;
 1213                 }
 1214         /* the used one jump to the idle one */
 1215         patm_sram_write(sc, sc->tst_jump[act],
 1216             IDT_TST_BR | (sc->tst_base[idle] << 2));
 1217 
 1218         /* wait for the chip to jump */
 1219         sc->tst_state &= ~TST_PENDING;
 1220         sc->tst_state |= TST_WAIT;
 1221 
 1222         callout_reset(&sc->tst_callout, 1, patm_tst_timer, sc);
 1223 }
 1224 
 1225 /*
 1226  * Timer for TST updates
 1227  */
 1228 static void
 1229 patm_tst_timer(void *p)
 1230 {
 1231         struct patm_softc *sc = p;
 1232         u_int act;      /* active TST */
 1233         u_int now;      /* current place in TST */
 1234 
 1235         mtx_lock(&sc->tst_lock);
 1236 
 1237         if (sc->tst_state & TST_WAIT) {
 1238                 /* ignore the PENDING state while we are waiting for
 1239                  * the chip to switch tables. Once the switch is done,
 1240                  * we will again lock at PENDING */
 1241                 act = (sc->tst_state & TST_ACT1) ? 1 : 0;
 1242                 now = patm_nor_read(sc, IDT_NOR_NOW) >> 2;
 1243                 if (now >= sc->tst_base[act] && now <= sc->tst_jump[act]) {
 1244                         /* not yet */
 1245                         callout_reset(&sc->tst_callout, 1, patm_tst_timer, sc);
 1246                         goto done;
 1247                 }
 1248                 sc->tst_state &= ~TST_WAIT;
 1249                 /* change back jump */
 1250                 patm_sram_write(sc, sc->tst_jump[act],
 1251                     IDT_TST_BR | (sc->tst_base[act] << 2));
 1252 
 1253                 /* switch */
 1254                 sc->tst_state ^= TST_ACT1;
 1255         }
 1256 
 1257         if (sc->tst_state & TST_PENDING)
 1258                 /* we got another update request while the timer was running. */
 1259                 patm_tst_update(sc);
 1260 
 1261   done:
 1262         mtx_unlock(&sc->tst_lock);
 1263 }
 1264 
 1265 static const char *
 1266 dump_scd(struct patm_softc *sc, struct patm_scd *scd)
 1267 {
 1268         u_int i;
 1269 
 1270         for (i = 0; i < IDT_TSQE_TAG_SPACE; i++)
 1271                 printf("on_card[%u] = %p\n", i, scd->on_card[i]);
 1272         printf("space=%u tag=%u num_on_card=%u last_tag=%u\n",
 1273             scd->space, scd->tag, scd->num_on_card, scd->last_tag);
 1274 
 1275         return ("");
 1276 }

Cache object: 8e3d6114761b2670e4fcfa751dc05aac


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