2 * ===================================
3 * HARP | Host ATM Research Platform
4 * ===================================
7 * This Host ATM Research Platform ("HARP") file (the "Software") is
8 * made available by Network Computing Services, Inc. ("NetworkCS")
9 * "AS IS". NetworkCS does not provide maintenance, improvements or
10 * support of any kind.
12 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
13 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
14 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
15 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
16 * In no event shall NetworkCS be responsible for any damages, including
17 * but not limited to consequential damages, arising from or relating to
18 * any use of the Software or related support.
20 * Copyright 1994-1998 Network Computing Services, Inc.
22 * Copies of this Software may be made, however, the above copyright
23 * notice must be reproduced on all copies.
30 * ATM device support functions
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/errno.h>
39 #include <sys/malloc.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/syslog.h>
46 #include <netatm/port.h>
47 #include <netatm/queue.h>
48 #include <netatm/atm.h>
49 #include <netatm/atm_sys.h>
50 #include <netatm/atm_sap.h>
51 #include <netatm/atm_cm.h>
52 #include <netatm/atm_if.h>
53 #include <netatm/atm_vc.h>
54 #include <netatm/atm_stack.h>
55 #include <netatm/atm_pcb.h>
56 #include <netatm/atm_var.h>
59 * Private structures for managing allocated kernel memory resources
61 * For each allocation of kernel memory, one Mem_ent will be used.
62 * The Mem_ent structures will be allocated in blocks inside of a
65 #define MEM_NMEMENT 10 /* How many Mem_ent's in a Mem_blk */
68 void *me_kaddr; /* Allocated memory address */
69 u_int me_ksize; /* Allocated memory length */
70 void *me_uaddr; /* Memory address returned to caller */
71 u_int me_flags; /* Flags (see below) */
73 typedef struct mem_ent Mem_ent;
78 #define MEF_NONCACHE 1 /* Memory is noncacheable */
82 struct mem_blk *mb_next; /* Next block in chain */
83 Mem_ent mb_mement[MEM_NMEMENT]; /* Allocated memory entries */
85 typedef struct mem_blk Mem_blk;
87 static Mem_blk *atm_mem_head = NULL;
89 static struct t_atm_cause atm_dev_cause = {
92 T_ATM_CAUSE_VPCI_VCI_ASSIGNMENT_FAILURE,
96 extern struct ifqueue atm_intrq;
99 * ATM Device Stack Instantiation
104 * ssp pointer to array of stack definition pointers
106 * ssp[0] points to upper layer's stack definition
107 * ssp[1] points to this layer's stack definition
108 * ssp[2] points to lower layer's stack definition
109 * cvcp pointer to connection vcc for this stack
112 * 0 instantiation successful
113 * err instantiation failed - reason indicated
117 atm_dev_inst(ssp, cvcp)
118 struct stack_defn **ssp;
121 Cmn_unit *cup = (Cmn_unit *)cvcp->cvc_attr.nif->nif_pif;
126 * Check to see if device has been initialized
128 if ((cup->cu_flags & CUF_INITED) == 0)
135 * Device driver is the lowest layer - no need to validate
139 * Validate PVC vpi.vci
141 if (cvcp->cvc_attr.called.addr.address_format == T_ATM_PVC_ADDR) {
143 * Look through existing circuits - return error if found
147 pp = (Atm_addr_pvc *)cvcp->cvc_attr.called.addr.address;
148 if (atm_dev_vcc_find(cup, ATM_PVC_GET_VPI(pp),
149 ATM_PVC_GET_VCI(pp), 0))
150 return ( EADDRINUSE );
154 * Validate our SAP type
156 switch ((*(ssp+1))->sd_sap) {
157 case SAP_CPCS_AAL3_4:
166 * Allocate a VCC control block
167 * This can happen from a callout so don't wait here.
169 cvp = uma_zalloc(cup->cu_vcc_zone, M_NOWAIT);
173 cvp->cv_state = CVS_INST;
174 cvp->cv_toku = (*ssp)->sd_toku;
175 cvp->cv_upper = (*ssp)->sd_upper;
176 cvp->cv_connvc = cvcp;
179 * Let device have a look at the connection request
181 err = (*cup->cu_instvcc)(cup, cvp);
183 uma_zfree(cup->cu_vcc_zone, cvp);
188 * Looks good so far, so link in device VCC
190 LINK2TAIL ( cvp, Cmn_vcc, cup->cu_vcc, cv_next );
195 (*++ssp)->sd_toku = cvp;
198 * Pass instantiation down the stack
201 * No need - we're the lowest point.
203 /* err = (*(ssp + 1))->sd_inst(ssp, cvcp); */
206 * Save the lower layer's interface info
209 * No need - we're the lowest point
211 /* cvp->cv_lower = (*++ssp)->sd_lower; */
212 /* cvp->cv_tok1 = (*ssp)->sd_toku; */
219 * ATM Device Stack Command Handler
222 * cmd stack command code
223 * tok session token (Cmn_vcc)
224 * arg1 command specific argument
225 * arg2 command specific argument
233 atm_dev_lower(cmd, tok, arg1, arg2)
239 Cmn_vcc *cvp = (Cmn_vcc *)tok;
240 Atm_connvc *cvcp = cvp->cv_connvc;
241 Cmn_unit *cup = (Cmn_unit *)cvcp->cvc_attr.nif->nif_pif;
252 if ( cvp->cv_state != CVS_INST ) {
254 "atm_dev_lower: INIT: tok=%p, state=%d\n",
255 tok, cvp->cv_state );
259 vcp = cvp->cv_connvc->cvc_vcc;
262 * Validate SVC vpi.vci
264 if ( vcp->vc_type & VCC_SVC ) {
266 if (atm_dev_vcc_find(cup, vcp->vc_vpi, vcp->vc_vci,
267 vcp->vc_type & (VCC_IN | VCC_OUT))
270 "atm_dev_lower: dup SVC (%d,%d) tok=%p\n",
271 vcp->vc_vpi, vcp->vc_vci, tok );
272 atm_cm_abort(cvp->cv_connvc, &atm_dev_cause);
278 * Tell the device to open the VCC
280 cvp->cv_state = CVS_INITED;
282 if ((*cup->cu_openvcc)(cup, cvp)) {
283 atm_cm_abort(cvp->cv_connvc, &atm_dev_cause);
291 KBuffer *m, *prev, *next;
297 * Disconnect the VCC - ignore return code
299 if ((cvp->cv_state == CVS_INITED) ||
300 (cvp->cv_state == CVS_ACTIVE)) {
301 (void) (*cup->cu_closevcc)(cup, cvp);
303 cvp->cv_state = CVS_TERM;
306 * Remove from interface list
308 UNLINK ( cvp, Cmn_vcc, cup->cu_vcc, cv_next );
311 * Free any buffers from this VCC on the ATM interrupt queue
315 for (m = atm_intrq.ifq_head; m; m = next) {
319 * See if this entry is for the terminating VCC
321 KB_DATASTART(m, ip, int *);
323 if (*ip == (intptr_t)cvp) {
325 * Yep, so dequeue the entry
328 atm_intrq.ifq_head = next;
330 KB_QNEXT(prev) = next;
333 atm_intrq.ifq_tail = prev;
338 * Free the unwanted buffers
345 IF_UNLOCK(&atm_intrq);
351 uma_zfree(cup->cu_vcc_zone, cvp);
355 case CPCS_UNITDATA_INV:
360 * Use temp state variable since we dont want to lock out
361 * interrupts, but initial VC activation interrupt may
362 * happen here, changing state somewhere in the middle.
364 state = cvp->cv_state;
365 if ((state != CVS_ACTIVE) &&
366 (state != CVS_INITED)) {
368 "atm_dev_lower: UNITDATA: tok=%p, state=%d\n",
370 KB_FREEALL((KBuffer *)arg1);
375 * Send the packet to the interface's bpf if this vc has one.
377 if (cvcp->cvc_vcc != NULL && cvcp->cvc_vcc->vc_nif != NULL) {
379 (struct ifnet *)cvcp->cvc_vcc->vc_nif;
381 BPF_MTAP(ifp, (KBuffer *)arg1);
385 * Hand the data off to the device
387 (*cup->cu_output)(cup, cvp, (KBuffer *)arg1);
391 case CPCS_UABORT_INV:
393 "atm_dev_lower: unimplemented stack cmd 0x%x, tok=%p\n",
399 "atm_dev_lower: unknown stack cmd 0x%x, tok=%p\n",
410 * Allocate kernel memory block
412 * This function will allocate a kernel memory block of the type specified
413 * in the flags parameter. The returned address will point to a memory
414 * block of the requested size and alignment. The memory block will also
415 * be zeroed. The alloc/free functions will manage/mask both the OS-specific
416 * kernel memory management requirements and the bookkeeping required to
417 * deal with data alignment issues.
419 * This function should not be called from interrupt level.
422 * size size of memory block to allocate
423 * align data alignment requirement
424 * flags allocation flags (ATM_DEV_*)
427 * uaddr pointer to aligned memory block
428 * NULL unable to allocate memory
432 atm_dev_alloc(size, align, flags)
445 * Find a free Mem_ent
448 for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) {
449 for (i = 0; i < MEM_NMEMENT; i++) {
450 if (mbp->mb_mement[i].me_uaddr == NULL) {
451 mep = &mbp->mb_mement[i];
458 * If there are no free Mem_ent's, then allocate a new Mem_blk
459 * and link it into the chain
462 mbp = malloc(sizeof(Mem_blk), M_DEVBUF, M_NOWAIT|M_ZERO);
464 log(LOG_ERR, "atm_dev_alloc: Mem_blk failure\n");
468 mbp->mb_next = atm_mem_head;
470 mep = mbp->mb_mement;
474 * Now we need to get the kernel's allocation alignment minimum
476 * This is obviously very OS-specific stuff
478 kalign = MINALLOCSIZE;
481 * Figure out how much memory we must allocate to satify the
482 * user's size and alignment needs
487 ksize = size + align - kalign;
490 * Finally, go get the memory
492 if (flags & ATM_DEV_NONCACHE) {
493 mep->me_kaddr = malloc(ksize, M_DEVBUF, M_NOWAIT);
495 mep->me_kaddr = malloc(ksize, M_DEVBUF, M_NOWAIT);
498 if (mep->me_kaddr == NULL) {
499 log(LOG_ERR, "atm_dev_alloc: %skernel memory unavailable\n",
500 (flags & ATM_DEV_NONCACHE) ? "non-cacheable " : "");
506 * Calculate correct alignment address to pass back to user
508 mep->me_uaddr = (void *) roundup((uintptr_t)mep->me_kaddr, align);
509 mep->me_ksize = ksize;
510 mep->me_flags = flags;
513 * Clear memory for user
515 bzero(mep->me_uaddr, size);
517 ATM_DEBUG4("atm_dev_alloc: size=%d, align=%d, flags=%d, uaddr=%p\n",
518 size, align, flags, mep->me_uaddr);
522 return (mep->me_uaddr);
527 * Free kernel memory block
529 * This function will free a kernel memory block previously allocated by
530 * the atm_dev_alloc function.
532 * This function should not be called from interrupt level.
535 * uaddr pointer to allocated aligned memory block
543 volatile void *uaddr;
549 ATM_DEBUG1("atm_dev_free: uaddr=%p\n", uaddr);
554 * Protect ourselves...
557 panic("atm_dev_free: trying to free null address");
560 * Find our associated entry
563 for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) {
564 for (i = 0; i < MEM_NMEMENT; i++) {
565 if (mbp->mb_mement[i].me_uaddr == uaddr) {
566 mep = &mbp->mb_mement[i];
573 * If we didn't find our entry, then unceremoniously let the caller
574 * know they screwed up (it certainly couldn't be a bug here...)
577 panic("atm_dev_free: trying to free unknown address");
580 * Give the memory space back to the kernel
582 if (mep->me_flags & ATM_DEV_NONCACHE) {
583 free(mep->me_kaddr, M_DEVBUF);
585 free(mep->me_kaddr, M_DEVBUF);
591 mep->me_uaddr = NULL;
599 * Compress buffer chain
601 * This function will compress a supplied buffer chain into a minimum number
602 * of kernel buffers. Typically, this function will be used because the
603 * number of buffers in an output buffer chain is too large for a device's
604 * DMA capabilities. This should only be called as a last resort, since
605 * all the data copying will surely kill any hopes of decent performance.
608 * m pointer to source buffer chain
611 * n pointer to compressed buffer chain
618 KBuffer *n, *n0, **np;
628 * Copy each source buffer into compressed chain
635 * Allocate another buffer for compressed chain
637 KB_ALLOCEXT(n, ATM_DEV_CMPR_LG, KB_F_NOWAIT, KB_T_DATA);
639 space = ATM_DEV_CMPR_LG;
641 KB_ALLOC(n, ATM_DEV_CMPR_SM, KB_F_NOWAIT,
644 space = ATM_DEV_CMPR_SM;
647 * Unable to get any new buffers, so
648 * just return the partially compressed
658 KB_BFRSTART(n, dst, caddr_t);
665 * Copy what we can from source buffer
667 len = MIN(space, KB_LEN(m));
668 KB_DATASTART(m, src, caddr_t);
669 bcopy(src, dst, len);
672 * Adjust for copied data
681 * If we've exhausted our current source buffer, free it
682 * and move to the next one
684 if (KB_LEN(m) == 0) {
696 * This function will return the VCC entry for a specified interface and
700 * cup pointer to interface unit structure
706 * vcp pointer to located VCC entry matching
711 atm_dev_vcc_find(cup, vpi, vci, type)
723 * (Probably should stick in a hash table some time)
725 for (cvp = cup->cu_vcc; cvp; cvp = cvp->cv_next) {
728 vcp = cvp->cv_connvc->cvc_vcc;
729 if ((vcp->vc_vci == vci) && (vcp->vc_vpi == vpi) &&
730 ((vcp->vc_type & type) == type))
741 * Module unloading notification
743 * This function must be called just prior to unloading the module from
744 * memory. All allocated memory will be freed here and anything else that
764 * Free up all of our memory management storage
766 while (mbp = atm_mem_head) {
769 * Make sure users have freed up all of their memory
771 for (i = 0; i < MEM_NMEMENT; i++) {
772 if (mbp->mb_mement[i].me_uaddr != NULL) {
773 panic("atm_unload: unfreed memory");
777 atm_mem_head = mbp->mb_next;
780 * Hand this block back to the kernel
782 free((caddr_t)mbp, M_DEVBUF);
796 * cup pointer to device unit
797 * cvp pointer to VCC control block
798 * m pointer to pdu buffer chain
799 * msg pointer to message string
806 atm_dev_pdu_print(const Cmn_unit *cup, const Cmn_vcc *cvp,
807 const KBuffer *m, const char *msg)
811 snprintf(buf, sizeof(buf), "%s vcc=(%d,%d)", msg,
812 cvp->cv_connvc->cvc_vcc->vc_vpi,
813 cvp->cv_connvc->cvc_vcc->vc_vci);
815 atm_pdu_print(m, buf);