The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netatm/atm_subr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *
    3  * ===================================
    4  * HARP  |  Host ATM Research Platform
    5  * ===================================
    6  *
    7  *
    8  * This Host ATM Research Platform ("HARP") file (the "Software") is
    9  * made available by Network Computing Services, Inc. ("NetworkCS")
   10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
   11  * support of any kind.
   12  *
   13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
   14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
   15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
   16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
   17  * In no event shall NetworkCS be responsible for any damages, including
   18  * but not limited to consequential damages, arising from or relating to
   19  * any use of the Software or related support.
   20  *
   21  * Copyright 1994-1998 Network Computing Services, Inc.
   22  *
   23  * Copies of this Software may be made, however, the above copyright
   24  * notice must be reproduced on all copies.
   25  *
   26  *      @(#) $FreeBSD$
   27  *
   28  */
   29 
   30 /*
   31  * Core ATM Services
   32  * -----------------
   33  *
   34  * Miscellaneous ATM subroutines
   35  *
   36  */
   37 
   38 #include <sys/param.h>
   39 #include <sys/sysctl.h>
   40 #include <netatm/kern_include.h>
   41 #include <net/intrq.h>
   42 
   43 #ifndef lint
   44 __RCSID("@(#) $FreeBSD$");
   45 #endif
   46 
   47 
   48 /*
   49  * Global variables
   50  */
   51 struct atm_pif          *atm_interface_head = NULL;
   52 struct atm_ncm          *atm_netconv_head = NULL;
   53 Atm_endpoint            *atm_endpoints[ENDPT_MAX+1] = {NULL};
   54 struct sp_info          *atm_pool_head = NULL;
   55 struct stackq_entry     *atm_stackq_head = NULL, *atm_stackq_tail;
   56 #ifdef sgi
   57 int                     atm_intr_index;
   58 #endif
   59 struct atm_sock_stat    atm_sock_stat = { { 0 } };
   60 int                     atm_init = 0;
   61 int                     atm_version = ATM_VERSION;
   62 struct timeval          atm_debugtime = {0, 0};
   63 const int               atmintrq_present = 1;
   64 
   65 struct sp_info  atm_attributes_pool = {
   66         "atm attributes pool",          /* si_name */
   67         sizeof(Atm_attributes),         /* si_blksiz */
   68         10,                             /* si_blkcnt */
   69         100                             /* si_maxallow */
   70 };
   71 
   72 /*
   73  * net.harp.atm.atm_debug
   74  */
   75 int atm_debug;
   76 SYSCTL_INT(_net_harp_atm, OID_AUTO, atm_debug, CTLFLAG_RW,
   77     &atm_debug, 0, "HARP ATM layer debugging flag");
   78 
   79 /*
   80  * net.harp.atm.atm_dev_print
   81  */
   82 int atm_dev_print;
   83 SYSCTL_INT(_net_harp_atm, OID_AUTO, atm_dev_print, CTLFLAG_RW,
   84     &atm_dev_print, 0, "display ATM CPCS headers");
   85 
   86 /*
   87  * net.harp.atm.atm_print_data
   88  */
   89 int atm_print_data;
   90 SYSCTL_INT(_net_harp_atm, OID_AUTO, atm_print_data, CTLFLAG_RW,
   91     &atm_print_data, 0, "display ATM CPCS payloads");
   92 
   93 /*
   94  * Local functions
   95  */
   96 static void     atm_compact __P((struct atm_time *));
   97 static KTimeout_ret     atm_timexp __P((void *));
   98 
   99 /*
  100  * Local variables
  101  */
  102 static struct atm_time  *atm_timeq = NULL;
  103 static struct atm_time  atm_compactimer = {0, 0};
  104 
  105 static struct sp_info   atm_stackq_pool = {
  106         "Service stack queue pool",     /* si_name */
  107         sizeof(struct stackq_entry),    /* si_blksiz */
  108         10,                             /* si_blkcnt */
  109         10                              /* si_maxallow */
  110 };
  111 
  112 
  113 /*
  114  * Initialize ATM kernel
  115  * 
  116  * Performs any initialization required before things really get underway.
  117  * Called from ATM domain initialization or from first registration function 
  118  * which gets called.
  119  *
  120  * Arguments:
  121  *      none
  122  *
  123  * Returns:
  124  *      none
  125  *
  126  */
  127 void
  128 atm_initialize()
  129 {
  130         /*
  131          * Never called from interrupts, so no locking needed
  132          */
  133         if (atm_init)
  134                 return;
  135         atm_init = 1;
  136 
  137 #ifndef __FreeBSD__
  138         /*
  139          * Add ATM protocol family
  140          */
  141         (void) protocol_family(&atmdomain, NULL, NULL);
  142 #endif
  143 
  144         atm_intrq.ifq_maxlen = ATM_INTRQ_MAX;
  145 #ifdef sgi
  146         atm_intr_index = register_isr(atm_intr);
  147 #endif
  148 #ifdef __FreeBSD__
  149         register_netisr(NETISR_ATM, atm_intr);
  150 #endif
  151 
  152         /*
  153          * Initialize subsystems
  154          */
  155         atm_aal5_init();
  156 
  157         /*
  158          * Prime the timer
  159          */
  160         (void) timeout(atm_timexp, (void *)0, hz/ATM_HZ);
  161 
  162         /*
  163          * Start the compaction timer
  164          */
  165         atm_timeout(&atm_compactimer, SPOOL_COMPACT, atm_compact);
  166 }
  167 
  168 
  169 /*
  170  * Allocate a Control Block
  171  * 
  172  * Gets a new control block allocated from the specified storage pool, 
  173  * acquiring memory for new pool chunks if required.  The returned control
  174  * block's contents will be cleared.
  175  *
  176  * Arguments:
  177  *      sip     pointer to sp_info for storage pool
  178  *
  179  * Returns:
  180  *      addr    pointer to allocated control block
  181  *      0       allocation failed
  182  *
  183  */
  184 void *
  185 atm_allocate(sip)
  186         struct sp_info  *sip;
  187 {
  188         void            *bp;
  189         struct sp_chunk *scp;
  190         struct sp_link  *slp;
  191         int             s = splnet();
  192 
  193         /*
  194          * Count calls
  195          */
  196         sip->si_allocs++;
  197 
  198         /*
  199          * Are there any free in the pool?
  200          */
  201         if (sip->si_free) {
  202 
  203                 /*
  204                  * Find first chunk with a free block
  205                  */
  206                 for (scp = sip->si_poolh; scp; scp = scp->sc_next) {
  207                         if (scp->sc_freeh != NULL)
  208                                 break;
  209                 }
  210 
  211         } else {
  212 
  213                 /*
  214                  * No free blocks - have to allocate a new
  215                  * chunk (but put a limit to this)
  216                  */
  217                 struct sp_link  *slp_next;
  218                 int     i;
  219 
  220                 /*
  221                  * First time for this pool??
  222                  */
  223                 if (sip->si_chunksiz == 0) {
  224                         size_t  n;
  225 
  226                         /*
  227                          * Initialize pool information
  228                          */
  229                         n = sizeof(struct sp_chunk) +
  230                                 sip->si_blkcnt * 
  231                                 (sip->si_blksiz + sizeof(struct sp_link));
  232                         sip->si_chunksiz = roundup(n, SPOOL_ROUNDUP);
  233 
  234                         /*
  235                          * Place pool on kernel chain
  236                          */
  237                         LINK2TAIL(sip, struct sp_info, atm_pool_head, si_next);
  238                 }
  239 
  240                 if (sip->si_chunks >= sip->si_maxallow) {
  241                         sip->si_fails++;
  242                         (void) splx(s);
  243                         return (NULL);
  244                 }
  245 
  246                 scp = (struct sp_chunk *)
  247                         KM_ALLOC(sip->si_chunksiz, M_DEVBUF, M_NOWAIT);
  248                 if (scp == NULL) {
  249                         sip->si_fails++;
  250                         (void) splx(s);
  251                         return (NULL);
  252                 }
  253                 scp->sc_next = NULL;
  254                 scp->sc_info = sip;
  255                 scp->sc_magic = SPOOL_MAGIC;
  256                 scp->sc_used = 0;
  257 
  258                 /*
  259                  * Divy up chunk into free blocks
  260                  */
  261                 slp = (struct sp_link *)(scp + 1);
  262                 scp->sc_freeh = slp;
  263 
  264                 for (i = sip->si_blkcnt; i > 1; i--) { 
  265                         slp_next = (struct sp_link *)((caddr_t)(slp + 1) + 
  266                                         sip->si_blksiz);
  267                         slp->sl_u.slu_next = slp_next;
  268                         slp = slp_next;
  269                 }
  270                 slp->sl_u.slu_next = NULL;
  271                 scp->sc_freet = slp;
  272 
  273                 /*
  274                  * Add new chunk to end of pool
  275                  */
  276                 if (sip->si_poolh)
  277                         sip->si_poolt->sc_next = scp;
  278                 else
  279                         sip->si_poolh = scp;
  280                 sip->si_poolt = scp;
  281                 
  282                 sip->si_chunks++;
  283                 sip->si_total += sip->si_blkcnt;
  284                 sip->si_free += sip->si_blkcnt;
  285                 if (sip->si_chunks > sip->si_maxused)
  286                         sip->si_maxused = sip->si_chunks;
  287         }
  288 
  289         /*
  290          * Allocate the first free block in chunk
  291          */
  292         slp = scp->sc_freeh;
  293         scp->sc_freeh = slp->sl_u.slu_next;
  294         scp->sc_used++;
  295         sip->si_free--;
  296         bp = (slp + 1);
  297 
  298         /*
  299          * Save link back to pool chunk
  300          */
  301         slp->sl_u.slu_chunk = scp;
  302 
  303         /*
  304          * Clear out block
  305          */
  306         KM_ZERO(bp, sip->si_blksiz);
  307 
  308         (void) splx(s);
  309         return (bp);
  310 }
  311 
  312 
  313 /*
  314  * Free a Control Block
  315  * 
  316  * Returns a previously allocated control block back to the owners 
  317  * storage pool.  
  318  *
  319  * Arguments:
  320  *      bp      pointer to block to be freed
  321  *
  322  * Returns:
  323  *      none
  324  *
  325  */
  326 void
  327 atm_free(bp)
  328         void            *bp;
  329 {
  330         struct sp_info  *sip;
  331         struct sp_chunk *scp;
  332         struct sp_link  *slp;
  333         int             s = splnet();
  334 
  335         /*
  336          * Get containing chunk and pool info
  337          */
  338         slp = (struct sp_link *)bp;
  339         slp--;
  340         scp = slp->sl_u.slu_chunk;
  341         if (scp->sc_magic != SPOOL_MAGIC)
  342                 panic("atm_free: chunk magic missing");
  343         sip = scp->sc_info;
  344 
  345         /*
  346          * Add block to free chain
  347          */
  348         if (scp->sc_freeh) {
  349                 scp->sc_freet->sl_u.slu_next = slp;
  350                 scp->sc_freet = slp;
  351         } else
  352                 scp->sc_freeh = scp->sc_freet = slp;
  353         slp->sl_u.slu_next = NULL;
  354         sip->si_free++;
  355         scp->sc_used--;
  356 
  357         (void) splx(s);
  358         return;
  359 }
  360 
  361 
  362 /*
  363  * Storage Pool Compaction
  364  * 
  365  * Called periodically in order to perform compaction of the
  366  * storage pools.  Each pool will be checked to see if any chunks 
  367  * can be freed, taking some care to avoid freeing too many chunks
  368  * in order to avoid memory thrashing.
  369  *
  370  * Called at splnet.
  371  *
  372  * Arguments:
  373  *      tip     pointer to timer control block (atm_compactimer)
  374  *
  375  * Returns:
  376  *      none
  377  *
  378  */
  379 static void
  380 atm_compact(tip)
  381         struct atm_time *tip;
  382 {
  383         struct sp_info  *sip;
  384         struct sp_chunk *scp;
  385         int             i;
  386         struct sp_chunk *scp_prev;
  387 
  388         /*
  389          * Check out all storage pools
  390          */
  391         for (sip = atm_pool_head; sip; sip = sip->si_next) {
  392 
  393                 /*
  394                  * Always keep a minimum number of chunks around
  395                  */
  396                 if (sip->si_chunks <= SPOOL_MIN_CHUNK)
  397                         continue;
  398 
  399                 /*
  400                  * Maximum chunks to free at one time will leave
  401                  * pool with at least 50% utilization, but never
  402                  * go below minimum chunk count.
  403                  */
  404                 i = ((sip->si_free * 2) - sip->si_total) / sip->si_blkcnt;
  405                 i = MIN(i, sip->si_chunks - SPOOL_MIN_CHUNK);
  406 
  407                 /*
  408                  * Look for chunks to free
  409                  */
  410                 scp_prev = NULL;
  411                 for (scp = sip->si_poolh; scp && i > 0; ) {
  412 
  413                         if (scp->sc_used == 0) {
  414 
  415                                 /*
  416                                  * Found a chunk to free, so do it
  417                                  */
  418                                 if (scp_prev) {
  419                                         scp_prev->sc_next = scp->sc_next;
  420                                         if (sip->si_poolt == scp)
  421                                                 sip->si_poolt = scp_prev;
  422                                 } else
  423                                         sip->si_poolh = scp->sc_next;
  424 
  425                                 KM_FREE((caddr_t)scp, sip->si_chunksiz,
  426                                         M_DEVBUF);
  427 
  428                                 /*
  429                                  * Update pool controls
  430                                  */
  431                                 sip->si_chunks--;
  432                                 sip->si_total -= sip->si_blkcnt;
  433                                 sip->si_free -= sip->si_blkcnt;
  434                                 i--;
  435                                 if (scp_prev)
  436                                         scp = scp_prev->sc_next;
  437                                 else
  438                                         scp = sip->si_poolh;
  439                         } else {
  440                                 scp_prev = scp;
  441                                 scp = scp->sc_next;
  442                         }
  443                 }
  444         }
  445 
  446         /*
  447          * Restart the compaction timer
  448          */
  449         atm_timeout(&atm_compactimer, SPOOL_COMPACT, atm_compact);
  450 
  451         return;
  452 }
  453 
  454 
  455 /*
  456  * Release a Storage Pool
  457  * 
  458  * Frees all dynamic storage acquired for a storage pool.
  459  * This function is normally called just prior to a module's unloading.
  460  *
  461  * Arguments:
  462  *      sip     pointer to sp_info for storage pool
  463  *
  464  * Returns:
  465  *      none
  466  *
  467  */
  468 void
  469 atm_release_pool(sip)
  470         struct sp_info  *sip;
  471 {
  472         struct sp_chunk *scp, *scp_next;
  473         int             s = splnet();
  474 
  475         /*
  476          * Free each chunk in pool
  477          */
  478         for (scp = sip->si_poolh; scp; scp = scp_next) {
  479 
  480                 /*
  481                  * Check for memory leaks
  482                  */
  483                 if (scp->sc_used)
  484                         panic("atm_release_pool: unfreed blocks");
  485 
  486                 scp_next = scp->sc_next;
  487 
  488                 KM_FREE((caddr_t)scp, sip->si_chunksiz, M_DEVBUF);
  489         }
  490 
  491         /*
  492          * Update pool controls
  493          */
  494         sip->si_poolh = NULL;
  495         sip->si_chunks = 0;
  496         sip->si_total = 0;
  497         sip->si_free = 0;
  498 
  499         /*
  500          * Unlink pool from active chain
  501          */
  502         sip->si_chunksiz = 0;
  503         UNLINK(sip, struct sp_info, atm_pool_head, si_next);
  504 
  505         (void) splx(s);
  506         return;
  507 }
  508 
  509 
  510 /*
  511  * Handle timer tick expiration
  512  * 
  513  * Decrement tick count in first block on timer queue.  If there
  514  * are blocks with expired timers, call their timeout function.
  515  * This function is called ATM_HZ times per second.
  516  *
  517  * Arguments:
  518  *      arg     argument passed on timeout() call
  519  *
  520  * Returns:
  521  *      none
  522  *
  523  */
  524 static KTimeout_ret
  525 atm_timexp(arg)
  526         void    *arg;
  527 {
  528         struct atm_time *tip;
  529         int             s = splimp();
  530 
  531 
  532         /*
  533          * Decrement tick count
  534          */
  535         if (((tip = atm_timeq) == NULL) || (--tip->ti_ticks > 0)) {
  536                 goto restart;
  537         }
  538 
  539         /*
  540          * Stack queue should have been drained
  541          */
  542 #ifdef DIAGNOSTIC
  543         if (atm_stackq_head != NULL)
  544                 panic("atm_timexp: stack queue not empty");
  545 #endif
  546 
  547         /*
  548          * Dispatch expired timers
  549          */
  550         while (((tip = atm_timeq) != NULL) && (tip->ti_ticks == 0)) {
  551                 void    (*func)__P((struct atm_time *));
  552 
  553                 /*
  554                  * Remove expired block from queue
  555                  */
  556                 atm_timeq = tip->ti_next;
  557                 tip->ti_flag &= ~TIF_QUEUED;
  558 
  559                 /*
  560                  * Call timeout handler (with network interrupts locked out)
  561                  */
  562                 func = tip->ti_func;
  563                 (void) splx(s);
  564                 s = splnet();
  565                 (*func)(tip);
  566                 (void) splx(s);
  567                 s = splimp();
  568 
  569                 /*
  570                  * Drain any deferred calls
  571                  */
  572                 STACK_DRAIN();
  573         }
  574 
  575 restart:
  576         /*
  577          * Restart the timer
  578          */
  579         (void) splx(s);
  580         (void) timeout(atm_timexp, (void *)0, hz/ATM_HZ);
  581 
  582         return;
  583 }
  584 
  585 
  586 /*
  587  * Schedule a control block timeout
  588  * 
  589  * Place the supplied timer control block on the timer queue.  The
  590  * function (func) will be called in 't' timer ticks with the
  591  * control block address as its only argument.  There are ATM_HZ
  592  * timer ticks per second.  The ticks value stored in each block is
  593  * a delta of the number of ticks from the previous block in the queue.
  594  * Thus, for each tick interval, only the first block in the queue 
  595  * needs to have its tick value decremented.
  596  *
  597  * Arguments:
  598  *      tip     pointer to timer control block
  599  *      t       number of timer ticks until expiration
  600  *      func    pointer to function to call at expiration 
  601  *
  602  * Returns:
  603  *      none
  604  *
  605  */
  606 void
  607 atm_timeout(tip, t, func)
  608         struct atm_time *tip;
  609         int             t;
  610         void            (*func)__P((struct atm_time *));
  611 {
  612         struct atm_time *tip1, *tip2;
  613         int             s;
  614 
  615 
  616         /*
  617          * Check for double queueing error
  618          */
  619         if (tip->ti_flag & TIF_QUEUED)
  620                 panic("atm_timeout: double queueing");
  621 
  622         /*
  623          * Make sure we delay at least a little bit
  624          */
  625         if (t <= 0)
  626                 t = 1;
  627 
  628         /*
  629          * Find out where we belong on the queue
  630          */
  631         s = splimp();
  632         for (tip1 = NULL, tip2 = atm_timeq; tip2 && (tip2->ti_ticks <= t); 
  633                                             tip1 = tip2, tip2 = tip1->ti_next) {
  634                 t -= tip2->ti_ticks;
  635         }
  636 
  637         /*
  638          * Place ourselves on queue and update timer deltas
  639          */
  640         if (tip1 == NULL)
  641                 atm_timeq = tip;
  642         else
  643                 tip1->ti_next = tip;
  644         tip->ti_next = tip2;
  645 
  646         if (tip2)
  647                 tip2->ti_ticks -= t;
  648         
  649         /*
  650          * Setup timer block
  651          */
  652         tip->ti_flag |= TIF_QUEUED;
  653         tip->ti_ticks = t;
  654         tip->ti_func = func;
  655 
  656         (void) splx(s);
  657         return;
  658 }
  659 
  660 
  661 /*
  662  * Cancel a timeout
  663  * 
  664  * Remove the supplied timer control block from the timer queue.
  665  *
  666  * Arguments:
  667  *      tip     pointer to timer control block
  668  *
  669  * Returns:
  670  *      0       control block successfully dequeued
  671  *      1       control block not on timer queue
  672  *
  673  */
  674 int
  675 atm_untimeout(tip)
  676         struct atm_time *tip;
  677 {
  678         struct atm_time *tip1, *tip2;
  679         int             s;
  680 
  681         /*
  682          * Is control block queued?
  683          */
  684         if ((tip->ti_flag & TIF_QUEUED) == 0)
  685                 return(1);
  686 
  687         /*
  688          * Find control block on the queue
  689          */
  690         s = splimp();
  691         for (tip1 = NULL, tip2 = atm_timeq; tip2 && (tip2 != tip); 
  692                                             tip1 = tip2, tip2 = tip1->ti_next) {
  693         }
  694 
  695         if (tip2 == NULL) {
  696                 (void) splx(s);
  697                 return (1);
  698         }
  699 
  700         /*
  701          * Remove block from queue and update timer deltas
  702          */
  703         tip2 = tip->ti_next;
  704         if (tip1 == NULL)
  705                 atm_timeq = tip2;
  706         else
  707                 tip1->ti_next = tip2;
  708 
  709         if (tip2)
  710                 tip2->ti_ticks += tip->ti_ticks;
  711         
  712         /*
  713          * Reset timer block
  714          */
  715         tip->ti_flag &= ~TIF_QUEUED;
  716 
  717         (void) splx(s);
  718         return (0);
  719 }
  720 
  721 
  722 /*
  723  * Queue a Stack Call 
  724  * 
  725  * Queues a stack call which must be deferred to the global stack queue.
  726  * The call parameters are stored in entries which are allocated from the
  727  * stack queue storage pool.
  728  *
  729  * Arguments:
  730  *      cmd     stack command
  731  *      func    destination function
  732  *      token   destination layer's token
  733  *      cvp     pointer to  connection vcc
  734  *      arg1    command argument
  735  *      arg2    command argument
  736  *
  737  * Returns:
  738  *      0       call queued
  739  *      errno   call not queued - reason indicated
  740  *
  741  */
  742 int
  743 atm_stack_enq(cmd, func, token, cvp, arg1, arg2)
  744         int             cmd;
  745         void            (*func)__P((int, void *, int, int));
  746         void            *token;
  747         Atm_connvc      *cvp;
  748         int             arg1;
  749         int             arg2;
  750 {
  751         struct stackq_entry     *sqp;
  752         int             s = splnet();
  753 
  754         /*
  755          * Get a new queue entry for this call
  756          */
  757         sqp = (struct stackq_entry *)atm_allocate(&atm_stackq_pool);
  758         if (sqp == NULL) {
  759                 (void) splx(s);
  760                 return (ENOMEM);
  761         }
  762 
  763         /*
  764          * Fill in new entry
  765          */
  766         sqp->sq_next = NULL;
  767         sqp->sq_cmd = cmd;
  768         sqp->sq_func = func;
  769         sqp->sq_token = token;
  770         sqp->sq_arg1 = arg1;
  771         sqp->sq_arg2 = arg2;
  772         sqp->sq_connvc = cvp;
  773 
  774         /*
  775          * Put new entry at end of queue
  776          */
  777         if (atm_stackq_head == NULL)
  778                 atm_stackq_head = sqp;
  779         else
  780                 atm_stackq_tail->sq_next = sqp;
  781         atm_stackq_tail = sqp;
  782 
  783         (void) splx(s);
  784         return (0);
  785 }
  786 
  787 
  788 /*
  789  * Drain the Stack Queue
  790  * 
  791  * Dequeues and processes entries from the global stack queue.  
  792  *
  793  * Arguments:
  794  *      none
  795  *
  796  * Returns:
  797  *      none
  798  *
  799  */
  800 void
  801 atm_stack_drain()
  802 {
  803         struct stackq_entry     *sqp, *qprev, *qnext;
  804         int             s = splnet();
  805         int             cnt;
  806 
  807         /*
  808          * Loop thru entire queue until queue is empty
  809          *      (but panic rather loop forever)
  810          */
  811         do {
  812                 cnt = 0;
  813                 qprev = NULL;
  814                 for (sqp = atm_stackq_head; sqp; ) {
  815 
  816                         /*
  817                          * Got an eligible entry, do STACK_CALL stuff
  818                          */
  819                         if (sqp->sq_cmd & STKCMD_UP) {
  820                                 if (sqp->sq_connvc->cvc_downcnt) {
  821 
  822                                         /*
  823                                          * Cant process now, skip it
  824                                          */
  825                                         qprev = sqp;
  826                                         sqp = sqp->sq_next;
  827                                         continue;
  828                                 }
  829 
  830                                 /*
  831                                  * OK, dispatch the call
  832                                  */
  833                                 sqp->sq_connvc->cvc_upcnt++;
  834                                 (*sqp->sq_func)(sqp->sq_cmd, 
  835                                                 sqp->sq_token,
  836                                                 sqp->sq_arg1,
  837                                                 sqp->sq_arg2);
  838                                 sqp->sq_connvc->cvc_upcnt--;
  839                         } else {
  840                                 if (sqp->sq_connvc->cvc_upcnt) {
  841 
  842                                         /*
  843                                          * Cant process now, skip it
  844                                          */
  845                                         qprev = sqp;
  846                                         sqp = sqp->sq_next;
  847                                         continue;
  848                                 }
  849 
  850                                 /*
  851                                  * OK, dispatch the call
  852                                  */
  853                                 sqp->sq_connvc->cvc_downcnt++;
  854                                 (*sqp->sq_func)(sqp->sq_cmd, 
  855                                                 sqp->sq_token,
  856                                                 sqp->sq_arg1,
  857                                                 sqp->sq_arg2);
  858                                 sqp->sq_connvc->cvc_downcnt--;
  859                         }
  860 
  861                         /*
  862                          * Dequeue processed entry and free it
  863                          */
  864                         cnt++;
  865                         qnext = sqp->sq_next;
  866                         if (qprev)
  867                                 qprev->sq_next = qnext;
  868                         else
  869                                 atm_stackq_head = qnext;
  870                         if (qnext == NULL)
  871                                 atm_stackq_tail = qprev;
  872                         atm_free((caddr_t)sqp);
  873                         sqp = qnext;
  874                 }
  875         } while (cnt > 0);
  876 
  877         /*
  878          * Make sure entire queue was drained
  879          */
  880         if (atm_stackq_head != NULL)
  881                 panic("atm_stack_drain: Queue not emptied");
  882 
  883         (void) splx(s);
  884 }
  885 
  886 
  887 /*
  888  * Process Interrupt Queue
  889  * 
  890  * Processes entries on the ATM interrupt queue.  This queue is used by
  891  * device interface drivers in order to schedule events from the driver's 
  892  * lower (interrupt) half to the driver's stack services.
  893  *
  894  * The interrupt routines must store the stack processing function to call
  895  * and a token (typically a driver/stack control block) at the front of the
  896  * queued buffer.  We assume that the function pointer and token values are 
  897  * both contained (and properly aligned) in the first buffer of the chain.
  898  *
  899  * Arguments:
  900  *      none
  901  *
  902  * Returns:
  903  *      none
  904  *
  905  */
  906 void
  907 atm_intr()
  908 {
  909         KBuffer         *m;
  910         caddr_t         cp;
  911         atm_intr_func_t func;
  912         void            *token;
  913         int             s;
  914 
  915         for (; ; ) {
  916                 /*
  917                  * Get next buffer from queue
  918                  */
  919                 s = splimp();
  920                 IF_DEQUEUE(&atm_intrq, m);
  921                 (void) splx(s);
  922                 if (m == NULL)
  923                         break;
  924 
  925                 /*
  926                  * Get function to call and token value
  927                  */
  928                 KB_DATASTART(m, cp, caddr_t);
  929                 func = *(atm_intr_func_t *)cp;
  930                 cp += sizeof(func);
  931                 token = *(void **)cp;
  932                 KB_HEADADJ(m, -(sizeof(func) + sizeof(token)));
  933                 if (KB_LEN(m) == 0) {
  934                         KBuffer         *m1;
  935                         KB_UNLINKHEAD(m, m1);
  936                         m = m1;
  937                 }
  938 
  939                 /*
  940                  * Call processing function
  941                  */
  942                 (*func)(token, m);
  943 
  944                 /*
  945                  * Drain any deferred calls
  946                  */
  947                 STACK_DRAIN();
  948         }
  949 }
  950 
  951 
  952 /*
  953  * Print a pdu buffer chain
  954  * 
  955  * Arguments:
  956  *      m       pointer to pdu buffer chain
  957  *      msg     pointer to message header string
  958  *
  959  * Returns:
  960  *      none
  961  *
  962  */
  963 void
  964 atm_pdu_print(const KBuffer *m, const char *msg)
  965 {
  966         const u_char    *cp;
  967         int             i;
  968         char            c = ' ';
  969 
  970         printf("%s:", msg);
  971         while (m) { 
  972                 KB_DATASTART(m, cp, const u_char *);
  973                 printf("%cbfr=%p data=%p len=%d: ",
  974                         c, m, cp, KB_LEN(m));
  975                 c = '\t';
  976                 if (atm_print_data) {
  977                         for (i = 0; i < KB_LEN(m); i++) {
  978                                 printf("%2x ", *cp++);
  979                         }
  980                         printf("<end_bfr>\n");
  981                 } else {
  982                         printf("\n");
  983                 }
  984                 m = KB_NEXT(m);
  985         }
  986 }

Cache object: 4f98b3ba294139b14ce8461738122a07


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.