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/atm/hea/eni_receive.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  *
    3  * ===================================
    4  * HARP  |  Host ATM Research Platform
    5  * ===================================
    6  *
    7  *
    8  * This Host ATM Research Platform ("HARP") file (the "Software") is
    9  * made available by Network Computing Services, Inc. ("NetworkCS")
   10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
   11  * support of any kind.
   12  *
   13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
   14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
   15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
   16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
   17  * In no event shall NetworkCS be responsible for any damages, including
   18  * but not limited to consequential damages, arising from or relating to
   19  * any use of the Software or related support.
   20  *
   21  * Copyright 1994-1998 Network Computing Services, Inc.
   22  *
   23  * Copies of this Software may be made, however, the above copyright
   24  * notice must be reproduced on all copies.
   25  *
   26  *      @(#) $FreeBSD: src/sys/dev/hea/eni_receive.c,v 1.5 1999/08/28 00:41:45 peter Exp $
   27  *      @(#) $DragonFly: src/sys/dev/atm/hea/eni_receive.c,v 1.10 2008/03/01 22:03:13 swildner Exp $
   28  */
   29 
   30 /*
   31  * Efficient ENI Adapter Support
   32  * -----------------------------
   33  *
   34  * Receive management
   35  *
   36  */
   37 
   38 #include <netproto/atm/kern_include.h>
   39 
   40 #include "eni_stats.h"
   41 #include "eni.h"
   42 #include "eni_var.h"
   43 
   44 static void     eni_recv_stack (void *, KBuffer *);
   45 
   46 #ifdef  DIAGNOSTIC
   47 extern int      eni_pdu_print;
   48 #endif
   49 
   50 /*
   51  * Procedure to remove VCs from the Service List and generate DMA
   52  * requests to move the associated PDUs into host memory. As PDUs
   53  * are completed in adapter memory, the adapter examines the IN_SERVICE
   54  * bit for the VC in the VC table. If this bit is not set, the adapter
   55  * will place the VC number at the end of the service list queue, set
   56  * the IN_SERVICE bit in the VC table, and interrupt the host. The host
   57  * will remove VCs from the service list, clear the IN_SERVICE bit in
   58  * the VC table, and create a DMA list to move the PDU into host buffers.
   59  *
   60  * Arguments:
   61  *      eup             pointer to per unit structure
   62  *
   63  * Returns:
   64  *      none
   65  *
   66  */
   67 void
   68 eni_do_service(Eni_unit *eup)
   69 {
   70         int             vcc;
   71         Eni_vcc         *evp;
   72         u_long          servwrite;
   73         VCI_Table       *vct;
   74         u_long          rdptr;
   75         u_long          *rxp;
   76         KBuffer         *m;
   77         u_long          dma[TEMP_DMA_SIZE];
   78         u_long          i, j;
   79         u_long          dma_rd, dma_wr;
   80         u_long          dma_avail;
   81         int             pdulen;
   82         int             mask;
   83         u_long          *upp;
   84 
   85         /*
   86          * Where is the adapter currently inserting entries?
   87          */
   88         servwrite = eup->eu_midway[MIDWAY_SVCWR] & SVC_SIZE_MASK;
   89         /*
   90          * As long as we're not caught up with the adapter, keep
   91          * removing VCs from the service list.
   92          */
   93         while ( servwrite != eup->eu_servread ) {
   94                 int     vci_hdr;
   95                 u_long  descr;
   96 
   97                 /*
   98                  * Get VC number and find VC table entry.
   99                  */
  100                 vcc = eup->eu_svclist[eup->eu_servread];
  101                 vct = &eup->eu_vcitbl[vcc];
  102                 vci_hdr = vct->vci_control;     /* Current status */
  103 
  104                 /*
  105                  * Check that this VCC still needs servicing. We
  106                  * might have closed this VCC down in between
  107                  * the adapter setting the flag and our checking
  108                  * the flag. Also check that we haven't placed the
  109                  * VCC into TRASH mode.
  110                  */
  111                 if ( ( vci_hdr & VCI_IN_SERVICE ) == 0 ||
  112                     ( (vci_hdr & ~VCI_MODE_MASK) ==
  113                         (VCI_MODE_TRASH << VCI_MODE_SHIFT) ) )
  114                             goto next_vcc;
  115 
  116                 /*
  117                  * Find the size of this VCs buffer
  118                  */
  119                 mask = (vci_hdr >> VCI_SIZE_SHIFT) & VCI_SIZE_MASK;
  120                 mask = 1 << (ENI_LOC_PREDIV + mask);
  121                 /* Turn byte count into word count */
  122                 mask >>= 2;
  123                 /*
  124                  * Find the start of the adapter buffer for this VC.
  125                  */
  126                 rxp = (u_long *)
  127                     ((int)(((vci_hdr >> VCI_LOC_SHIFT ) & VCI_LOC_MASK)
  128                         << ENI_LOC_PREDIV) + (int)eup->eu_ram);
  129                 /*
  130                  * Locate incoming VCC for this PDU and find where we
  131                  * should next read from.
  132                  */
  133                 evp = (Eni_vcc *) atm_dev_vcc_find ( (Cmn_unit *)eup,
  134                     0, vcc, VCC_IN );
  135                 if ( evp == NULL )
  136                         goto next_vcc;          /* VCI no longer active */
  137                 rdptr = evp->ev_rxpos;
  138                 /*
  139                  * Find out where the adapter is currently reassembling.
  140                  * The PDU which starts at descr is not yet complete so we
  141                  * must stop there.
  142                  */
  143                 descr = ( vct->vci_descr >> 16 ) & 0x7FFF;
  144                 /*
  145                  * As long as we haven't processed all the completed PDUs on
  146                  * this VC, keep going...
  147                  */
  148                 while ( rdptr != descr )
  149                 {
  150                     int         n_cells;
  151                     int         pdu_descr;
  152                     int         aal5;
  153 
  154                     /*
  155                      * Ensure that the following are reset for every new
  156                      * PDU.
  157                      */
  158                     upp = NULL;
  159                     m = NULL;
  160 
  161                     /*
  162                      * Fisrt build a DMA with JK to skip the descriptor word.
  163                      * We must always skip the descriptor even if it turns out
  164                      * that there isn't any PDU here.
  165                      */
  166                     j = 0;
  167                     dma[j++] = (((rdptr + 1) & (mask-1)) << DMA_COUNT_SHIFT ) |
  168                         ( vcc << DMA_VCC_SHIFT ) | DMA_JK;
  169                     dma[j++] = 0;
  170 
  171                     /*
  172                      * We'll use some of the values below for skipping
  173                      * bad PDUs or counting statistics so compute them
  174                      * now.
  175                      */
  176 
  177                     /*
  178                      * Grab a copy of the descriptor word
  179                      */
  180                     pdu_descr = rxp[rdptr];
  181 
  182                     /*
  183                      * Strip out cell count from descriptor word.
  184                      * At this point, we still don't know if there
  185                      * is any real data until after we check for
  186                      * TRASH mode.
  187                      */
  188                     n_cells = pdu_descr & DESCR_CELL_COUNT;
  189 
  190                     /*
  191                      * Is this an AAL5 PDU? Check MODE in vci_hdr.
  192                      */
  193                     aal5 = ( ( vci_hdr & ~VCI_MODE_MASK ) ==
  194                         VCI_MODE_AAL5 << VCI_MODE_SHIFT );
  195 
  196                     /*
  197                      * Now check to see if we're trashing on this vcc.
  198                      * If so, there is no data with this VC and the
  199                      * next word after the current descriptor is the
  200                      * descriptor for the next PDU.
  201                      */
  202                     if ( ( pdu_descr & DESCR_TRASH_BIT ) != 0 ) {
  203                         if ( aal5 )
  204                                 /*
  205                                  * Count as number of AAL5 cells dropped
  206                                  */
  207                                 eup->eu_stats.eni_st_aal5.aal5_drops += n_cells;
  208                         else
  209                                 /*
  210                                  * Count as number of AAL0 cells dropped
  211                                  */
  212                                 eup->eu_stats.eni_st_aal0.aal0_drops += n_cells;
  213                         eup->eu_pif.pif_ierrors++;
  214                         /*
  215                          * When cells have been trashed, all we have in the
  216                          * buffer is a descriptor word. There are no data
  217                          * words. Set the number of cells to zero so that
  218                          * we correctly skip to the next word which will
  219                          * be the descriptor for the next PDU.
  220                          */
  221                         n_cells = 0;
  222                         /*
  223                          * Go issue the DMA to skip this descriptor word.
  224                          */
  225                         goto send_dma;
  226                     }
  227 
  228                     /*
  229                      * Data length: number of cells * cell size
  230                      */
  231                     pdulen = n_cells * BYTES_PER_CELL;
  232 
  233                     /*
  234                      * If this is an AAL5 PDU, then we need to check
  235                      * for the presence of any CRC errors. If there
  236                      * is one or more CRC errors, then we are going to
  237                      * drop this PDU.
  238                      */
  239                     if ( aal5 && ( pdu_descr & DESCR_CRC_ERR ) ) {
  240                         /*
  241                          * Count the stat
  242                          */
  243                         eup->eu_pif.pif_ierrors++;
  244                         eup->eu_stats.eni_st_aal5.aal5_pdu_crc++;
  245                         if ( evp->ev_connvc->cvc_vcc )
  246                                 evp->ev_connvc->cvc_vcc->vc_ierrors++;
  247                         /*
  248                          * Build a DMA entry to skip the rest of this
  249                          * PDU.
  250                          */
  251                         dma[j++] =
  252                             (((rdptr + n_cells*WORDS_PER_CELL + 1)
  253                                 & (mask-1)) << DMA_COUNT_SHIFT ) |
  254                                     (vcc << DMA_VCC_SHIFT ) | DMA_JK;
  255                         dma[j++] = 0;
  256                         /*
  257                          * All done with this PDU. Get a buffer to save some
  258                          * data for reclamation services.
  259                          */
  260                         KB_ALLOCPKT ( m, ENI_SMALL_BSIZE, KB_F_NOWAIT,
  261                             KB_T_DATA );
  262                         if ( m ) {
  263                                 u_long  *up;
  264 
  265                                 KB_DATASTART ( m, up, u_long * );
  266                                 /*
  267                                  * Indicate no PDU
  268                                  */
  269                                 KB_PLENSET ( m, 0 );
  270                                 /*
  271                                  * Set buffer length - only driver overhead
  272                                  */
  273                                 KB_LEN ( m ) = 3 * sizeof ( u_long );
  274                                 /*
  275                                  * Insert vcc, space for DMA pointers,
  276                                  * and pdulen
  277                                  */
  278                                 *up++ = vcc;
  279                                 upp = up;       /* Remember location */
  280                                 up++;           /* And skip it */
  281                                                 /* - to be filled later */
  282                                 *up = pdulen;   /* Actual PDU length if it */
  283                                                 /* were valid */
  284                         } else {
  285                                 /*
  286                                  * We've a real problem here as now we can't
  287                                  * reclaim/advance resources/safety pointers.
  288                                  */
  289                                 eup->eu_stats.eni_st_drv.drv_rv_norsc++;
  290 #ifdef  DO_LOG
  291                                 log ( LOG_ERR,
  292     "eni_do_service: No drain buffers available. Receiver about to lock.\n" );
  293 #endif
  294                         }
  295                         goto send_dma;
  296                     }
  297 
  298                     /*
  299                      * Do we need to strip the AAL layer? Yes if this
  300                      * is an AAL5 PDU.
  301                      */
  302                     if ( aal5 ) {
  303                         /*
  304                          * Grab the CS-PDU length. Find the address of the
  305                          * last word, back up one word to skip CRC, and
  306                          * then mask the whole thing to handle circular wraps.
  307                          */
  308                         pdulen = rxp[(rdptr + n_cells*WORDS_PER_CELL - 1)
  309                             & (mask-1)]
  310                                 & 0xFFFF;
  311                     }
  312 
  313                     /*
  314                      * We now have a valid PDU of some length. Build
  315                      * the necessary DMA list to move it into host
  316                      * memory.
  317                      */
  318 
  319                     /*
  320                      * Get an initial buffer.
  321                      */
  322                     KB_ALLOCPKT ( m, ENI_SMALL_BSIZE, KB_F_NOWAIT, KB_T_DATA );
  323                     /*
  324                      * Do we have a valid buffer?
  325                      */
  326                     if ( m != NULL )
  327                     {
  328                         int     len;
  329                         u_long  *up;
  330                         KBuffer *m0;
  331         
  332                         KB_DATASTART ( m, up, u_long * );
  333                         /*
  334                          * Fill in pdulen in PKTHDR structure (for IP).
  335                          */
  336                         KB_PLENSET ( m, pdulen );
  337                         /*
  338                          * We're going to save the VCI nuber, the start
  339                          * and stop DMA pointers, and the PDU length at
  340                          * the head of the buffer. We'll pull this out
  341                          * later after the DMA has completed.
  342                          *
  343                          * Insert VCI number as first word in first buffer,
  344                          * remeber where we want to store the start/stop
  345                          * pointers, and store the PDU length.
  346                          */
  347                         *up++ = vcc;    /* PDU's VCC */
  348                         upp = up;       /* Remember where we are */
  349                         up++;           /* To stuff start/stop pointers in */
  350                         *up++ = pdulen; /* PDU's length */
  351                         /*
  352                          * Leave some extra room in case a higher protocol
  353                          * (IP) wants to do a pullup. Maybe we can keep
  354                          * someone from having to allocate another buffer
  355                          * a do a larger memory copy.
  356                          */
  357                         len = MIN ( ENI_SMALL_BSIZE, pdulen );
  358                         (void) eni_set_dma ( eup, 1, dma, TEMP_DMA_SIZE, &j,
  359                                 vcc, (u_long)up, len );
  360                         /*
  361                          * Adjust length of remaining data in PDU
  362                          */
  363                         pdulen -= len;
  364                         /*
  365                          * Set buffer length, including our overhead
  366                          */
  367                         KB_LEN ( m ) = len + 3 * sizeof ( u_long );
  368                         /*
  369                          * Finish by moving anything which won't fit in
  370                          * first buffer
  371                          */
  372                         m0 = m;
  373                         while ( pdulen ) {
  374                                 KBuffer *m1;
  375                                 u_long  data_addr;
  376         
  377                                 /*
  378                                  * Get another buffer
  379                                  */
  380                                 KB_ALLOCEXT ( m1, ENI_LARGE_BSIZE, KB_F_NOWAIT,
  381                                         KB_T_DATA );
  382         
  383                                 /*
  384                                  * If we succeeded...
  385                                  */
  386                                 if ( m1 ) {
  387                                     /*
  388                                      * Figure out how much we can move into
  389                                      * this buffer.
  390                                      */
  391                                     len = MIN ( ENI_LARGE_BSIZE, pdulen );
  392                                     /*
  393                                      * Setup DMA list for this buffer
  394                                      */
  395                                     KB_DATASTART ( m1, data_addr, u_long );
  396                                     (void) eni_set_dma
  397                                         ( eup, 1, dma, TEMP_DMA_SIZE, &j, vcc,
  398                                             data_addr, len );
  399                                     /*
  400                                      * Adjust remaining length
  401                                      */
  402                                     pdulen -= len;
  403                                     /*
  404                                      * Set buffer length
  405                                      */
  406                                     KB_LEN ( m1 ) = len;
  407                                     /*
  408                                      * Link new buffer onto end and advance
  409                                      * pointer
  410                                      */
  411                                     KB_NEXT ( m0 ) = m1;
  412                                     m0 = m1;
  413                                 } else {
  414                                     /*
  415                                      * Either we were unable to grab another
  416                                      * buffer or there are no large buffers
  417                                      * available. We know that the first
  418                                      * buffer is valid, so drop everything
  419                                      * else, build a JK DMA to skip/drop this
  420                                      * PDU, set the pointers to reclaim
  421                                      * resources/advance pointers, and
  422                                      * finish this PDU now.
  423                                      */
  424                                     if ( KB_NEXT ( m ) )
  425                                         KB_FREEALL ( KB_NEXT ( m ) );
  426                                     eup->eu_pif.pif_ierrors++;
  427                                     j = 2;
  428                                     dma[j++] =
  429                                         (((rdptr + n_cells*WORDS_PER_CELL + 1)
  430                                             & (mask-1)) << DMA_COUNT_SHIFT ) |
  431                                                 (vcc << DMA_VCC_SHIFT ) |
  432                                                     DMA_JK;
  433                                     dma[j++] = 0;
  434                                     /*
  435                                      * Reset PDU length to zero
  436                                      */
  437                                     KB_PLENSET ( m, 0 );
  438                                     /*
  439                                      * Count some statistics
  440                                      */
  441                                     /*
  442                                      * Count this as dropped cells
  443                                      */
  444                                     if ( aal5 ) {
  445                                         eup->eu_stats.eni_st_aal5.aal5_drops +=
  446                                             n_cells;
  447                                         eup->eu_stats.eni_st_aal5.aal5_pdu_drops++;
  448                                     } else
  449                                         eup->eu_stats.eni_st_aal0.aal0_drops +=
  450                                             n_cells;
  451                                     /*
  452                                      * Drop it
  453                                      */
  454                                     goto send_dma;
  455                                 }
  456                         }
  457                         /*
  458                          * If necessary, skip AAL layer
  459                          */
  460                         if ( aal5 ) {
  461                                 dma[j++] =
  462                                   (((rdptr + n_cells*WORDS_PER_CELL + 1)
  463                                         & (mask-1)) << DMA_COUNT_SHIFT)
  464                                             | (vcc << DMA_VCC_SHIFT) | DMA_JK;
  465                                 dma[j++] = 0;
  466                         }
  467                     } else {
  468                         /*
  469                          * We failed to get an initial buffer. Since we
  470                          * haven't changed anything for this PDU yet and the
  471                          * PDU is still valid, exit now and try to service it
  472                          * next time around. We're not very likely to get
  473                          * another buffer right now anyways.
  474                          */
  475                         eup->eu_stats.eni_st_drv.drv_rv_nobufs++;
  476 #ifdef  DO_LOG
  477                         log ( LOG_ERR,
  478 "eni_do_service: No buffers available. Exiting without servicing service list.\n" );
  479 #endif
  480                         /*
  481                          * Clear the IN_SERVICE indicator for this VCC
  482                          */
  483                         vct->vci_control &= ~VCI_IN_SERVICE;
  484                         return;
  485                     }
  486 
  487 send_dma:
  488                     /*
  489                      * Set the end bit on the last DMA for this PDU
  490                      */
  491                     dma[j-2] |= DMA_END_BIT;
  492 
  493                     /*
  494                      * Where are the current DMA pointers
  495                      */
  496                     dma_rd = eup->eu_midway[MIDWAY_RX_RD];
  497                     dma_wr = eup->eu_midway[MIDWAY_RX_WR];
  498 
  499                     /*
  500                      * Check how much space is available
  501                      */
  502                     if ( dma_rd == dma_wr )
  503                         dma_avail = DMA_LIST_SIZE;
  504                     else
  505                         dma_avail = ( dma_rd + DMA_LIST_SIZE - dma_wr )
  506                             & (DMA_LIST_SIZE-1);
  507 
  508                     /*
  509                      * Check for queue full or wrap past write okay pointer
  510                      */
  511                     if ( dma_avail < j  ||
  512                         ( dma_wr + j > eup->eu_rxdmawr + DMA_LIST_SIZE ) ) {
  513                         /*
  514                          * There's no room in the DMA list to insert
  515                          * this request. Since we haven't changed anything
  516                          * yet and the PDU is good, exit now and service
  517                          * it next time around. What we really need to do
  518                          * is wait for the RX list to drain and that won't
  519                          * happen if we keep trying to process PDUs here.
  520                          */
  521                         eup->eu_stats.eni_st_drv.drv_rv_nodma++;
  522 #ifdef  DO_LOG
  523                         log ( LOG_ERR,
  524 "eni_do_service: No room in receive DMA list. Postponing service request.\n" );
  525 #endif
  526                         /*
  527                          * Free the local buffer chain
  528                          */
  529                         KB_FREEALL ( m );
  530                         /*
  531                          * Clear the IN_SERVICE indicator for this VCC.
  532                          */
  533                         vct->vci_control &= ~VCI_IN_SERVICE;
  534                         return; 
  535                     }
  536 
  537                     /*
  538                      * If we have a buffer chain, save the starting
  539                      * dma_list location.
  540                      */
  541                     if ( upp ) {
  542                         *upp = dma_wr << 16;
  543                     }
  544 
  545                     /*
  546                      * Stuff the DMA list
  547                      */
  548                     j >>= 1;
  549                     for ( i = 0; i < j; i++ ) {
  550                         eup->eu_rxdma[dma_wr*2] = dma[i*2];
  551                         eup->eu_rxdma[dma_wr*2+1] = dma[i*2+1];
  552                         dma_wr = (dma_wr+1) & (DMA_LIST_SIZE-1);
  553                     }
  554                     /*
  555                      * If we have a buffer chain, save the location of
  556                      * the ending dma_list location and queue the chain
  557                      * so that we can recover the resources later.
  558                      */
  559                     if ( upp ) {
  560                         *upp |= dma_wr;
  561                         /*
  562                          * Place buffer on receive queue waiting for RX_DMA
  563                          */
  564                         if ( IF_QFULL ( &eup->eu_rxqueue ) ) {
  565                             /*
  566                              * We haven't done anything we can't back out
  567                              * of. Drop request and service it next time.
  568                              * We've inserted the DMA list but it's not
  569                              * valid until we advance the RX_WR pointer,
  570                              * thus it's okay to bail here...
  571                              */
  572                             eup->eu_stats.eni_st_drv.drv_rv_rxq++;
  573 #ifdef  DO_LOG
  574                             log ( LOG_ERR,
  575         "eni_do_service: RX drain queue full. Postponing servicing.\n" );
  576 #endif
  577                             KB_FREEALL ( m );
  578                             /*
  579                              * Clear the IN_SERVICE indicator for this VCC.
  580                              */
  581                             vct->vci_control &= ~VCI_IN_SERVICE;
  582                             return;
  583                         } else { 
  584                             IF_ENQUEUE ( &eup->eu_rxqueue, m );
  585                             /*
  586                              * Advance the RX_WR pointer to cause
  587                              * the adapter to work on this DMA list.
  588                              */
  589                             eup->eu_midway[MIDWAY_RX_WR] = dma_wr;
  590                         }
  591                     }
  592                     /*
  593                      * Advance our notion of where the next PDU
  594                      * should start.
  595                      */
  596                     rdptr = (rdptr + n_cells*WORDS_PER_CELL + 1)
  597                         & (mask-1);
  598                     evp->ev_rxpos = rdptr;
  599 
  600                     /*
  601                      * Increment cells/pdu received stats.
  602                      */
  603                     eup->eu_stats.eni_st_atm.atm_rcvd += n_cells;
  604                     if ( aal5 ) {
  605                         eup->eu_stats.eni_st_aal5.aal5_rcvd += n_cells;
  606                         eup->eu_stats.eni_st_aal5.aal5_pdu_rcvd++;
  607                     } else {
  608                         eup->eu_stats.eni_st_aal0.aal0_rcvd += n_cells;
  609                     }
  610 
  611                     /*
  612                      * Continue processing PDUs on this same VCI
  613                      */
  614                 }
  615 
  616 next_vcc:
  617                 /*
  618                  * Advance to next entry in the service_list.
  619                  */
  620                 eup->eu_servread = (eup->eu_servread + 1) & SVC_SIZE_MASK;
  621 
  622                 /*
  623                  * And clear the IN_SERVICE indicator for this VCC.
  624                  */
  625                 vct->vci_control &= ~VCI_IN_SERVICE;
  626         }
  627         return;
  628 }
  629 
  630 /*
  631  * Drain Receive queue
  632  *
  633  * As we build DMA lists to move PDUs from adapter buffers into host
  634  * buffers, we place the request on a private ifqueue so that we can
  635  * free any resources AFTER we know they've been successfully DMAed.
  636  * As part of the service processing, we record the PDUs start and stop
  637  * entries in the DMA list, and prevent wrapping. When we pull the top
  638  * entry off, we simply check that the current DMA location is outside
  639  * this PDU and if so, it's okay to free things.
  640  *
  641  * Arguments:
  642  *      eup             pointer to device unit structure
  643  *
  644  * Returns:
  645  *      none
  646  *
  647  */
  648 void
  649 eni_recv_drain(Eni_unit *eup)
  650 {
  651         KBuffer         *m;
  652         Eni_vcc         *evp;
  653         struct vccb     *vcp;
  654         u_long          vcc;
  655         u_long          DMA_Rdptr;
  656         u_long          dma_wrp;
  657         u_long          start, stop;
  658 
  659         crit_enter();
  660         /* Pop first buffer */
  661         IF_DEQUEUE ( &eup->eu_rxqueue, m );
  662         while ( m ) {
  663                 u_long  *up;
  664                 u_long  pdulen;
  665 
  666                 KB_DATASTART ( m, up, u_long * );
  667 
  668                 /*
  669                  * Grab the VCI number
  670                  */
  671                 vcc = *up++;
  672 
  673                 /*
  674                  * Check to see if we can process this buffer yet.
  675                  */
  676                 /* Get current DMA_Rdptr */
  677                 DMA_Rdptr = eup->eu_midway[MIDWAY_RX_RD];
  678                 /* Boundaries for first buffer */
  679                 dma_wrp = *up++;
  680                 start = dma_wrp >> 16;
  681                 stop = dma_wrp & 0xffff;
  682                 /*
  683                  * Start should not equal stop because that would
  684                  * mean we tried inserting a NULL DMA list.
  685                  */
  686                 if ( start > stop ) {           /* We wrapped */
  687                         if ( !(DMA_Rdptr >= stop && DMA_Rdptr < start) ) {
  688                                 IF_PREPEND ( &eup->eu_rxqueue, m );
  689                                 goto finish;
  690                         }
  691                 } else {
  692                         if ( DMA_Rdptr < stop && DMA_Rdptr >= start ) {
  693                                 IF_PREPEND ( &eup->eu_rxqueue, m );
  694                                 goto finish;
  695                         }
  696                 }
  697                 /*
  698                  * Adapter is finished with this buffer, we can
  699                  * continue processing it now.
  700                  */
  701 
  702                 /*
  703                  * Locate incoming VCC for this PDU
  704                  */
  705                 evp = (Eni_vcc *) atm_dev_vcc_find ( (Cmn_unit *)eup,
  706                     0, vcc, VCC_IN );
  707 
  708                 if ( evp == NULL ) {
  709                         eup->eu_stats.eni_st_drv.drv_rv_novcc++;
  710                         KB_FREEALL ( m );
  711                         goto next_buffer;
  712                 }
  713 
  714 #ifdef  DIAGNOSTIC
  715                 if ( eni_pdu_print )
  716                     atm_dev_pdu_print ( (Cmn_unit *)eup, (Cmn_vcc *)evp, m,
  717                         "eni_stack_drain" );
  718 #endif
  719 
  720                 /*
  721                  * Grab theoretical PDU length
  722                  */
  723                 pdulen = *up++;
  724 
  725                 /*
  726                  * Quick, count the PDU
  727                  */
  728                 eup->eu_pif.pif_ipdus++;
  729                 eup->eu_pif.pif_ibytes += pdulen;
  730                 if ( evp ) {
  731                     vcp = evp->ev_connvc->cvc_vcc;
  732                     if ( vcp ) {
  733                         vcp->vc_ipdus++;
  734                         vcp->vc_ibytes += pdulen;
  735                         if ( vcp->vc_nif ) {
  736                             vcp->vc_nif->nif_ibytes += pdulen;
  737                             vcp->vc_nif->nif_if.if_ipackets++;
  738                             vcp->vc_nif->nif_if.if_ibytes += pdulen;
  739                         }
  740                     }
  741                 }
  742 
  743                 /*
  744                  * Advance DMA write allowable pointer
  745                  */
  746                 eup->eu_rxdmawr = stop;
  747 
  748                 /*
  749                  * Get packet PDU length
  750                  */
  751                 KB_PLENGET ( m, pdulen );
  752 
  753                 /*
  754                  * Only try queueing this if there is data
  755                  * to be handed up to the next layer. Errors
  756                  * such as CRC and VC trashing will get us this
  757                  * far to advance pointers, etc., but the PDU
  758                  * length will be zero.
  759                  */
  760                 if ( pdulen ) {
  761                         /*
  762                          * We saved three words back in eni_do_service()
  763                          * to use for callback. Since the core only
  764                          * expects two words, skip over the first one.
  765                          * Then, reset up pointer to start of buffer data
  766                          * area and write the callback info.
  767                          */
  768                         KB_HEADADJ ( m, -sizeof(u_long) );
  769                         KB_DATASTART ( m, up, u_long * );
  770                         *((int *)up) = (int)eni_recv_stack;
  771                         up++;
  772                         *((int *)up) = (int)evp;
  773                         /*
  774                          * Schedule callback
  775                          */
  776                         if (netisr_queue(NETISR_ATM, m)) {
  777                                 eup->eu_stats.eni_st_drv.drv_rv_intrq++;
  778                                 eup->eu_pif.pif_ierrors++;
  779 #ifdef  DO_LOG
  780                                 log ( LOG_ERR,
  781 "eni_receive_drain: ATM_INTRQ is full. Unable to pass up stack.\n" );
  782 #endif
  783                                 KB_FREEALL ( m );
  784                         }
  785                 } else {
  786                         /*
  787                          * Free zero-length buffer
  788                          */
  789                         KB_FREEALL(m);
  790                 }
  791 
  792 next_buffer:
  793                 /*
  794                  * Look for next buffer
  795                  */
  796                 IF_DEQUEUE ( &eup->eu_rxqueue, m );
  797         }
  798 finish:
  799         crit_exit();
  800 }
  801 
  802 /*
  803  * Pass incoming PDU up Stack
  804  *
  805  * This function is called via the core ATM interrupt queue callback
  806  * set in eni_recv_drain(). It will pass the supplied incoming
  807  * PDU up the incoming VCC's stack.
  808  *
  809  * Arguments:
  810  *      tok             token to identify stack instantiation
  811  *      m               pointer to incoming PDU buffer chain
  812  *
  813  * Returns:
  814  *      none
  815  */
  816 static void
  817 eni_recv_stack(void *tok, KBuffer *m)
  818 {
  819         Eni_vcc         *evp = (Eni_vcc *)tok;
  820         int             err;
  821 
  822         /*
  823          * This should never happen now but if it does and we don't stop it,
  824          * we end up panic'ing in netatm when trying to pull a function
  825          * pointer and token value out of a buffer with address zero.
  826          */
  827         if ( !m ) {
  828 #ifdef  DO_LOG
  829                 log ( LOG_ERR,
  830                         "eni_recv_stack: NULL buffer, tok = %p\n", tok );
  831 #endif
  832                 return;
  833         }
  834 
  835         /*
  836          * Send the data up the stack
  837          */
  838         STACK_CALL ( CPCS_UNITDATA_SIG, evp->ev_upper,
  839                 (void *)evp->ev_toku, evp->ev_connvc, (int)m, 0, err );
  840         if ( err ) {
  841                 KB_FREEALL ( m );
  842         }
  843 
  844         return;
  845 }
  846 

Cache object: a943e0cad24a6cfb8e8f1c9965106143


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