File:  [DragonFly] / src / sys / netproto / atm / atm_subr.c
Revision 1.12: download - view: text, annotated - select for diffs
Sun Apr 11 07:41:52 2004 UTC (10 years ago) by hsu
Branches: MAIN
CVS tags: HEAD
Silence compiler warning by adding include files.

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