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/hatm/if_hatm_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) 2001-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  * Author: Hartmut Brandt <harti@freebsd.org>
   28  *
   29  * ForeHE driver.
   30  *
   31  * Transmission.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: releng/8.1/sys/dev/hatm/if_hatm_tx.c 148887 2005-08-09 10:20:02Z rwatson $");
   36 
   37 #include "opt_inet.h"
   38 #include "opt_natm.h"
   39 
   40 #include <sys/types.h>
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/kernel.h>
   44 #include <sys/malloc.h>
   45 #include <sys/bus.h>
   46 #include <sys/errno.h>
   47 #include <sys/conf.h>
   48 #include <sys/module.h>
   49 #include <sys/queue.h>
   50 #include <sys/syslog.h>
   51 #include <sys/condvar.h>
   52 #include <sys/sysctl.h>
   53 #include <vm/uma.h>
   54 
   55 #include <sys/sockio.h>
   56 #include <sys/mbuf.h>
   57 #include <sys/socket.h>
   58 
   59 #include <net/if.h>
   60 #include <net/if_media.h>
   61 #include <net/if_atm.h>
   62 #include <net/route.h>
   63 #ifdef ENABLE_BPF
   64 #include <net/bpf.h>
   65 #endif
   66 #include <netinet/in.h>
   67 #include <netinet/if_atm.h>
   68 
   69 #include <machine/bus.h>
   70 #include <machine/resource.h>
   71 #include <sys/bus.h>
   72 #include <sys/rman.h>
   73 #include <dev/pci/pcireg.h>
   74 #include <dev/pci/pcivar.h>
   75 
   76 #include <dev/utopia/utopia.h>
   77 #include <dev/hatm/if_hatmconf.h>
   78 #include <dev/hatm/if_hatmreg.h>
   79 #include <dev/hatm/if_hatmvar.h>
   80 
   81 
   82 /*
   83  * These macros are used to trace the flow of transmit mbufs and to
   84  * detect transmit mbuf leaks in the driver.
   85  */
   86 #ifdef HATM_DEBUG
   87 #define hatm_free_txmbuf(SC)                                            \
   88         do {                                                            \
   89                 if (--sc->txmbuf < 0)                                   \
   90                         DBG(sc, TX, ("txmbuf below 0!"));               \
   91                 else if (sc->txmbuf == 0)                               \
   92                         DBG(sc, TX, ("txmbuf now 0"));                  \
   93         } while (0)
   94 #define hatm_get_txmbuf(SC)                                             \
   95         do {                                                            \
   96                 if (++sc->txmbuf > 20000)                               \
   97                         DBG(sc, TX, ("txmbuf %u", sc->txmbuf));         \
   98                 else if (sc->txmbuf == 1)                               \
   99                         DBG(sc, TX, ("txmbuf leaves 0"));               \
  100         } while (0)
  101 #else
  102 #define hatm_free_txmbuf(SC)    do { } while (0)
  103 #define hatm_get_txmbuf(SC)     do { } while (0)
  104 #endif
  105 
  106 /*
  107  * Allocate a new TPD, zero the TPD part. Cannot return NULL if
  108  * flag is 0. The TPD is removed from the free list and its used
  109  * bit is set.
  110  */
  111 static struct tpd *
  112 hatm_alloc_tpd(struct hatm_softc *sc, u_int flags)
  113 {
  114         struct tpd *t;
  115 
  116         /* if we allocate a transmit TPD check for the reserve */
  117         if (flags & M_NOWAIT) {
  118                 if (sc->tpd_nfree <= HE_CONFIG_TPD_RESERVE)
  119                         return (NULL);
  120         } else {
  121                 if (sc->tpd_nfree == 0)
  122                         return (NULL);
  123         }
  124 
  125         /* make it beeing used */
  126         t = SLIST_FIRST(&sc->tpd_free);
  127         KASSERT(t != NULL, ("tpd botch"));
  128         SLIST_REMOVE_HEAD(&sc->tpd_free, link);
  129         TPD_SET_USED(sc, t->no);
  130         sc->tpd_nfree--;
  131 
  132         /* initialize */
  133         t->mbuf = NULL;
  134         t->cid = 0;
  135         bzero(&t->tpd, sizeof(t->tpd));
  136         t->tpd.addr = t->no << HE_REGS_TPD_ADDR;
  137 
  138         return (t);
  139 }
  140 
  141 /*
  142  * Free a TPD. If the mbuf pointer in that TPD is not zero, it is assumed, that
  143  * the DMA map of this TPD was used to load this mbuf. The map is unloaded
  144  * and the mbuf is freed. The TPD is put back onto the free list and
  145  * its used bit is cleared.
  146  */
  147 static void
  148 hatm_free_tpd(struct hatm_softc *sc, struct tpd *tpd)
  149 {
  150         if (tpd->mbuf != NULL) {
  151                 bus_dmamap_unload(sc->tx_tag, tpd->map);
  152                 hatm_free_txmbuf(sc);
  153                 m_freem(tpd->mbuf);
  154                 tpd->mbuf = NULL;
  155         }
  156 
  157         /* insert TPD into free list */
  158         SLIST_INSERT_HEAD(&sc->tpd_free, tpd, link);
  159         TPD_CLR_USED(sc, tpd->no);
  160         sc->tpd_nfree++;
  161 }
  162 
  163 /*
  164  * Queue a number of TPD. If there is not enough space none of the TPDs
  165  * is queued and an error code is returned.
  166  */
  167 static int
  168 hatm_queue_tpds(struct hatm_softc *sc, u_int count, struct tpd **list,
  169     u_int cid)
  170 {
  171         u_int space;
  172         u_int i;
  173 
  174         if (count >= sc->tpdrq.size) {
  175                 sc->istats.tdprq_full++;
  176                 return (EBUSY);
  177         }
  178 
  179         if (sc->tpdrq.tail < sc->tpdrq.head)
  180                 space = sc->tpdrq.head - sc->tpdrq.tail;
  181         else
  182                 space = sc->tpdrq.head - sc->tpdrq.tail +  sc->tpdrq.size;
  183 
  184         if (space <= count) {
  185                 sc->tpdrq.head =
  186                     (READ4(sc, HE_REGO_TPDRQ_H) >> HE_REGS_TPDRQ_H_H) &
  187                     (sc->tpdrq.size - 1);
  188 
  189                 if (sc->tpdrq.tail < sc->tpdrq.head)
  190                         space = sc->tpdrq.head - sc->tpdrq.tail;
  191                 else
  192                         space = sc->tpdrq.head - sc->tpdrq.tail +
  193                             sc->tpdrq.size;
  194 
  195                 if (space <= count) {
  196                         if_printf(sc->ifp, "TPDRQ full\n");
  197                         sc->istats.tdprq_full++;
  198                         return (EBUSY);
  199                 }
  200         }
  201 
  202         /* we are going to write to the TPD queue space */
  203         bus_dmamap_sync(sc->tpdrq.mem.tag, sc->tpdrq.mem.map,
  204             BUS_DMASYNC_PREWRITE);
  205 
  206         /* put the entries into the TPD space */
  207         for (i = 0; i < count; i++) {
  208                 /* we are going to 'write' the TPD to the device */
  209                 bus_dmamap_sync(sc->tpds.tag, sc->tpds.map,
  210                     BUS_DMASYNC_PREWRITE);
  211 
  212                 sc->tpdrq.tpdrq[sc->tpdrq.tail].tpd =
  213                     sc->tpds.paddr + HE_TPD_SIZE * list[i]->no;
  214                 sc->tpdrq.tpdrq[sc->tpdrq.tail].cid = cid;
  215 
  216                 if (++sc->tpdrq.tail == sc->tpdrq.size)
  217                         sc->tpdrq.tail = 0;
  218         }
  219 
  220         /* update tail pointer */
  221         WRITE4(sc, HE_REGO_TPDRQ_T, (sc->tpdrq.tail << HE_REGS_TPDRQ_T_T));
  222 
  223         return (0);
  224 }
  225 
  226 /*
  227  * Helper struct for communication with the DMA load helper.
  228  */
  229 struct load_txbuf_arg {
  230         struct hatm_softc *sc;
  231         struct tpd *first;
  232         struct mbuf *mbuf;
  233         struct hevcc *vcc;
  234         int error;
  235         u_int pti;
  236         u_int vpi, vci;
  237 };
  238 
  239 /*
  240  * Loader callback for the mbuf. This function allocates the TPDs and
  241  * fills them. It puts the dmamap and and the mbuf pointer into the last
  242  * TPD and then tries to queue all the TPDs. If anything fails, all TPDs
  243  * allocated by this function are freed and the error flag is set in the
  244  * argument structure. The first TPD must then be freed by the caller.
  245  */
  246 static void
  247 hatm_load_txbuf(void *uarg, bus_dma_segment_t *segs, int nseg,
  248     bus_size_t mapsize, int error)
  249 {
  250         struct load_txbuf_arg *arg = uarg;
  251         u_int tpds_needed, i, n, tpd_cnt;
  252         int need_intr;
  253         struct tpd *tpd;
  254         struct tpd *tpd_list[HE_CONFIG_MAX_TPD_PER_PACKET];
  255 
  256         if (error != 0) {
  257                 DBG(arg->sc, DMA, ("%s -- error=%d plen=%d\n",
  258                     __func__, error, arg->mbuf->m_pkthdr.len));
  259                 return;
  260         }
  261 
  262         /* ensure, we have enough TPDs (remember, we already have one) */
  263         tpds_needed = (nseg + 2) / 3;
  264         if (HE_CONFIG_TPD_RESERVE + tpds_needed - 1 > arg->sc->tpd_nfree) {
  265                 if_printf(arg->sc->ifp, "%s -- out of TPDs (need %d, "
  266                     "have %u)\n", __func__, tpds_needed - 1,
  267                     arg->sc->tpd_nfree + 1);
  268                 arg->error = 1;
  269                 return;
  270         }
  271 
  272         /*
  273          * Check for the maximum number of TPDs on the connection.
  274          */
  275         need_intr = 0;
  276         if (arg->sc->max_tpd > 0) {
  277                 if (arg->vcc->ntpds + tpds_needed > arg->sc->max_tpd) {
  278                         arg->sc->istats.flow_closed++;
  279                         arg->vcc->vflags |= HE_VCC_FLOW_CTRL;
  280                         ATMEV_SEND_FLOW_CONTROL(IFP2IFATM(arg->sc->ifp),
  281                             arg->vpi, arg->vci, 1);
  282                         arg->error = 1;
  283                         return;
  284                 }
  285                 if (arg->vcc->ntpds + tpds_needed >
  286                     (9 * arg->sc->max_tpd) / 10)
  287                         need_intr = 1;
  288         }
  289 
  290         tpd = arg->first;
  291         tpd_cnt = 0;
  292         tpd_list[tpd_cnt++] = tpd;
  293         for (i = n = 0; i < nseg; i++, n++) {
  294                 if (n == 3) {
  295                         if ((tpd = hatm_alloc_tpd(arg->sc, M_NOWAIT)) == NULL)
  296                                 /* may not fail (see check above) */
  297                                 panic("%s: out of TPDs", __func__);
  298                         tpd->cid = arg->first->cid;
  299                         tpd->tpd.addr |= arg->pti;
  300                         tpd_list[tpd_cnt++] = tpd;
  301                         n = 0;
  302                 }
  303                 KASSERT(segs[i].ds_addr <= 0xffffffffLU,
  304                     ("phys addr too large %lx", (u_long)segs[i].ds_addr));
  305 
  306                 DBG(arg->sc, DMA, ("DMA loaded: %lx/%lu",
  307                     (u_long)segs[i].ds_addr, (u_long)segs[i].ds_len));
  308 
  309                 tpd->tpd.bufs[n].addr = segs[i].ds_addr;
  310                 tpd->tpd.bufs[n].len = segs[i].ds_len;
  311 
  312                 DBG(arg->sc, TX, ("seg[%u]=tpd[%u,%u]=%x/%u", i,
  313                     tpd_cnt, n, tpd->tpd.bufs[n].addr, tpd->tpd.bufs[n].len));
  314 
  315                 if (i == nseg - 1)
  316                         tpd->tpd.bufs[n].len |= HE_REGM_TPD_LST;
  317         }
  318 
  319         /*
  320          * Swap the MAP in the first and the last TPD and set the mbuf
  321          * pointer into the last TPD. We use the map in the last TPD, because
  322          * the map must stay valid until the last TPD is processed by the card.
  323          */
  324         if (tpd_cnt > 1) {
  325                 bus_dmamap_t tmp;
  326 
  327                 tmp = arg->first->map;
  328                 arg->first->map = tpd_list[tpd_cnt - 1]->map;
  329                 tpd_list[tpd_cnt - 1]->map = tmp;
  330         }
  331         tpd_list[tpd_cnt - 1]->mbuf = arg->mbuf;
  332 
  333         if (need_intr)
  334                 tpd_list[tpd_cnt - 1]->tpd.addr |= HE_REGM_TPD_INTR;
  335 
  336         /* queue the TPDs */
  337         if (hatm_queue_tpds(arg->sc, tpd_cnt, tpd_list, arg->first->cid)) {
  338                 /* free all, except the first TPD */
  339                 for (i = 1; i < tpd_cnt; i++)
  340                         hatm_free_tpd(arg->sc, tpd_list[i]);
  341                 arg->error = 1;
  342                 return;
  343         }
  344         arg->vcc->ntpds += tpd_cnt;
  345 }
  346 
  347 
  348 /*
  349  * Start output on the interface
  350  */
  351 void
  352 hatm_start(struct ifnet *ifp)
  353 {
  354         struct hatm_softc *sc = ifp->if_softc;
  355         struct mbuf *m;
  356         struct atm_pseudohdr *aph;
  357         u_int cid;
  358         struct tpd *tpd;
  359         struct load_txbuf_arg arg;
  360         u_int len;
  361         int error;
  362 
  363         if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
  364                 return;
  365         mtx_lock(&sc->mtx);
  366         arg.sc = sc;
  367 
  368         while (1) {
  369                 IF_DEQUEUE(&ifp->if_snd, m);
  370                 if (m == NULL)
  371                         break;
  372 
  373                 hatm_get_txmbuf(sc);
  374 
  375                 if (m->m_len < sizeof(*aph))
  376                         if ((m = m_pullup(m, sizeof(*aph))) == NULL) {
  377                                 hatm_free_txmbuf(sc);
  378                                 continue;
  379                         }
  380 
  381                 aph = mtod(m, struct atm_pseudohdr *);
  382                 arg.vci = ATM_PH_VCI(aph);
  383                 arg.vpi = ATM_PH_VPI(aph);
  384                 m_adj(m, sizeof(*aph));
  385 
  386                 if ((len = m->m_pkthdr.len) == 0) {
  387                         hatm_free_txmbuf(sc);
  388                         m_freem(m);
  389                         continue;
  390                 }
  391 
  392                 if ((arg.vpi & ~HE_VPI_MASK) || (arg.vci & ~HE_VCI_MASK) ||
  393                     (arg.vci == 0)) {
  394                         hatm_free_txmbuf(sc);
  395                         m_freem(m);
  396                         continue;
  397                 }
  398                 cid = HE_CID(arg.vpi, arg.vci);
  399                 arg.vcc = sc->vccs[cid];
  400 
  401                 if (arg.vcc == NULL || !(arg.vcc->vflags & HE_VCC_OPEN)) {
  402                         hatm_free_txmbuf(sc);
  403                         m_freem(m);
  404                         continue;
  405                 }
  406                 if (arg.vcc->vflags & HE_VCC_FLOW_CTRL) {
  407                         hatm_free_txmbuf(sc);
  408                         m_freem(m);
  409                         sc->istats.flow_drop++;
  410                         continue;
  411                 }
  412 
  413                 arg.pti = 0;
  414                 if (arg.vcc->param.aal == ATMIO_AAL_RAW) {
  415                         if (len < 52) {
  416                                 /* too short */
  417                                 hatm_free_txmbuf(sc);
  418                                 m_freem(m);
  419                                 continue;
  420                         }
  421 
  422                         /*
  423                          * Get the header and ignore except
  424                          * payload type and CLP.
  425                          */
  426                         if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) {
  427                                 hatm_free_txmbuf(sc);
  428                                 continue;
  429                         }
  430                         arg.pti = mtod(m, u_char *)[3] & 0xf;
  431                         arg.pti = ((arg.pti & 0xe) << 2) | ((arg.pti & 1) << 1);
  432                         m_adj(m, 4);
  433                         len -= 4;
  434 
  435                         if (len % 48 != 0) {
  436                                 m_adj(m, -((int)(len % 48)));
  437                                 len -= len % 48;
  438                         }
  439                 }
  440 
  441 #ifdef ENABLE_BPF
  442                 if (!(arg.vcc->param.flags & ATMIO_FLAG_NG) &&
  443                     (arg.vcc->param.aal == ATMIO_AAL_5) &&
  444                     (arg.vcc->param.flags & ATM_PH_LLCSNAP))
  445                         BPF_MTAP(ifp, m);
  446 #endif
  447 
  448                 /* Now load a DMA map with the packet. Allocate the first
  449                  * TPD to get a map. Additional TPDs may be allocated by the
  450                  * callback. */
  451                 if ((tpd = hatm_alloc_tpd(sc, M_NOWAIT)) == NULL) {
  452                         hatm_free_txmbuf(sc);
  453                         m_freem(m);
  454                         sc->ifp->if_oerrors++;
  455                         continue;
  456                 }
  457                 tpd->cid = cid;
  458                 tpd->tpd.addr |= arg.pti;
  459                 arg.first = tpd;
  460                 arg.error = 0;
  461                 arg.mbuf = m;
  462 
  463                 error = bus_dmamap_load_mbuf(sc->tx_tag, tpd->map, m,
  464                     hatm_load_txbuf, &arg, BUS_DMA_NOWAIT);
  465 
  466                 if (error == EFBIG) {
  467                         /* try to defragment the packet */
  468                         sc->istats.defrag++;
  469                         m = m_defrag(m, M_DONTWAIT);
  470                         if (m == NULL) {
  471                                 tpd->mbuf = NULL;
  472                                 hatm_free_txmbuf(sc);
  473                                 hatm_free_tpd(sc, tpd);
  474                                 sc->ifp->if_oerrors++;
  475                                 continue;
  476                         }
  477                         arg.mbuf = m;
  478                         error = bus_dmamap_load_mbuf(sc->tx_tag, tpd->map, m,
  479                             hatm_load_txbuf, &arg, BUS_DMA_NOWAIT);
  480                 }
  481 
  482                 if (error != 0) {
  483                         if_printf(sc->ifp, "mbuf loaded error=%d\n",
  484                             error);
  485                         hatm_free_tpd(sc, tpd);
  486                         sc->ifp->if_oerrors++;
  487                         continue;
  488                 }
  489                 if (arg.error) {
  490                         hatm_free_tpd(sc, tpd);
  491                         sc->ifp->if_oerrors++;
  492                         continue;
  493                 }
  494                 arg.vcc->opackets++;
  495                 arg.vcc->obytes += len;
  496                 sc->ifp->if_opackets++;
  497         }
  498         mtx_unlock(&sc->mtx);
  499 }
  500 
  501 void
  502 hatm_tx_complete(struct hatm_softc *sc, struct tpd *tpd, uint32_t flags)
  503 {
  504         struct hevcc *vcc = sc->vccs[tpd->cid];
  505 
  506         DBG(sc, TX, ("tx_complete cid=%#x flags=%#x", tpd->cid, flags));
  507 
  508         if (vcc == NULL)
  509                 return;
  510         if ((flags & HE_REGM_TBRQ_EOS) && (vcc->vflags & HE_VCC_TX_CLOSING)) {
  511                 vcc->vflags &= ~HE_VCC_TX_CLOSING;
  512                 if (vcc->param.flags & ATMIO_FLAG_ASYNC) {
  513                         hatm_tx_vcc_closed(sc, tpd->cid);
  514                         if (!(vcc->vflags & HE_VCC_OPEN)) {
  515                                 hatm_vcc_closed(sc, tpd->cid);
  516                                 vcc = NULL;
  517                         }
  518                 } else
  519                         cv_signal(&sc->vcc_cv);
  520         }
  521         hatm_free_tpd(sc, tpd);
  522 
  523         if (vcc == NULL)
  524                 return;
  525 
  526         vcc->ntpds--;
  527 
  528         if ((vcc->vflags & HE_VCC_FLOW_CTRL) &&
  529             vcc->ntpds <= HE_CONFIG_TPD_FLOW_ENB) {
  530                 vcc->vflags &= ~HE_VCC_FLOW_CTRL;
  531                 ATMEV_SEND_FLOW_CONTROL(IFP2IFATM(sc->ifp),
  532                     HE_VPI(tpd->cid), HE_VCI(tpd->cid), 0);
  533         }
  534 }
  535 
  536 /*
  537  * Convert CPS to Rate for a rate group
  538  */
  539 static u_int
  540 cps_to_rate(struct hatm_softc *sc, uint32_t cps)
  541 {
  542         u_int clk = sc->he622 ? HE_622_CLOCK : HE_155_CLOCK;
  543         u_int period, rate;
  544 
  545         /* how many double ticks between two cells */
  546         period = (clk + 2 * cps - 1) / (2 * cps);
  547         rate = hatm_cps2atmf(period);
  548         if (hatm_atmf2cps(rate) < period)
  549                 rate++;
  550 
  551         return (rate);
  552 }
  553 
  554 /*
  555  * Check whether the VCC is really closed on the hardware and available for
  556  * open. Check that we have enough resources. If this function returns ok,
  557  * a later actual open must succeed. Assume, that we are locked between this
  558  * function and the next one, so that nothing does change. For CBR this
  559  * assigns the rate group and set the rate group's parameter.
  560  */
  561 int
  562 hatm_tx_vcc_can_open(struct hatm_softc *sc, u_int cid, struct hevcc *vcc)
  563 {
  564         uint32_t v, line_rate;
  565         u_int rc, idx, free_idx;
  566         struct atmio_tparam *t = &vcc->param.tparam;
  567 
  568         /* verify that connection is closed */
  569 #if 0
  570         v = READ_TSR(sc, cid, 4);
  571         if(!(v & HE_REGM_TSR4_SESS_END)) {
  572                 if_printf(sc->ifp, "cid=%#x not closed (TSR4)\n", cid);
  573                 return (EBUSY);
  574         }
  575 #endif
  576         v = READ_TSR(sc, cid, 0);
  577         if((v & HE_REGM_TSR0_CONN_STATE) != 0) {
  578                 if_printf(sc->ifp, "cid=%#x not closed (TSR0=%#x)\n",
  579                     cid, v);
  580                 return (EBUSY);
  581         }
  582 
  583         /* check traffic parameters */
  584         line_rate = sc->he622 ? ATM_RATE_622M : ATM_RATE_155M;
  585         switch (vcc->param.traffic) {
  586 
  587           case ATMIO_TRAFFIC_UBR:
  588                 if (t->pcr == 0 || t->pcr > line_rate)
  589                         t->pcr = line_rate;
  590                 if (t->mcr != 0 || t->icr != 0 || t->tbe != 0 || t->nrm != 0 ||
  591                     t->trm != 0 || t->adtf != 0 || t->rif != 0 || t->rdf != 0 ||
  592                     t->cdf != 0)
  593                         return (EINVAL);
  594                 break;
  595 
  596           case ATMIO_TRAFFIC_CBR:
  597                 /*
  598                  * Compute rate group index
  599                  */
  600                 if (t->pcr < 10)
  601                         t->pcr = 10;
  602                 if (sc->cbr_bw + t->pcr > line_rate)
  603                         return (EINVAL);
  604                 if (t->mcr != 0 || t->icr != 0 || t->tbe != 0 || t->nrm != 0 ||
  605                     t->trm != 0 || t->adtf != 0 || t->rif != 0 || t->rdf != 0 ||
  606                     t->cdf != 0)
  607                         return (EINVAL);
  608 
  609                 rc = cps_to_rate(sc, t->pcr);
  610                 free_idx = HE_REGN_CS_STPER;
  611                 for (idx = 0; idx < HE_REGN_CS_STPER; idx++) {
  612                         if (sc->rate_ctrl[idx].refcnt == 0) {
  613                                 if (free_idx == HE_REGN_CS_STPER)
  614                                         free_idx = idx;
  615                         } else {
  616                                 if (sc->rate_ctrl[idx].rate == rc)
  617                                         break;
  618                         }
  619                 }
  620                 if (idx == HE_REGN_CS_STPER) {
  621                         if ((idx = free_idx) == HE_REGN_CS_STPER)
  622                                 return (EBUSY);
  623                         sc->rate_ctrl[idx].rate = rc;
  624                 }
  625                 vcc->rc = idx;
  626 
  627                 /* commit */
  628                 sc->rate_ctrl[idx].refcnt++;
  629                 sc->cbr_bw += t->pcr;
  630                 break;
  631 
  632           case ATMIO_TRAFFIC_ABR:
  633                 if (t->pcr > line_rate)
  634                         t->pcr = line_rate;
  635                 if (t->mcr > line_rate)
  636                         t->mcr = line_rate;
  637                 if (t->icr > line_rate)
  638                         t->icr = line_rate;
  639                 if (t->tbe == 0 || t->tbe >= 1 << 24 || t->nrm > 7 ||
  640                     t->trm > 7 || t->adtf >= 1 << 10 || t->rif > 15 ||
  641                     t->rdf > 15 || t->cdf > 7)
  642                         return (EINVAL);
  643                 break;
  644 
  645           default:
  646                 return (EINVAL);
  647         }
  648         return (0);
  649 }
  650 
  651 #define NRM_CODE2VAL(CODE) (2 * (1 << (CODE)))
  652 
  653 /*
  654  * Actually open the transmit VCC
  655  */
  656 void
  657 hatm_tx_vcc_open(struct hatm_softc *sc, u_int cid)
  658 {
  659         struct hevcc *vcc = sc->vccs[cid];
  660         uint32_t tsr0, tsr4, atmf, crm;
  661         const struct atmio_tparam *t = &vcc->param.tparam;
  662 
  663         if (vcc->param.aal == ATMIO_AAL_5) {
  664                 tsr0 = HE_REGM_TSR0_AAL_5 << HE_REGS_TSR0_AAL;
  665                 tsr4 = HE_REGM_TSR4_AAL_5 << HE_REGS_TSR4_AAL;
  666         } else {
  667                 tsr0 = HE_REGM_TSR0_AAL_0 << HE_REGS_TSR0_AAL;
  668                 tsr4 = HE_REGM_TSR4_AAL_0 << HE_REGS_TSR4_AAL;
  669         }
  670         tsr4 |= 1;
  671 
  672         switch (vcc->param.traffic) {
  673 
  674           case ATMIO_TRAFFIC_UBR:
  675                 atmf = hatm_cps2atmf(t->pcr);
  676 
  677                 tsr0 |= HE_REGM_TSR0_TRAFFIC_UBR << HE_REGS_TSR0_TRAFFIC;
  678                 tsr0 |= HE_REGM_TSR0_USE_WMIN | HE_REGM_TSR0_UPDATE_GER;
  679 
  680                 WRITE_TSR(sc, cid, 0, 0xf, tsr0);
  681                 WRITE_TSR(sc, cid, 4, 0xf, tsr4);
  682                 WRITE_TSR(sc, cid, 1, 0xf, (atmf << HE_REGS_TSR1_PCR));
  683                 WRITE_TSR(sc, cid, 2, 0xf, (atmf << HE_REGS_TSR2_ACR));
  684                 WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT);
  685                 WRITE_TSR(sc, cid, 3, 0xf, 0);
  686                 WRITE_TSR(sc, cid, 5, 0xf, 0);
  687                 WRITE_TSR(sc, cid, 6, 0xf, 0);
  688                 WRITE_TSR(sc, cid, 7, 0xf, 0);
  689                 WRITE_TSR(sc, cid, 8, 0xf, 0);
  690                 WRITE_TSR(sc, cid, 10, 0xf, 0);
  691                 WRITE_TSR(sc, cid, 11, 0xf, 0);
  692                 WRITE_TSR(sc, cid, 12, 0xf, 0);
  693                 WRITE_TSR(sc, cid, 13, 0xf, 0);
  694                 WRITE_TSR(sc, cid, 14, 0xf, 0);
  695                 break;
  696 
  697           case ATMIO_TRAFFIC_CBR:
  698                 atmf = hatm_cps2atmf(t->pcr);
  699 
  700                 if (sc->rate_ctrl[vcc->rc].refcnt == 1)
  701                         WRITE_MBOX4(sc, HE_REGO_CS_STPER(vcc->rc),
  702                             sc->rate_ctrl[vcc->rc].rate);
  703 
  704                 tsr0 |= HE_REGM_TSR0_TRAFFIC_CBR << HE_REGS_TSR0_TRAFFIC;
  705                 tsr0 |= vcc->rc;
  706 
  707                 WRITE_TSR(sc, cid, 1, 0xf, (atmf << HE_REGS_TSR1_PCR));
  708                 WRITE_TSR(sc, cid, 2, 0xf, (atmf << HE_REGS_TSR2_ACR));
  709                 WRITE_TSR(sc, cid, 3, 0xf, 0);
  710                 WRITE_TSR(sc, cid, 5, 0xf, 0);
  711                 WRITE_TSR(sc, cid, 6, 0xf, 0);
  712                 WRITE_TSR(sc, cid, 7, 0xf, 0);
  713                 WRITE_TSR(sc, cid, 8, 0xf, 0);
  714                 WRITE_TSR(sc, cid, 10, 0xf, 0);
  715                 WRITE_TSR(sc, cid, 11, 0xf, 0);
  716                 WRITE_TSR(sc, cid, 12, 0xf, 0);
  717                 WRITE_TSR(sc, cid, 13, 0xf, 0);
  718                 WRITE_TSR(sc, cid, 14, 0xf, 0);
  719                 WRITE_TSR(sc, cid, 4, 0xf, tsr4);
  720                 WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT);
  721                 WRITE_TSR(sc, cid, 0, 0xf, tsr0);
  722 
  723                 break;
  724 
  725           case ATMIO_TRAFFIC_ABR:
  726                 if ((crm = t->tbe / NRM_CODE2VAL(t->nrm)) > 0xffff)
  727                         crm = 0xffff;
  728 
  729                 tsr0 |= HE_REGM_TSR0_TRAFFIC_ABR << HE_REGS_TSR0_TRAFFIC;
  730                 tsr0 |= HE_REGM_TSR0_USE_WMIN | HE_REGM_TSR0_UPDATE_GER;
  731 
  732                 WRITE_TSR(sc, cid, 0, 0xf, tsr0);
  733                 WRITE_TSR(sc, cid, 4, 0xf, tsr4);
  734 
  735                 WRITE_TSR(sc, cid, 1, 0xf,
  736                     ((hatm_cps2atmf(t->pcr) << HE_REGS_TSR1_PCR) |
  737                      (hatm_cps2atmf(t->mcr) << HE_REGS_TSR1_MCR)));
  738                 WRITE_TSR(sc, cid, 2, 0xf,
  739                     (hatm_cps2atmf(t->icr) << HE_REGS_TSR2_ACR));
  740                 WRITE_TSR(sc, cid, 3, 0xf,
  741                     ((NRM_CODE2VAL(t->nrm) - 1) << HE_REGS_TSR3_NRM) |
  742                     (crm << HE_REGS_TSR3_CRM));
  743 
  744                 WRITE_TSR(sc, cid, 5, 0xf, 0);
  745                 WRITE_TSR(sc, cid, 6, 0xf, 0);
  746                 WRITE_TSR(sc, cid, 7, 0xf, 0);
  747                 WRITE_TSR(sc, cid, 8, 0xf, 0);
  748                 WRITE_TSR(sc, cid, 10, 0xf, 0);
  749                 WRITE_TSR(sc, cid, 12, 0xf, 0);
  750                 WRITE_TSR(sc, cid, 14, 0xf, 0);
  751                 WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT);
  752 
  753                 WRITE_TSR(sc, cid, 11, 0xf,
  754                     (hatm_cps2atmf(t->icr) << HE_REGS_TSR11_ICR) |
  755                     (t->trm << HE_REGS_TSR11_TRM) |
  756                     (t->nrm << HE_REGS_TSR11_NRM) |
  757                     (t->adtf << HE_REGS_TSR11_ADTF));
  758 
  759                 WRITE_TSR(sc, cid, 13, 0xf,
  760                     (t->rdf << HE_REGS_TSR13_RDF) |
  761                     (t->rif << HE_REGS_TSR13_RIF) |
  762                     (t->cdf << HE_REGS_TSR13_CDF) |
  763                     (crm << HE_REGS_TSR13_CRM));
  764 
  765                 break;
  766 
  767           default:
  768                 return;
  769         }
  770 
  771         vcc->vflags |= HE_VCC_TX_OPEN;
  772 }
  773 
  774 /*
  775  * Close the TX side of a VCC. Set the CLOSING flag.
  776  */
  777 void
  778 hatm_tx_vcc_close(struct hatm_softc *sc, u_int cid)
  779 {
  780         struct hevcc *vcc = sc->vccs[cid];
  781         struct tpd *tpd_list[1];
  782         u_int i, pcr = 0;
  783 
  784         WRITE_TSR(sc, cid, 4, 0x8, HE_REGM_TSR4_FLUSH);
  785 
  786         switch (vcc->param.traffic) {
  787 
  788           case ATMIO_TRAFFIC_CBR:
  789                 WRITE_TSR(sc, cid, 14, 0x8, HE_REGM_TSR14_CBR_DELETE);
  790                 break;
  791 
  792           case ATMIO_TRAFFIC_ABR:
  793                 WRITE_TSR(sc, cid, 14, 0x4, HE_REGM_TSR14_ABR_CLOSE);
  794                 pcr = vcc->param.tparam.pcr;
  795                 /* FALL THROUGH */
  796 
  797           case ATMIO_TRAFFIC_UBR:
  798                 WRITE_TSR(sc, cid, 1, 0xf,
  799                     hatm_cps2atmf(HE_CONFIG_FLUSH_RATE) << HE_REGS_TSR1_MCR |
  800                     hatm_cps2atmf(pcr) << HE_REGS_TSR1_PCR);
  801                 break;
  802         }
  803 
  804         tpd_list[0] = hatm_alloc_tpd(sc, 0);
  805         tpd_list[0]->tpd.addr |= HE_REGM_TPD_EOS | HE_REGM_TPD_INTR;
  806         tpd_list[0]->cid = cid;
  807 
  808         vcc->vflags |= HE_VCC_TX_CLOSING;
  809         vcc->vflags &= ~HE_VCC_TX_OPEN;
  810 
  811         i = 0;
  812         while (hatm_queue_tpds(sc, 1, tpd_list, cid) != 0) {
  813                 if (++i == 1000)
  814                         panic("TPDRQ permanently full");
  815                 DELAY(1000);
  816         }
  817 }
  818 
  819 void
  820 hatm_tx_vcc_closed(struct hatm_softc *sc, u_int cid)
  821 {
  822         if (sc->vccs[cid]->param.traffic == ATMIO_TRAFFIC_CBR) {
  823                 sc->cbr_bw -= sc->vccs[cid]->param.tparam.pcr;
  824                 sc->rate_ctrl[sc->vccs[cid]->rc].refcnt--;
  825         }
  826 }

Cache object: 842f0aff65ac01e62a6512ae83087b95


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