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