3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
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.
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.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
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.23 2008/09/24 14:26:39 sephe Exp $
34 * Miscellaneous ATM subroutines
38 #include "kern_include.h"
43 struct atm_pif *atm_interface_head = NULL;
44 struct atm_ncm *atm_netconv_head = NULL;
45 Atm_endpoint *atm_endpoints[ENDPT_MAX+1] = {NULL};
46 struct sp_info *atm_pool_head = NULL;
47 struct stackq_entry *atm_stackq_head = NULL, *atm_stackq_tail;
48 struct atm_sock_stat atm_sock_stat = { { 0 } };
51 int atm_dev_print = 0;
52 int atm_print_data = 0;
53 int atm_version = ATM_VERSION;
54 struct timeval atm_debugtime = {0, 0};
55 struct ifqueue atm_intrq;
57 struct sp_info atm_attributes_pool = {
58 "atm attributes pool", /* si_name */
59 sizeof(Atm_attributes), /* si_blksiz */
64 static struct callout atm_timexp_ch;
69 static void atm_compact (struct atm_time *);
70 static KTimeout_ret atm_timexp (void *);
71 static void atm_intr(netmsg_t msg);
76 static struct atm_time *atm_timeq = NULL;
77 static struct atm_time atm_compactimer = {0, 0};
79 static struct sp_info atm_stackq_pool = {
80 "Service stack queue pool", /* si_name */
81 sizeof(struct stackq_entry), /* si_blksiz */
88 * Initialize ATM kernel
90 * Performs any initialization required before things really get underway.
91 * Called from ATM domain initialization or from first registration function
105 * Never called from interrupts, so no locking needed
111 atm_intrq.ifq_maxlen = ATM_INTRQ_MAX;
112 netisr_register(NETISR_ATM, atm_intr, NULL);
115 * Initialize subsystems
122 callout_init(&atm_timexp_ch);
123 callout_reset(&atm_timexp_ch, hz / ATM_HZ, atm_timexp, NULL);
126 * Start the compaction timer
128 atm_timeout(&atm_compactimer, SPOOL_COMPACT, atm_compact);
133 * Allocate a Control Block
135 * Gets a new control block allocated from the specified storage pool,
136 * acquiring memory for new pool chunks if required. The returned control
137 * block's contents will be cleared.
140 * sip pointer to sp_info for storage pool
143 * addr pointer to allocated control block
144 * 0 allocation failed
148 atm_allocate(struct sp_info *sip)
151 struct sp_chunk *scp;
162 * Are there any free in the pool?
167 * Find first chunk with a free block
169 for (scp = sip->si_poolh; scp; scp = scp->sc_next) {
170 if (scp->sc_freeh != NULL)
177 * No free blocks - have to allocate a new
178 * chunk (but put a limit to this)
180 struct sp_link *slp_next;
184 * First time for this pool??
186 if (sip->si_chunksiz == 0) {
190 * Initialize pool information
192 n = sizeof(struct sp_chunk) +
194 (sip->si_blksiz + sizeof(struct sp_link));
195 sip->si_chunksiz = roundup(n, SPOOL_ROUNDUP);
198 * Place pool on kernel chain
200 LINK2TAIL(sip, struct sp_info, atm_pool_head, si_next);
203 if (sip->si_chunks >= sip->si_maxallow) {
209 scp = KM_ALLOC(sip->si_chunksiz, M_DEVBUF,
210 M_INTWAIT | M_NULLOK);
218 scp->sc_magic = SPOOL_MAGIC;
222 * Divy up chunk into free blocks
224 slp = (struct sp_link *)(scp + 1);
227 for (i = sip->si_blkcnt; i > 1; i--) {
228 slp_next = (struct sp_link *)((caddr_t)(slp + 1) +
230 slp->sl_u.slu_next = slp_next;
233 slp->sl_u.slu_next = NULL;
237 * Add new chunk to end of pool
240 sip->si_poolt->sc_next = scp;
246 sip->si_total += sip->si_blkcnt;
247 sip->si_free += sip->si_blkcnt;
248 if (sip->si_chunks > sip->si_maxused)
249 sip->si_maxused = sip->si_chunks;
253 * Allocate the first free block in chunk
256 scp->sc_freeh = slp->sl_u.slu_next;
262 * Save link back to pool chunk
264 slp->sl_u.slu_chunk = scp;
269 KM_ZERO(bp, sip->si_blksiz);
277 * Free a Control Block
279 * Returns a previously allocated control block back to the owners
283 * bp pointer to block to be freed
293 struct sp_chunk *scp;
299 * Get containing chunk and pool info
301 slp = (struct sp_link *)bp;
303 scp = slp->sl_u.slu_chunk;
304 if (scp->sc_magic != SPOOL_MAGIC)
305 panic("atm_free: chunk magic missing");
309 * Add block to free chain
312 scp->sc_freet->sl_u.slu_next = slp;
315 scp->sc_freeh = scp->sc_freet = slp;
316 slp->sl_u.slu_next = NULL;
326 * Storage Pool Compaction
328 * Called periodically in order to perform compaction of the
329 * storage pools. Each pool will be checked to see if any chunks
330 * can be freed, taking some care to avoid freeing too many chunks
331 * in order to avoid memory thrashing.
333 * Called from a critical section.
336 * tip pointer to timer control block (atm_compactimer)
343 atm_compact(struct atm_time *tip)
346 struct sp_chunk *scp;
348 struct sp_chunk *scp_prev;
351 * Check out all storage pools
353 for (sip = atm_pool_head; sip; sip = sip->si_next) {
356 * Always keep a minimum number of chunks around
358 if (sip->si_chunks <= SPOOL_MIN_CHUNK)
362 * Maximum chunks to free at one time will leave
363 * pool with at least 50% utilization, but never
364 * go below minimum chunk count.
366 i = ((sip->si_free * 2) - sip->si_total) / sip->si_blkcnt;
367 i = MIN(i, sip->si_chunks - SPOOL_MIN_CHUNK);
370 * Look for chunks to free
373 for (scp = sip->si_poolh; scp && i > 0; ) {
375 if (scp->sc_used == 0) {
378 * Found a chunk to free, so do it
381 scp_prev->sc_next = scp->sc_next;
382 if (sip->si_poolt == scp)
383 sip->si_poolt = scp_prev;
385 sip->si_poolh = scp->sc_next;
387 KM_FREE((caddr_t)scp, sip->si_chunksiz,
391 * Update pool controls
394 sip->si_total -= sip->si_blkcnt;
395 sip->si_free -= sip->si_blkcnt;
398 scp = scp_prev->sc_next;
409 * Restart the compaction timer
411 atm_timeout(&atm_compactimer, SPOOL_COMPACT, atm_compact);
418 * Release a Storage Pool
420 * Frees all dynamic storage acquired for a storage pool.
421 * This function is normally called just prior to a module's unloading.
424 * sip pointer to sp_info for storage pool
431 atm_release_pool(struct sp_info *sip)
433 struct sp_chunk *scp, *scp_next;
437 * Free each chunk in pool
439 for (scp = sip->si_poolh; scp; scp = scp_next) {
442 * Check for memory leaks
445 panic("atm_release_pool: unfreed blocks");
447 scp_next = scp->sc_next;
449 KM_FREE((caddr_t)scp, sip->si_chunksiz, M_DEVBUF);
453 * Update pool controls
455 sip->si_poolh = NULL;
461 * Unlink pool from active chain
463 sip->si_chunksiz = 0;
464 UNLINK(sip, struct sp_info, atm_pool_head, si_next);
471 * Handle timer tick expiration
473 * Decrement tick count in first block on timer queue. If there
474 * are blocks with expired timers, call their timeout function.
475 * This function is called ATM_HZ times per second.
478 * arg argument passed on timeout() call
485 atm_timexp(void *arg)
487 struct atm_time *tip;
491 * Decrement tick count
493 if (((tip = atm_timeq) == NULL) || (--tip->ti_ticks > 0)) {
498 * Stack queue should have been drained
501 if (atm_stackq_head != NULL)
502 panic("atm_timexp: stack queue not empty");
506 * Dispatch expired timers
508 while (((tip = atm_timeq) != NULL) && (tip->ti_ticks == 0)) {
509 void (*func)(struct atm_time *);
512 * Remove expired block from queue
514 atm_timeq = tip->ti_next;
515 tip->ti_flag &= ~TIF_QUEUED;
518 * Call timeout handler (with network interrupts locked out)
524 * Drain any deferred calls
534 callout_reset(&atm_timexp_ch, hz / ATM_HZ, atm_timexp, NULL);
539 * Schedule a control block timeout
541 * Place the supplied timer control block on the timer queue. The
542 * function (func) will be called in 't' timer ticks with the
543 * control block address as its only argument. There are ATM_HZ
544 * timer ticks per second. The ticks value stored in each block is
545 * a delta of the number of ticks from the previous block in the queue.
546 * Thus, for each tick interval, only the first block in the queue
547 * needs to have its tick value decremented.
550 * tip pointer to timer control block
551 * t number of timer ticks until expiration
552 * func pointer to function to call at expiration
559 atm_timeout(struct atm_time *tip, int t, void (*func)(struct atm_time *))
561 struct atm_time *tip1, *tip2;
565 * Check for double queueing error
567 if (tip->ti_flag & TIF_QUEUED)
568 panic("atm_timeout: double queueing");
571 * Make sure we delay at least a little bit
577 * Find out where we belong on the queue
580 for (tip1 = NULL, tip2 = atm_timeq; tip2 && (tip2->ti_ticks <= t);
581 tip1 = tip2, tip2 = tip1->ti_next) {
586 * Place ourselves on queue and update timer deltas
600 tip->ti_flag |= TIF_QUEUED;
612 * Remove the supplied timer control block from the timer queue.
615 * tip pointer to timer control block
618 * 0 control block successfully dequeued
619 * 1 control block not on timer queue
623 atm_untimeout(struct atm_time *tip)
625 struct atm_time *tip1, *tip2;
628 * Is control block queued?
630 if ((tip->ti_flag & TIF_QUEUED) == 0)
634 * Find control block on the queue
637 for (tip1 = NULL, tip2 = atm_timeq; tip2 && (tip2 != tip);
638 tip1 = tip2, tip2 = tip1->ti_next) {
647 * Remove block from queue and update timer deltas
653 tip1->ti_next = tip2;
656 tip2->ti_ticks += tip->ti_ticks;
661 tip->ti_flag &= ~TIF_QUEUED;
671 * Queues a stack call which must be deferred to the global stack queue.
672 * The call parameters are stored in entries which are allocated from the
673 * stack queue storage pool.
677 * func destination function
678 * token destination layer's token
679 * cvp pointer to connection vcc
680 * arg1 command argument
681 * arg2 command argument
685 * errno call not queued - reason indicated
689 atm_stack_enq(int cmd, void (*func)(int, void *, int, int), void *token,
690 Atm_connvc *cvp, int arg1, int arg2)
692 struct stackq_entry *sqp;
697 * Get a new queue entry for this call
699 sqp = (struct stackq_entry *)atm_allocate(&atm_stackq_pool);
711 sqp->sq_token = token;
714 sqp->sq_connvc = cvp;
717 * Put new entry at end of queue
719 if (atm_stackq_head == NULL)
720 atm_stackq_head = sqp;
722 atm_stackq_tail->sq_next = sqp;
723 atm_stackq_tail = sqp;
731 * Drain the Stack Queue
733 * Dequeues and processes entries from the global stack queue.
743 atm_stack_drain(void)
745 struct stackq_entry *sqp, *qprev, *qnext;
750 * Loop thru entire queue until queue is empty
751 * (but panic rather loop forever)
756 for (sqp = atm_stackq_head; sqp; ) {
759 * Got an eligible entry, do STACK_CALL stuff
761 if (sqp->sq_cmd & STKCMD_UP) {
762 if (sqp->sq_connvc->cvc_downcnt) {
765 * Cant process now, skip it
773 * OK, dispatch the call
775 sqp->sq_connvc->cvc_upcnt++;
776 (*sqp->sq_func)(sqp->sq_cmd,
780 sqp->sq_connvc->cvc_upcnt--;
782 if (sqp->sq_connvc->cvc_upcnt) {
785 * Cant process now, skip it
793 * OK, dispatch the call
795 sqp->sq_connvc->cvc_downcnt++;
796 (*sqp->sq_func)(sqp->sq_cmd,
800 sqp->sq_connvc->cvc_downcnt--;
804 * Dequeue processed entry and free it
807 qnext = sqp->sq_next;
809 qprev->sq_next = qnext;
811 atm_stackq_head = qnext;
813 atm_stackq_tail = qprev;
814 atm_free((caddr_t)sqp);
820 * Make sure entire queue was drained
822 if (atm_stackq_head != NULL)
823 panic("atm_stack_drain: Queue not emptied");
829 * Process Interrupt Queue
831 * Processes entries on the ATM interrupt queue. This queue is used by
832 * device interface drivers in order to schedule events from the driver's
833 * lower (interrupt) half to the driver's stack services.
835 * The interrupt routines must store the stack processing function to call
836 * and a token (typically a driver/stack control block) at the front of the
837 * queued buffer. We assume that the function pointer and token values are
838 * both contained (and properly aligned) in the first buffer of the chain.
848 atm_intr(netmsg_t msg)
850 struct mbuf *m = msg->packet.nm_packet;
852 atm_intr_func_t func;
856 * Get function to call and token value
859 KB_DATASTART(m, cp, caddr_t);
860 func = *(atm_intr_func_t *)cp;
862 token = *(void **)cp;
863 KB_HEADADJ(m, -(sizeof(func) + sizeof(token)));
864 if (KB_LEN(m) == 0) {
866 KB_UNLINKHEAD(m, m1);
871 * Call processing function
876 * Drain any deferred calls
880 /* msg was embedded in the mbuf, do not reply! */
884 * Print a pdu buffer chain
887 * m pointer to pdu buffer chain
888 * msg pointer to message header string
895 atm_pdu_print(KBuffer *m, char *msg)
903 KB_DATASTART(m, cp, caddr_t);
904 kprintf("%cbfr=%p data=%p len=%d: ",
905 c, m, cp, KB_LEN(m));
907 if (atm_print_data) {
908 for (i = 0; i < KB_LEN(m); i++) {
909 kprintf("%2x ", (u_char)*cp++);
911 kprintf("<end_bfr>\n");