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