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