FreeBSD/Linux Kernel Cross Reference
sys/netatm/atm_subr.c
1 /*
2 *
3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
6 *
7 *
8 * This Host ATM Research Platform ("HARP") file (the "Software") is
9 * made available by Network Computing Services, Inc. ("NetworkCS")
10 * "AS IS". NetworkCS does not provide maintenance, improvements or
11 * support of any kind.
12 *
13 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17 * In no event shall NetworkCS be responsible for any damages, including
18 * but not limited to consequential damages, arising from or relating to
19 * any use of the Software or related support.
20 *
21 * Copyright 1994-1998 Network Computing Services, Inc.
22 *
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
25 *
26 * @(#) $FreeBSD: releng/5.0/sys/netatm/atm_subr.c 106651 2002-11-08 18:27:30Z jhb $
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/systm.h>
40 #include <sys/errno.h>
41 #include <sys/malloc.h>
42 #include <sys/time.h>
43 #include <sys/kernel.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <net/if.h>
47 #include <net/netisr.h>
48 #include <net/intrq.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_stack.h>
57 #include <netatm/atm_pcb.h>
58 #include <netatm/atm_var.h>
59 #include <vm/uma.h>
60
61 #ifndef lint
62 __RCSID("@(#) $FreeBSD: releng/5.0/sys/netatm/atm_subr.c 106651 2002-11-08 18:27:30Z jhb $");
63 #endif
64
65
66 /*
67 * Global variables
68 */
69 struct atm_pif *atm_interface_head = NULL;
70 struct atm_ncm *atm_netconv_head = NULL;
71 Atm_endpoint *atm_endpoints[ENDPT_MAX+1] = {NULL};
72 struct stackq_entry *atm_stackq_head = NULL, *atm_stackq_tail;
73 struct atm_sock_stat atm_sock_stat = { { 0 } };
74 int atm_init = 0;
75 int atm_debug = 0;
76 int atm_dev_print = 0;
77 int atm_print_data = 0;
78 int atm_version = ATM_VERSION;
79 struct timeval atm_debugtime = {0, 0};
80
81 uma_zone_t atm_attributes_zone;
82
83 /*
84 * Local functions
85 */
86 static KTimeout_ret atm_timexp(void *);
87
88 /*
89 * Local variables
90 */
91 static struct atm_time *atm_timeq = NULL;
92 static uma_zone_t atm_stackq_zone;
93
94 /*
95 * Initialize ATM kernel
96 *
97 * Performs any initialization required before things really get underway.
98 * Called from ATM domain initialization or from first registration function
99 * which gets called.
100 *
101 * Arguments:
102 * none
103 *
104 * Returns:
105 * none
106 *
107 */
108 void
109 atm_initialize()
110 {
111 /*
112 * Never called from interrupts, so no locking needed
113 */
114 if (atm_init)
115 return;
116 atm_init = 1;
117
118 atm_intrq.ifq_maxlen = ATM_INTRQ_MAX;
119 mtx_init(&atm_intrq.ifq_mtx, "atm_inq", NULL, MTX_DEF);
120 atmintrq_present = 1;
121
122 atm_attributes_zone = uma_zcreate("atm attributes",
123 sizeof(Atm_attributes), NULL, NULL, NULL, NULL,
124 UMA_ALIGN_PTR, 0);
125 if (atm_attributes_zone == NULL)
126 panic("atm_initialize: unable to create attributes zone");
127 uma_zone_set_max(atm_attributes_zone, 100);
128
129 atm_stackq_zone = uma_zcreate("atm stackq", sizeof(struct stackq_entry),
130 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
131 if (atm_stackq_zone == NULL)
132 panic("atm_initialize: unable to create stackq zone");
133 uma_zone_set_max(atm_stackq_zone, 10);
134
135 register_netisr(NETISR_ATM, atm_intr);
136
137 /*
138 * Initialize subsystems
139 */
140 atm_sock_init();
141 atm_cm_init();
142 atm_aal5_init();
143
144 /*
145 * Prime the timer
146 */
147 (void)timeout(atm_timexp, (void *)0, hz/ATM_HZ);
148 }
149
150
151 /*
152 * Handle timer tick expiration
153 *
154 * Decrement tick count in first block on timer queue. If there
155 * are blocks with expired timers, call their timeout function.
156 * This function is called ATM_HZ times per second.
157 *
158 * Arguments:
159 * arg argument passed on timeout() call
160 *
161 * Returns:
162 * none
163 *
164 */
165 static KTimeout_ret
166 atm_timexp(arg)
167 void *arg;
168 {
169 struct atm_time *tip;
170 int s = splimp();
171
172
173 /*
174 * Decrement tick count
175 */
176 if (((tip = atm_timeq) == NULL) || (--tip->ti_ticks > 0)) {
177 goto restart;
178 }
179
180 /*
181 * Stack queue should have been drained
182 */
183 KASSERT(atm_stackq_head == NULL, ("atm_timexp: stack queue not empty"));
184
185 /*
186 * Dispatch expired timers
187 */
188 while (((tip = atm_timeq) != NULL) && (tip->ti_ticks == 0)) {
189 void (*func)(struct atm_time *);
190
191 /*
192 * Remove expired block from queue
193 */
194 atm_timeq = tip->ti_next;
195 tip->ti_flag &= ~TIF_QUEUED;
196
197 /*
198 * Call timeout handler (with network interrupts locked out)
199 */
200 func = tip->ti_func;
201 (void) splx(s);
202 s = splnet();
203 (*func)(tip);
204 (void) splx(s);
205 s = splimp();
206
207 /*
208 * Drain any deferred calls
209 */
210 STACK_DRAIN();
211 }
212
213 restart:
214 /*
215 * Restart the timer
216 */
217 (void) splx(s);
218 (void) timeout(atm_timexp, (void *)0, hz/ATM_HZ);
219
220 return;
221 }
222
223
224 /*
225 * Schedule a control block timeout
226 *
227 * Place the supplied timer control block on the timer queue. The
228 * function (func) will be called in 't' timer ticks with the
229 * control block address as its only argument. There are ATM_HZ
230 * timer ticks per second. The ticks value stored in each block is
231 * a delta of the number of ticks from the previous block in the queue.
232 * Thus, for each tick interval, only the first block in the queue
233 * needs to have its tick value decremented.
234 *
235 * Arguments:
236 * tip pointer to timer control block
237 * t number of timer ticks until expiration
238 * func pointer to function to call at expiration
239 *
240 * Returns:
241 * none
242 *
243 */
244 void
245 atm_timeout(tip, t, func)
246 struct atm_time *tip;
247 int t;
248 void (*func)(struct atm_time *);
249 {
250 struct atm_time *tip1, *tip2;
251 int s;
252
253
254 /*
255 * Check for double queueing error
256 */
257 if (tip->ti_flag & TIF_QUEUED)
258 panic("atm_timeout: double queueing");
259
260 /*
261 * Make sure we delay at least a little bit
262 */
263 if (t <= 0)
264 t = 1;
265
266 /*
267 * Find out where we belong on the queue
268 */
269 s = splimp();
270 for (tip1 = NULL, tip2 = atm_timeq; tip2 && (tip2->ti_ticks <= t);
271 tip1 = tip2, tip2 = tip1->ti_next) {
272 t -= tip2->ti_ticks;
273 }
274
275 /*
276 * Place ourselves on queue and update timer deltas
277 */
278 if (tip1 == NULL)
279 atm_timeq = tip;
280 else
281 tip1->ti_next = tip;
282 tip->ti_next = tip2;
283
284 if (tip2)
285 tip2->ti_ticks -= t;
286
287 /*
288 * Setup timer block
289 */
290 tip->ti_flag |= TIF_QUEUED;
291 tip->ti_ticks = t;
292 tip->ti_func = func;
293
294 (void) splx(s);
295 return;
296 }
297
298
299 /*
300 * Cancel a timeout
301 *
302 * Remove the supplied timer control block from the timer queue.
303 *
304 * Arguments:
305 * tip pointer to timer control block
306 *
307 * Returns:
308 * 0 control block successfully dequeued
309 * 1 control block not on timer queue
310 *
311 */
312 int
313 atm_untimeout(tip)
314 struct atm_time *tip;
315 {
316 struct atm_time *tip1, *tip2;
317 int s;
318
319 /*
320 * Is control block queued?
321 */
322 if ((tip->ti_flag & TIF_QUEUED) == 0)
323 return(1);
324
325 /*
326 * Find control block on the queue
327 */
328 s = splimp();
329 for (tip1 = NULL, tip2 = atm_timeq; tip2 && (tip2 != tip);
330 tip1 = tip2, tip2 = tip1->ti_next) {
331 }
332
333 if (tip2 == NULL) {
334 (void) splx(s);
335 return (1);
336 }
337
338 /*
339 * Remove block from queue and update timer deltas
340 */
341 tip2 = tip->ti_next;
342 if (tip1 == NULL)
343 atm_timeq = tip2;
344 else
345 tip1->ti_next = tip2;
346
347 if (tip2)
348 tip2->ti_ticks += tip->ti_ticks;
349
350 /*
351 * Reset timer block
352 */
353 tip->ti_flag &= ~TIF_QUEUED;
354
355 (void) splx(s);
356 return (0);
357 }
358
359
360 /*
361 * Queue a Stack Call
362 *
363 * Queues a stack call which must be deferred to the global stack queue.
364 * The call parameters are stored in entries which are allocated from the
365 * stack queue storage pool.
366 *
367 * Arguments:
368 * cmd stack command
369 * func destination function
370 * token destination layer's token
371 * cvp pointer to connection vcc
372 * arg1 command argument
373 * arg2 command argument
374 *
375 * Returns:
376 * 0 call queued
377 * errno call not queued - reason indicated
378 *
379 */
380 int
381 atm_stack_enq(cmd, func, token, cvp, arg1, arg2)
382 int cmd;
383 void (*func)(int, void *, intptr_t, intptr_t);
384 void *token;
385 Atm_connvc *cvp;
386 intptr_t arg1;
387 intptr_t arg2;
388 {
389 struct stackq_entry *sqp;
390 int s = splnet();
391
392 /*
393 * Get a new queue entry for this call
394 */
395 sqp = uma_zalloc(atm_stackq_zone, M_ZERO);
396 if (sqp == NULL) {
397 (void) splx(s);
398 return (ENOMEM);
399 }
400
401 /*
402 * Fill in new entry
403 */
404 sqp->sq_next = NULL;
405 sqp->sq_cmd = cmd;
406 sqp->sq_func = func;
407 sqp->sq_token = token;
408 sqp->sq_arg1 = arg1;
409 sqp->sq_arg2 = arg2;
410 sqp->sq_connvc = cvp;
411
412 /*
413 * Put new entry at end of queue
414 */
415 if (atm_stackq_head == NULL)
416 atm_stackq_head = sqp;
417 else
418 atm_stackq_tail->sq_next = sqp;
419 atm_stackq_tail = sqp;
420
421 (void) splx(s);
422 return (0);
423 }
424
425
426 /*
427 * Drain the Stack Queue
428 *
429 * Dequeues and processes entries from the global stack queue.
430 *
431 * Arguments:
432 * none
433 *
434 * Returns:
435 * none
436 *
437 */
438 void
439 atm_stack_drain()
440 {
441 struct stackq_entry *sqp, *qprev, *qnext;
442 int s = splnet();
443 int cnt;
444
445 /*
446 * Loop thru entire queue until queue is empty
447 * (but panic rather loop forever)
448 */
449 do {
450 cnt = 0;
451 qprev = NULL;
452 for (sqp = atm_stackq_head; sqp; ) {
453
454 /*
455 * Got an eligible entry, do STACK_CALL stuff
456 */
457 if (sqp->sq_cmd & STKCMD_UP) {
458 if (sqp->sq_connvc->cvc_downcnt) {
459
460 /*
461 * Cant process now, skip it
462 */
463 qprev = sqp;
464 sqp = sqp->sq_next;
465 continue;
466 }
467
468 /*
469 * OK, dispatch the call
470 */
471 sqp->sq_connvc->cvc_upcnt++;
472 (*sqp->sq_func)(sqp->sq_cmd,
473 sqp->sq_token,
474 sqp->sq_arg1,
475 sqp->sq_arg2);
476 sqp->sq_connvc->cvc_upcnt--;
477 } else {
478 if (sqp->sq_connvc->cvc_upcnt) {
479
480 /*
481 * Cant process now, skip it
482 */
483 qprev = sqp;
484 sqp = sqp->sq_next;
485 continue;
486 }
487
488 /*
489 * OK, dispatch the call
490 */
491 sqp->sq_connvc->cvc_downcnt++;
492 (*sqp->sq_func)(sqp->sq_cmd,
493 sqp->sq_token,
494 sqp->sq_arg1,
495 sqp->sq_arg2);
496 sqp->sq_connvc->cvc_downcnt--;
497 }
498
499 /*
500 * Dequeue processed entry and free it
501 */
502 cnt++;
503 qnext = sqp->sq_next;
504 if (qprev)
505 qprev->sq_next = qnext;
506 else
507 atm_stackq_head = qnext;
508 if (qnext == NULL)
509 atm_stackq_tail = qprev;
510 uma_zfree(atm_stackq_zone, sqp);
511 sqp = qnext;
512 }
513 } while (cnt > 0);
514
515 /*
516 * Make sure entire queue was drained
517 */
518 if (atm_stackq_head != NULL)
519 panic("atm_stack_drain: Queue not emptied");
520
521 (void) splx(s);
522 }
523
524
525 /*
526 * Process Interrupt Queue
527 *
528 * Processes entries on the ATM interrupt queue. This queue is used by
529 * device interface drivers in order to schedule events from the driver's
530 * lower (interrupt) half to the driver's stack services.
531 *
532 * The interrupt routines must store the stack processing function to call
533 * and a token (typically a driver/stack control block) at the front of the
534 * queued buffer. We assume that the function pointer and token values are
535 * both contained (and properly aligned) in the first buffer of the chain.
536 *
537 * Arguments:
538 * none
539 *
540 * Returns:
541 * none
542 *
543 */
544 void
545 atm_intr()
546 {
547 KBuffer *m;
548 caddr_t cp;
549 atm_intr_func_t func;
550 void *token;
551 int s;
552
553 for (; ; ) {
554 /*
555 * Get next buffer from queue
556 */
557 s = splimp();
558 IF_DEQUEUE(&atm_intrq, m);
559 (void) splx(s);
560 if (m == NULL)
561 break;
562
563 /*
564 * Get function to call and token value
565 */
566 KB_DATASTART(m, cp, caddr_t);
567 func = *(atm_intr_func_t *)cp;
568 cp += sizeof(func);
569 token = *(void **)cp;
570 KB_HEADADJ(m, -(sizeof(func) + sizeof(token)));
571 if (KB_LEN(m) == 0) {
572 KBuffer *m1;
573 KB_UNLINKHEAD(m, m1);
574 m = m1;
575 }
576
577 /*
578 * Call processing function
579 */
580 (*func)(token, m);
581
582 /*
583 * Drain any deferred calls
584 */
585 STACK_DRAIN();
586 }
587 }
588
589
590 /*
591 * Print a pdu buffer chain
592 *
593 * Arguments:
594 * m pointer to pdu buffer chain
595 * msg pointer to message header string
596 *
597 * Returns:
598 * none
599 *
600 */
601 void
602 atm_pdu_print(m, msg)
603 KBuffer *m;
604 char *msg;
605 {
606 caddr_t cp;
607 int i;
608 char c = ' ';
609
610 printf("%s:", msg);
611 while (m) {
612 KB_DATASTART(m, cp, caddr_t);
613 printf("%cbfr=%p data=%p len=%d: ",
614 c, m, cp, KB_LEN(m));
615 c = '\t';
616 if (atm_print_data) {
617 for (i = 0; i < KB_LEN(m); i++) {
618 printf("%2x ", (u_char)*cp++);
619 }
620 printf("<end_bfr>\n");
621 } else {
622 printf("\n");
623 }
624 m = KB_NEXT(m);
625 }
626 }
627
Cache object: 0d9d05cb960a17d593257cafef548175
|