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_rx.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  * Author: Hartmut Brandt <harti@freebsd.org>
   28  *
   29  * Driver for IDT77252 based cards like ProSum's.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD: releng/8.3/sys/dev/patm/if_patm_rx.c 175872 2008-02-01 19:36:27Z phk $");
   34 
   35 #include "opt_inet.h"
   36 #include "opt_natm.h"
   37 
   38 #include <sys/types.h>
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/malloc.h>
   42 #include <sys/kernel.h>
   43 #include <sys/bus.h>
   44 #include <sys/errno.h>
   45 #include <sys/conf.h>
   46 #include <sys/module.h>
   47 #include <sys/lock.h>
   48 #include <sys/mutex.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/queue.h>
   51 #include <sys/condvar.h>
   52 #include <sys/endian.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 <sys/mbpool.h>
   74 
   75 #include <dev/utopia/utopia.h>
   76 #include <dev/patm/idt77252reg.h>
   77 #include <dev/patm/if_patmvar.h>
   78 
   79 static void *patm_rcv_handle(struct patm_softc *sc, u_int handle);
   80 static void patm_rcv_free(struct patm_softc *, void *, u_int handle);
   81 static struct mbuf *patm_rcv_mbuf(struct patm_softc *, void *, u_int, int);
   82 
   83 static __inline void
   84 rct_write(struct patm_softc *sc, u_int cid, u_int w, u_int val)
   85 {
   86         patm_sram_write(sc, sc->mmap->rct + cid * IDT_RCT_ENTRY_SIZE + w, val);
   87 }
   88 static __inline u_int
   89 rct_read(struct patm_softc *sc, u_int cid, u_int w)
   90 {
   91         return (patm_sram_read(sc, sc->mmap->rct +
   92             cid * IDT_RCT_ENTRY_SIZE + w));
   93 }
   94 
   95 /* check if we can open this one */
   96 int
   97 patm_rx_vcc_can_open(struct patm_softc *sc, struct patm_vcc *vcc)
   98 {
   99         return (0);
  100 }
  101 
  102 /*
  103  * open the VCC
  104  */
  105 void
  106 patm_rx_vcc_open(struct patm_softc *sc, struct patm_vcc *vcc)
  107 {
  108         uint32_t w1 = IDT_RCT_OPEN;
  109 
  110         patm_debug(sc, VCC, "%u.%u RX opening", vcc->vcc.vpi, vcc->vcc.vci);
  111 
  112         switch (vcc->vcc.aal) {
  113           case ATMIO_AAL_0:
  114                 w1 |= IDT_RCT_AAL0 | IDT_RCT_FBP2 | IDT_RCT_RCI;
  115                 break;
  116           case ATMIO_AAL_34:
  117                 w1 |= IDT_RCT_AAL34;
  118                 break;
  119           case ATMIO_AAL_5:
  120                 w1 |= IDT_RCT_AAL5;
  121                 break;
  122           case ATMIO_AAL_RAW:
  123                 w1 |= IDT_RCT_AALRAW | IDT_RCT_RCI;
  124                 break;
  125         }
  126 
  127         if (vcc->cid != 0)
  128                 patm_sram_write4(sc, sc->mmap->rct + vcc->cid *
  129                     IDT_RCT_ENTRY_SIZE, w1, 0, 0, 0xffffffff);
  130         else {
  131                 /* switch the interface into promiscuous mode */
  132                 patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) |
  133                     IDT_CFG_ICAPT | IDT_CFG_VPECA);
  134         }
  135 
  136         vcc->vflags |= PATM_VCC_RX_OPEN;
  137 }
  138 
  139 /* close the given vcc for transmission */
  140 void
  141 patm_rx_vcc_close(struct patm_softc *sc, struct patm_vcc *vcc)
  142 {
  143         u_int w1;
  144 
  145         patm_debug(sc, VCC, "%u.%u RX closing", vcc->vcc.vpi, vcc->vcc.vci);
  146 
  147         if (vcc->cid == 0) {
  148                 /* switch off promiscuous mode */
  149                 patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) &
  150                     ~(IDT_CFG_ICAPT | IDT_CFG_VPECA));
  151                 vcc->vflags &= ~PATM_VCC_RX_OPEN;
  152                 return;
  153         }
  154 
  155         /* close the connection but keep state */
  156         w1 = rct_read(sc, vcc->cid, 0);
  157         w1 &= ~IDT_RCT_OPEN;
  158         rct_write(sc, vcc->cid, 0, w1);
  159 
  160         /* minimum idle count */
  161         w1 = (w1 & ~IDT_RCT_IACT_CNT_MASK) | (1 << IDT_RCT_IACT_CNT_SHIFT);
  162         rct_write(sc, vcc->cid, 0, w1);
  163 
  164         /* initialize scan */
  165         patm_nor_write(sc, IDT_NOR_IRCP, vcc->cid);
  166 
  167         vcc->vflags &= ~PATM_VCC_RX_OPEN;
  168         vcc->vflags |= PATM_VCC_RX_CLOSING;
  169 
  170         /*
  171          * check the RSQ
  172          * This is a hack. The problem is, that although an entry is written
  173          * to the RSQ, no interrupt is generated. Also we must wait 1 cell
  174          * time for the SAR to process the scan of our connection.
  175          */
  176         DELAY(1);
  177         patm_intr_rsq(sc);
  178 }
  179 
  180 /* transmission side finally closed */
  181 void
  182 patm_rx_vcc_closed(struct patm_softc *sc, struct patm_vcc *vcc)
  183 {
  184         patm_debug(sc, VCC, "%u.%u RX finally closed",
  185             vcc->vcc.vpi, vcc->vcc.vci);
  186 }
  187 
  188 /*
  189  * Handle the given receive status queue entry
  190  */
  191 void
  192 patm_rx(struct patm_softc *sc, struct idt_rsqe *rsqe)
  193 {
  194         struct mbuf *m;
  195         void *buf;
  196         u_int stat, cid, w, cells, len, h;
  197         struct patm_vcc *vcc;
  198         struct atm_pseudohdr aph;
  199         u_char *trail;
  200 
  201         cid = le32toh(rsqe->cid);
  202         stat = le32toh(rsqe->stat);
  203         h = le32toh(rsqe->handle);
  204 
  205         cid = PATM_CID(sc, IDT_RSQE_VPI(cid), IDT_RSQE_VCI(cid));
  206         vcc = sc->vccs[cid];
  207 
  208         if (IDT_RSQE_TYPE(stat) == IDT_RSQE_IDLE) {
  209                 /* connection has gone idle */
  210                 if (stat & IDT_RSQE_BUF)
  211                         patm_rcv_free(sc, patm_rcv_handle(sc, h), h);
  212 
  213                 w = rct_read(sc, cid, 0);
  214                 if (w != 0 && !(w & IDT_RCT_OPEN))
  215                         rct_write(sc, cid, 0, 0);
  216                 if (vcc != NULL && (vcc->vflags & PATM_VCC_RX_CLOSING)) {
  217                         patm_debug(sc, VCC, "%u.%u RX closed", vcc->vcc.vpi,
  218                             vcc->vcc.vci);
  219                         vcc->vflags &= ~PATM_VCC_RX_CLOSING;
  220                         if (vcc->vcc.flags & ATMIO_FLAG_ASYNC) {
  221                                 patm_rx_vcc_closed(sc, vcc);
  222                                 if (!(vcc->vflags & PATM_VCC_OPEN))
  223                                         patm_vcc_closed(sc, vcc);
  224                         } else
  225                                 cv_signal(&sc->vcc_cv);
  226                 }
  227                 return;
  228         }
  229 
  230         buf = patm_rcv_handle(sc, h);
  231 
  232         if (vcc == NULL || (vcc->vflags & PATM_VCC_RX_OPEN) == 0) {
  233                 patm_rcv_free(sc, buf, h);
  234                 return;
  235         }
  236 
  237         cells = IDT_RSQE_CNT(stat);
  238         KASSERT(cells > 0, ("zero cell count"));
  239 
  240         if (vcc->vcc.aal == ATMIO_AAL_0) {
  241                 /* deliver this packet as it is */
  242                 if ((m = patm_rcv_mbuf(sc, buf, h, 1)) == NULL)
  243                         return;
  244 
  245                 m->m_len = cells * 48;
  246                 m->m_pkthdr.len = m->m_len;
  247                 m->m_pkthdr.rcvif = sc->ifp;
  248 
  249         } else if (vcc->vcc.aal == ATMIO_AAL_34) {
  250                 /* XXX AAL3/4 */
  251                 patm_rcv_free(sc, buf, h);
  252                 return;
  253 
  254         } else if (vcc->vcc.aal == ATMIO_AAL_5) {
  255                 if (stat & IDT_RSQE_CRC) {
  256                         sc->ifp->if_ierrors++;
  257                         if (vcc->chain != NULL) {
  258                                 m_freem(vcc->chain);
  259                                 vcc->chain = vcc->last = NULL;
  260                         }
  261                         return;
  262                 }
  263 
  264                 /* append to current chain */
  265                 if (vcc->chain == NULL) {
  266                         if ((m = patm_rcv_mbuf(sc, buf, h, 1)) == NULL)
  267                                 return;
  268                         m->m_len = cells * 48;
  269                         m->m_pkthdr.len = m->m_len;
  270                         m->m_pkthdr.rcvif = sc->ifp;
  271                         vcc->chain = vcc->last = m;
  272                 } else {
  273                         if ((m = patm_rcv_mbuf(sc, buf, h, 0)) == NULL)
  274                                 return;
  275                         m->m_len = cells * 48;
  276                         vcc->last->m_next = m;
  277                         vcc->last = m;
  278                         vcc->chain->m_pkthdr.len += m->m_len;
  279                 }
  280 
  281                 if (!(stat & IDT_RSQE_EPDU))
  282                         return;
  283 
  284                 trail = mtod(m, u_char *) + m->m_len - 6;
  285                 len = (trail[0] << 8) + trail[1];
  286 
  287                 if ((u_int)vcc->chain->m_pkthdr.len < len + 8) {
  288                         patm_printf(sc, "%s: bad aal5 lengths %u %u\n",
  289                             __func__, (u_int)m->m_pkthdr.len, len);
  290                         m_freem(vcc->chain);
  291                         vcc->chain = vcc->last = NULL;
  292                         return;
  293                 }
  294                 m->m_len -= vcc->chain->m_pkthdr.len - len;
  295                 KASSERT(m->m_len >= 0, ("bad last mbuf"));
  296 
  297                 m = vcc->chain;
  298                 vcc->chain = vcc->last = NULL;
  299                 m->m_pkthdr.len = len;
  300         } else
  301                 panic("bad aal");
  302 
  303 #if 0
  304         {
  305                 u_int i;
  306 
  307                 for (i = 0; i < m->m_len; i++) {
  308                         printf("%02x ", mtod(m, u_char *)[i]);
  309                 }
  310                 printf("\n");
  311         }
  312 #endif
  313 
  314         sc->ifp->if_ipackets++;
  315         /* this is in if_atmsubr.c */
  316         /* sc->ifp->if_ibytes += m->m_pkthdr.len; */
  317 
  318         vcc->ibytes += m->m_pkthdr.len;
  319         vcc->ipackets++;
  320 
  321         ATM_PH_FLAGS(&aph) = vcc->vcc.flags & 0xff;
  322         ATM_PH_VPI(&aph) = IDT_RSQE_VPI(cid);
  323         ATM_PH_SETVCI(&aph, IDT_RSQE_VCI(cid));
  324 
  325 #ifdef ENABLE_BPF
  326         if (!(vcc->vcc.flags & ATMIO_FLAG_NG) &&
  327             (vcc->vcc.aal == ATMIO_AAL_5) &&
  328             (vcc->vcc.flags & ATM_PH_LLCSNAP))
  329                 BPF_MTAP(sc->ifp, m);
  330 #endif
  331 
  332         atm_input(sc->ifp, &aph, m, vcc->rxhand);
  333 }
  334 
  335 /*
  336  * Get the buffer for a receive handle. This is either an mbuf for
  337  * a large handle or a pool buffer for the others.
  338  */
  339 static void *
  340 patm_rcv_handle(struct patm_softc *sc, u_int handle)
  341 {
  342         void *buf;
  343         u_int c;
  344 
  345         if ((handle & ~MBUF_HMASK) == LMBUF_HANDLE) {
  346                 struct lmbuf *b;
  347 
  348                 c = handle & MBUF_HMASK;
  349                 b = &sc->lbufs[c];
  350 
  351                 buf = b->m;
  352                 b->m = NULL;
  353 
  354                 bus_dmamap_sync(sc->lbuf_tag, b->map, BUS_DMASYNC_POSTREAD);
  355                 patm_lbuf_free(sc, b);
  356 
  357         } else if ((handle & ~MBUF_HMASK) == MBUF_VHANDLE) {
  358                 mbp_sync(sc->vbuf_pool, handle,
  359                     0, VMBUF_SIZE, BUS_DMASYNC_POSTREAD);
  360                 buf = mbp_get(sc->vbuf_pool, handle);
  361 
  362         } else {
  363                 mbp_sync(sc->sbuf_pool, handle,
  364                     0, SMBUF_SIZE, BUS_DMASYNC_POSTREAD);
  365                 buf = mbp_get(sc->sbuf_pool, handle);
  366         }
  367 
  368         return (buf);
  369 }
  370 
  371 /*
  372  * Free a buffer.
  373  */
  374 static void
  375 patm_rcv_free(struct patm_softc *sc, void *p, u_int handle)
  376 {
  377         if ((handle & ~MBUF_HMASK) == LMBUF_HANDLE)
  378                 m_free((struct mbuf *)p);
  379 
  380         else if ((handle & ~MBUF_HMASK) == MBUF_VHANDLE)
  381                 mbp_free(sc->vbuf_pool, p);
  382 
  383         else
  384                 mbp_free(sc->sbuf_pool, p);
  385 }
  386 
  387 /*
  388  * Make an mbuf around the buffer
  389  */
  390 static struct mbuf *
  391 patm_rcv_mbuf(struct patm_softc *sc, void *buf, u_int h, int hdr)
  392 {
  393         struct mbuf *m;
  394 
  395         if ((h & ~MBUF_HMASK) == MBUF_LHANDLE)
  396                 return ((struct mbuf *)buf);
  397 
  398         if (hdr)
  399                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  400         else
  401                 MGET(m, M_DONTWAIT, MT_DATA);
  402         if (m == NULL) {
  403                 patm_rcv_free(sc, buf, h);
  404                 return (NULL);
  405         }
  406 
  407         if ((h & ~MBUF_HMASK) == MBUF_VHANDLE) {
  408                 MEXTADD(m, (caddr_t)buf, VMBUF_SIZE, mbp_ext_free,
  409                     buf, sc->vbuf_pool, M_PKTHDR, EXT_NET_DRV);
  410                 m->m_data += VMBUF_OFFSET;
  411         } else {
  412                 MEXTADD(m, (caddr_t)buf, SMBUF_SIZE, mbp_ext_free,
  413                     buf, sc->sbuf_pool, M_PKTHDR, EXT_NET_DRV);
  414                 m->m_data += SMBUF_OFFSET;
  415         }
  416 
  417         if (!(m->m_flags & M_EXT)) {
  418                 patm_rcv_free(sc, buf, h);
  419                 m_free(m);
  420                 return (NULL);
  421         }
  422         return (m);
  423 }
  424 
  425 /*
  426  * Process the raw cell at the given address.
  427  */
  428 void
  429 patm_rx_raw(struct patm_softc *sc, u_char *cell)
  430 {
  431         u_int vpi, vci, cid;
  432         struct patm_vcc *vcc;
  433         struct mbuf *m;
  434         u_char *dst;
  435         struct timespec ts;
  436         struct atm_pseudohdr aph;
  437         uint64_t cts;
  438 
  439         sc->stats.raw_cells++;
  440 
  441         /*
  442          * For some non-appearant reason the cell header
  443          * is in the wrong endian.
  444          */
  445         *(uint32_t *)cell = bswap32(*(uint32_t *)cell);
  446 
  447         vpi = ((cell[0] & 0xf) << 4) | ((cell[1] & 0xf0) >> 4);
  448         vci = ((cell[1] & 0xf) << 12) | (cell[2] << 4) | ((cell[3] & 0xf0) >> 4);
  449         cid = PATM_CID(sc, vpi, vci);
  450 
  451         vcc = sc->vccs[cid];
  452         if (vcc == NULL || !(vcc->vflags & PATM_VCC_RX_OPEN) ||
  453             vcc->vcc.aal != ATMIO_AAL_RAW) {
  454                 vcc = sc->vccs[0];
  455                 if (vcc == NULL || !(vcc->vflags & PATM_VCC_RX_OPEN)) {
  456                         sc->stats.raw_no_vcc++;
  457                         return;
  458                 }
  459         }
  460 
  461         MGETHDR(m, M_DONTWAIT, MT_DATA);
  462         if (m == NULL) {
  463                 sc->stats.raw_no_buf++;
  464                 return;
  465         }
  466         m->m_pkthdr.rcvif = sc->ifp;
  467 
  468         switch (vcc->vflags & PATM_RAW_FORMAT) {
  469 
  470           default:
  471           case PATM_RAW_CELL:
  472                 m->m_len = m->m_pkthdr.len = 53;
  473                 MH_ALIGN(m, 53);
  474                 dst = mtod(m, u_char *);
  475                 *dst++ = *cell++;
  476                 *dst++ = *cell++;
  477                 *dst++ = *cell++;
  478                 *dst++ = *cell++;
  479                 *dst++ = 0;             /* HEC */
  480                 bcopy(cell + 12, dst, 48);
  481                 break;
  482 
  483           case PATM_RAW_NOHEC:
  484                 m->m_len = m->m_pkthdr.len = 52;
  485                 MH_ALIGN(m, 52);
  486                 dst = mtod(m, u_char *);
  487                 *dst++ = *cell++;
  488                 *dst++ = *cell++;
  489                 *dst++ = *cell++;
  490                 *dst++ = *cell++;
  491                 bcopy(cell + 12, dst, 48);
  492                 break;
  493 
  494           case PATM_RAW_CS:
  495                 m->m_len = m->m_pkthdr.len = 64;
  496                 MH_ALIGN(m, 64);
  497                 dst = mtod(m, u_char *);
  498                 *dst++ = *cell++;
  499                 *dst++ = *cell++;
  500                 *dst++ = *cell++;
  501                 *dst++ = *cell++;
  502                 *dst++ = 0;             /* HEC */
  503                 *dst++ = 0;             /* flags */
  504                 *dst++ = 0;             /* reserved */
  505                 *dst++ = 0;             /* reserved */
  506                 nanotime(&ts);
  507                 cts = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
  508                 bcopy(dst, &cts, 8);
  509                 bcopy(cell + 12, dst + 8, 48);
  510                 break;
  511         }
  512 
  513         sc->ifp->if_ipackets++;
  514         /* this is in if_atmsubr.c */
  515         /* sc->ifp->if_ibytes += m->m_pkthdr.len; */
  516 
  517         vcc->ibytes += m->m_pkthdr.len;
  518         vcc->ipackets++;
  519 
  520         ATM_PH_FLAGS(&aph) = vcc->vcc.flags & 0xff;
  521         ATM_PH_VPI(&aph) = vcc->vcc.vpi;
  522         ATM_PH_SETVCI(&aph, vcc->vcc.vci);
  523 
  524         atm_input(sc->ifp, &aph, m, vcc->rxhand);
  525 }

Cache object: 3d72f8a38c1488682bf6264d16f49091


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