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