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_device.c,v 1.5 1999/08/28 00:48:35 peter Exp $
27 * @(#) $DragonFly: src/sys/netproto/atm/atm_device.c,v 1.7 2005/06/02 22:37:45 dillon Exp $
34 * ATM device support functions
38 #include "kern_include.h"
41 * Private structures for managing allocated kernel memory resources
43 * For each allocation of kernel memory, one Mem_ent will be used.
44 * The Mem_ent structures will be allocated in blocks inside of a
47 #define MEM_NMEMENT 10 /* How many Mem_ent's in a Mem_blk */
50 void *me_kaddr; /* Allocated memory address */
51 u_int me_ksize; /* Allocated memory length */
52 void *me_uaddr; /* Memory address returned to caller */
53 u_int me_flags; /* Flags (see below) */
55 typedef struct mem_ent Mem_ent;
60 #define MEF_NONCACHE 1 /* Memory is noncacheable */
64 struct mem_blk *mb_next; /* Next block in chain */
65 Mem_ent mb_mement[MEM_NMEMENT]; /* Allocated memory entries */
67 typedef struct mem_blk Mem_blk;
69 static Mem_blk *atm_mem_head = NULL;
71 static struct t_atm_cause atm_dev_cause = {
74 T_ATM_CAUSE_VPCI_VCI_ASSIGNMENT_FAILURE,
80 * ATM Device Stack Instantiation
82 * Called from a critical section.
85 * ssp pointer to array of stack definition pointers
87 * ssp[0] points to upper layer's stack definition
88 * ssp[1] points to this layer's stack definition
89 * ssp[2] points to lower layer's stack definition
90 * cvcp pointer to connection vcc for this stack
93 * 0 instantiation successful
94 * err instantiation failed - reason indicated
98 atm_dev_inst(ssp, cvcp)
99 struct stack_defn **ssp;
102 Cmn_unit *cup = (Cmn_unit *)cvcp->cvc_attr.nif->nif_pif;
107 * Check to see if device has been initialized
109 if ((cup->cu_flags & CUF_INITED) == 0)
116 * Device driver is the lowest layer - no need to validate
120 * Validate PVC vpi.vci
122 if (cvcp->cvc_attr.called.addr.address_format == T_ATM_PVC_ADDR) {
124 * Look through existing circuits - return error if found
128 pp = (Atm_addr_pvc *)cvcp->cvc_attr.called.addr.address;
129 if (atm_dev_vcc_find(cup, ATM_PVC_GET_VPI(pp),
130 ATM_PVC_GET_VCI(pp), 0))
131 return ( EADDRINUSE );
135 * Validate our SAP type
137 switch ((*(ssp+1))->sd_sap) {
138 case SAP_CPCS_AAL3_4:
147 * Allocate a VCC control block
149 if ( ( cvp = (Cmn_vcc *)atm_allocate(cup->cu_vcc_pool) ) == NULL )
152 cvp->cv_state = CVS_INST;
153 cvp->cv_toku = (*ssp)->sd_toku;
154 cvp->cv_upper = (*ssp)->sd_upper;
155 cvp->cv_connvc = cvcp;
158 * Let device have a look at the connection request
160 err = (*cup->cu_instvcc)(cup, cvp);
162 atm_free((caddr_t)cvp);
167 * Looks good so far, so link in device VCC
169 LINK2TAIL ( cvp, Cmn_vcc, cup->cu_vcc, cv_next );
174 (*++ssp)->sd_toku = cvp;
177 * Pass instantiation down the stack
180 * No need - we're the lowest point.
182 /* err = (*(ssp + 1))->sd_inst(ssp, cvcp); */
185 * Save the lower layer's interface info
188 * No need - we're the lowest point
190 /* cvp->cv_lower = (*++ssp)->sd_lower; */
191 /* cvp->cv_tok1 = (*ssp)->sd_toku; */
198 * ATM Device Stack Command Handler
201 * cmd stack command code
202 * tok session token (Cmn_vcc)
203 * arg1 command specific argument
204 * arg2 command specific argument
212 atm_dev_lower(cmd, tok, arg1, arg2)
218 Cmn_vcc *cvp = (Cmn_vcc *)tok;
219 Atm_connvc *cvcp = cvp->cv_connvc;
220 Cmn_unit *cup = (Cmn_unit *)cvcp->cvc_attr.nif->nif_pif;
230 if ( cvp->cv_state != CVS_INST ) {
232 "atm_dev_lower: INIT: tok=%p, state=%d\n",
233 tok, cvp->cv_state );
237 vcp = cvp->cv_connvc->cvc_vcc;
240 * Validate SVC vpi.vci
242 if ( vcp->vc_type & VCC_SVC ) {
244 if (atm_dev_vcc_find(cup, vcp->vc_vpi, vcp->vc_vci,
245 vcp->vc_type & (VCC_IN | VCC_OUT))
248 "atm_dev_lower: dup SVC (%d,%d) tok=%p\n",
249 vcp->vc_vpi, vcp->vc_vci, tok );
250 atm_cm_abort(cvp->cv_connvc, &atm_dev_cause);
256 * Tell the device to open the VCC
258 cvp->cv_state = CVS_INITED;
260 if ((*cup->cu_openvcc)(cup, cvp)) {
261 atm_cm_abort(cvp->cv_connvc, &atm_dev_cause);
269 KBuffer *m, *prev, *next;
275 * Disconnect the VCC - ignore return code
277 if ((cvp->cv_state == CVS_INITED) ||
278 (cvp->cv_state == CVS_ACTIVE)) {
279 (void) (*cup->cu_closevcc)(cup, cvp);
281 cvp->cv_state = CVS_TERM;
284 * Remove from interface list
286 UNLINK ( cvp, Cmn_vcc, cup->cu_vcc, cv_next );
289 * Free any buffers from this VCC on the ATM interrupt queue
292 for (m = atm_intrq.ifq_head; m; m = next) {
296 * See if this entry is for the terminating VCC
298 KB_DATASTART(m, ip, int *);
300 if (*ip == (int)cvp) {
302 * Yep, so dequeue the entry
305 atm_intrq.ifq_head = next;
307 KB_QNEXT(prev) = next;
310 atm_intrq.ifq_tail = prev;
315 * Free the unwanted buffers
327 (void) atm_free((caddr_t)cvp);
331 case CPCS_UNITDATA_INV:
336 * Use temp state variable since we dont want to lock out
337 * interrupts, but initial VC activation interrupt may
338 * happen here, changing state somewhere in the middle.
340 state = cvp->cv_state;
341 if ((state != CVS_ACTIVE) &&
342 (state != CVS_INITED)) {
344 "atm_dev_lower: UNITDATA: tok=%p, state=%d\n",
346 KB_FREEALL((KBuffer *)arg1);
351 * Hand the data off to the device
353 (*cup->cu_output)(cup, cvp, (KBuffer *)arg1);
357 case CPCS_UABORT_INV:
359 "atm_dev_lower: unimplemented stack cmd 0x%x, tok=%p\n",
365 "atm_dev_lower: unknown stack cmd 0x%x, tok=%p\n",
376 * Allocate kernel memory block
378 * This function will allocate a kernel memory block of the type specified
379 * in the flags parameter. The returned address will point to a memory
380 * block of the requested size and alignment. The memory block will also
381 * be zeroed. The alloc/free functions will manage/mask both the OS-specific
382 * kernel memory management requirements and the bookkeeping required to
383 * deal with data alignment issues.
385 * This function should not be called from interrupt level.
388 * size size of memory block to allocate
389 * align data alignment requirement
390 * flags allocation flags (ATM_DEV_*)
393 * uaddr pointer to aligned memory block
394 * NULL unable to allocate memory
398 atm_dev_alloc(size, align, flags)
411 * Find a free Mem_ent
414 for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) {
415 for (i = 0; i < MEM_NMEMENT; i++) {
416 if (mbp->mb_mement[i].me_uaddr == NULL) {
417 mep = &mbp->mb_mement[i];
424 * If there are no free Mem_ent's, then allocate a new Mem_blk
425 * and link it into the chain
428 mbp = KM_ALLOC(sizeof(Mem_blk), M_DEVBUF,
429 M_INTWAIT | M_NULLOK);
431 log(LOG_ERR, "atm_dev_alloc: Mem_blk failure\n");
435 KM_ZERO(mbp, sizeof(Mem_blk));
437 mbp->mb_next = atm_mem_head;
439 mep = mbp->mb_mement;
443 * Now we need to get the kernel's allocation alignment minimum
445 * This is obviously very OS-specific stuff
447 kalign = MINALLOCSIZE;
450 * Figure out how much memory we must allocate to satify the
451 * user's size and alignment needs
456 ksize = size + align - kalign;
459 * Finally, go get the memory
461 if (flags & ATM_DEV_NONCACHE) {
462 mep->me_kaddr = KM_ALLOC(ksize, M_DEVBUF, M_INTWAIT | M_NULLOK);
464 mep->me_kaddr = KM_ALLOC(ksize, M_DEVBUF, M_INTWAIT | M_NULLOK);
467 if (mep->me_kaddr == NULL) {
468 log(LOG_ERR, "atm_dev_alloc: %skernel memory unavailable\n",
469 (flags & ATM_DEV_NONCACHE) ? "non-cacheable " : "");
475 * Calculate correct alignment address to pass back to user
477 mep->me_uaddr = (void *) roundup((u_int)mep->me_kaddr, align);
478 mep->me_ksize = ksize;
479 mep->me_flags = flags;
482 * Clear memory for user
484 KM_ZERO(mep->me_uaddr, size);
486 ATM_DEBUG4("atm_dev_alloc: size=%d, align=%d, flags=%d, uaddr=%p\n",
487 size, align, flags, mep->me_uaddr);
491 return (mep->me_uaddr);
496 * Free kernel memory block
498 * This function will free a kernel memory block previously allocated by
499 * the atm_dev_alloc function.
501 * This function should not be called from interrupt level.
504 * uaddr pointer to allocated aligned memory block
511 atm_dev_free(volatile void *uaddr)
517 ATM_DEBUG1("atm_dev_free: uaddr=%p\n", uaddr);
522 * Protect ourselves...
525 panic("atm_dev_free: trying to free null address");
528 * Find our associated entry
531 for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) {
532 for (i = 0; i < MEM_NMEMENT; i++) {
533 if (mbp->mb_mement[i].me_uaddr == uaddr) {
534 mep = &mbp->mb_mement[i];
541 * If we didn't find our entry, then unceremoniously let the caller
542 * know they screwed up (it certainly couldn't be a bug here...)
545 panic("atm_dev_free: trying to free unknown address");
548 * Give the memory space back to the kernel
550 if (mep->me_flags & ATM_DEV_NONCACHE) {
551 KM_FREE(mep->me_kaddr, mep->me_ksize, M_DEVBUF);
553 KM_FREE(mep->me_kaddr, mep->me_ksize, M_DEVBUF);
559 mep->me_uaddr = NULL;
567 * Compress buffer chain
569 * This function will compress a supplied buffer chain into a minimum number
570 * of kernel buffers. Typically, this function will be used because the
571 * number of buffers in an output buffer chain is too large for a device's
572 * DMA capabilities. This should only be called as a last resort, since
573 * all the data copying will surely kill any hopes of decent performance.
576 * m pointer to source buffer chain
579 * n pointer to compressed buffer chain
586 KBuffer *n, *n0, **np;
596 * Copy each source buffer into compressed chain
603 * Allocate another buffer for compressed chain
605 KB_ALLOCEXT(n, ATM_DEV_CMPR_LG, KB_F_NOWAIT, KB_T_DATA);
607 space = ATM_DEV_CMPR_LG;
609 KB_ALLOC(n, ATM_DEV_CMPR_SM, KB_F_NOWAIT,
612 space = ATM_DEV_CMPR_SM;
615 * Unable to get any new buffers, so
616 * just return the partially compressed
626 KB_BFRSTART(n, dst, caddr_t);
633 * Copy what we can from source buffer
635 len = MIN(space, KB_LEN(m));
636 KB_DATASTART(m, src, caddr_t);
637 KM_COPY(src, dst, len);
640 * Adjust for copied data
649 * If we've exhausted our current source buffer, free it
650 * and move to the next one
652 if (KB_LEN(m) == 0) {
664 * This function will return the VCC entry for a specified interface and
668 * cup pointer to interface unit structure
674 * vcp pointer to located VCC entry matching
679 atm_dev_vcc_find(cup, vpi, vci, type)
691 * (Probably should stick in a hash table some time)
693 for (cvp = cup->cu_vcc; cvp; cvp = cvp->cv_next) {
696 vcp = cvp->cv_connvc->cvc_vcc;
697 if ((vcp->vc_vci == vci) && (vcp->vc_vpi == vpi) &&
698 ((vcp->vc_type & type) == type))
708 * Module unloading notification
710 * This function must be called just prior to unloading the module from
711 * memory. All allocated memory will be freed here and anything else that
731 * Free up all of our memory management storage
733 while (mbp = atm_mem_head) {
736 * Make sure users have freed up all of their memory
738 for (i = 0; i < MEM_NMEMENT; i++) {
739 if (mbp->mb_mement[i].me_uaddr != NULL) {
740 panic("atm_unload: unfreed memory");
744 atm_mem_head = mbp->mb_next;
747 * Hand this block back to the kernel
749 KM_FREE((caddr_t) mbp, sizeof(Mem_blk), M_DEVBUF);
763 * cup pointer to device unit
764 * cvp pointer to VCC control block
765 * m pointer to pdu buffer chain
766 * msg pointer to message string
773 atm_dev_pdu_print(cup, cvp, m, msg)
781 snprintf(buf, sizeof(buf), "%s vcc=(%d,%d)", msg,
782 cvp->cv_connvc->cvc_vcc->vc_vpi,
783 cvp->cv_connvc->cvc_vcc->vc_vci);
785 atm_pdu_print(m, buf);