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.9 2006/12/20 18:14:43 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(struct stack_defn
**ssp
, Atm_connvc
*cvcp
)
100 Cmn_unit
*cup
= (Cmn_unit
*)cvcp
->cvc_attr
.nif
->nif_pif
;
105 * Check to see if device has been initialized
107 if ((cup
->cu_flags
& CUF_INITED
) == 0)
114 * Device driver is the lowest layer - no need to validate
118 * Validate PVC vpi.vci
120 if (cvcp
->cvc_attr
.called
.addr
.address_format
== T_ATM_PVC_ADDR
) {
122 * Look through existing circuits - return error if found
126 pp
= (Atm_addr_pvc
*)cvcp
->cvc_attr
.called
.addr
.address
;
127 if (atm_dev_vcc_find(cup
, ATM_PVC_GET_VPI(pp
),
128 ATM_PVC_GET_VCI(pp
), 0))
129 return ( EADDRINUSE
);
133 * Validate our SAP type
135 switch ((*(ssp
+1))->sd_sap
) {
136 case SAP_CPCS_AAL3_4
:
145 * Allocate a VCC control block
147 if ( ( cvp
= (Cmn_vcc
*)atm_allocate(cup
->cu_vcc_pool
) ) == NULL
)
150 cvp
->cv_state
= CVS_INST
;
151 cvp
->cv_toku
= (*ssp
)->sd_toku
;
152 cvp
->cv_upper
= (*ssp
)->sd_upper
;
153 cvp
->cv_connvc
= cvcp
;
156 * Let device have a look at the connection request
158 err
= (*cup
->cu_instvcc
)(cup
, cvp
);
160 atm_free((caddr_t
)cvp
);
165 * Looks good so far, so link in device VCC
167 LINK2TAIL ( cvp
, Cmn_vcc
, cup
->cu_vcc
, cv_next
);
172 (*++ssp
)->sd_toku
= cvp
;
175 * Pass instantiation down the stack
178 * No need - we're the lowest point.
180 /* err = (*(ssp + 1))->sd_inst(ssp, cvcp); */
183 * Save the lower layer's interface info
186 * No need - we're the lowest point
188 /* cvp->cv_lower = (*++ssp)->sd_lower; */
189 /* cvp->cv_tok1 = (*ssp)->sd_toku; */
196 * ATM Device Stack Command Handler
199 * cmd stack command code
200 * tok session token (Cmn_vcc)
201 * arg1 command specific argument
202 * arg2 command specific argument
210 atm_dev_lower(int cmd
, void *tok
, int arg1
, int arg2
)
212 Cmn_vcc
*cvp
= (Cmn_vcc
*)tok
;
213 Atm_connvc
*cvcp
= cvp
->cv_connvc
;
214 Cmn_unit
*cup
= (Cmn_unit
*)cvcp
->cvc_attr
.nif
->nif_pif
;
224 if ( cvp
->cv_state
!= CVS_INST
) {
226 "atm_dev_lower: INIT: tok=%p, state=%d\n",
227 tok
, cvp
->cv_state
);
231 vcp
= cvp
->cv_connvc
->cvc_vcc
;
234 * Validate SVC vpi.vci
236 if ( vcp
->vc_type
& VCC_SVC
) {
238 if (atm_dev_vcc_find(cup
, vcp
->vc_vpi
, vcp
->vc_vci
,
239 vcp
->vc_type
& (VCC_IN
| VCC_OUT
))
242 "atm_dev_lower: dup SVC (%d,%d) tok=%p\n",
243 vcp
->vc_vpi
, vcp
->vc_vci
, tok
);
244 atm_cm_abort(cvp
->cv_connvc
, &atm_dev_cause
);
250 * Tell the device to open the VCC
252 cvp
->cv_state
= CVS_INITED
;
254 if ((*cup
->cu_openvcc
)(cup
, cvp
)) {
255 atm_cm_abort(cvp
->cv_connvc
, &atm_dev_cause
);
263 KBuffer
*m
, *prev
, *next
;
269 * Disconnect the VCC - ignore return code
271 if ((cvp
->cv_state
== CVS_INITED
) ||
272 (cvp
->cv_state
== CVS_ACTIVE
)) {
273 (*cup
->cu_closevcc
)(cup
, cvp
);
275 cvp
->cv_state
= CVS_TERM
;
278 * Remove from interface list
280 UNLINK ( cvp
, Cmn_vcc
, cup
->cu_vcc
, cv_next
);
283 * Free any buffers from this VCC on the ATM interrupt queue
286 for (m
= atm_intrq
.ifq_head
; m
; m
= next
) {
290 * See if this entry is for the terminating VCC
292 KB_DATASTART(m
, ip
, int *);
294 if (*ip
== (int)cvp
) {
296 * Yep, so dequeue the entry
299 atm_intrq
.ifq_head
= next
;
301 KB_QNEXT(prev
) = next
;
304 atm_intrq
.ifq_tail
= prev
;
309 * Free the unwanted buffers
321 atm_free((caddr_t
)cvp
);
325 case CPCS_UNITDATA_INV
:
330 * Use temp state variable since we dont want to lock out
331 * interrupts, but initial VC activation interrupt may
332 * happen here, changing state somewhere in the middle.
334 state
= cvp
->cv_state
;
335 if ((state
!= CVS_ACTIVE
) &&
336 (state
!= CVS_INITED
)) {
338 "atm_dev_lower: UNITDATA: tok=%p, state=%d\n",
340 KB_FREEALL((KBuffer
*)arg1
);
345 * Hand the data off to the device
347 (*cup
->cu_output
)(cup
, cvp
, (KBuffer
*)arg1
);
351 case CPCS_UABORT_INV
:
353 "atm_dev_lower: unimplemented stack cmd 0x%x, tok=%p\n",
359 "atm_dev_lower: unknown stack cmd 0x%x, tok=%p\n",
370 * Allocate kernel memory block
372 * This function will allocate a kernel memory block of the type specified
373 * in the flags parameter. The returned address will point to a memory
374 * block of the requested size and alignment. The memory block will also
375 * be zeroed. The alloc/free functions will manage/mask both the OS-specific
376 * kernel memory management requirements and the bookkeeping required to
377 * deal with data alignment issues.
379 * This function should not be called from interrupt level.
382 * size size of memory block to allocate
383 * align data alignment requirement
384 * flags allocation flags (ATM_DEV_*)
387 * uaddr pointer to aligned memory block
388 * NULL unable to allocate memory
392 atm_dev_alloc(u_int size
, u_int align
, u_int flags
)
402 * Find a free Mem_ent
405 for (mbp
= atm_mem_head
; mbp
&& mep
== NULL
; mbp
= mbp
->mb_next
) {
406 for (i
= 0; i
< MEM_NMEMENT
; i
++) {
407 if (mbp
->mb_mement
[i
].me_uaddr
== NULL
) {
408 mep
= &mbp
->mb_mement
[i
];
415 * If there are no free Mem_ent's, then allocate a new Mem_blk
416 * and link it into the chain
419 mbp
= KM_ALLOC(sizeof(Mem_blk
), M_DEVBUF
,
420 M_INTWAIT
| M_NULLOK
);
422 log(LOG_ERR
, "atm_dev_alloc: Mem_blk failure\n");
426 KM_ZERO(mbp
, sizeof(Mem_blk
));
428 mbp
->mb_next
= atm_mem_head
;
430 mep
= mbp
->mb_mement
;
434 * Now we need to get the kernel's allocation alignment minimum
436 * This is obviously very OS-specific stuff
438 kalign
= MINALLOCSIZE
;
441 * Figure out how much memory we must allocate to satify the
442 * user's size and alignment needs
447 ksize
= size
+ align
- kalign
;
450 * Finally, go get the memory
452 if (flags
& ATM_DEV_NONCACHE
) {
453 mep
->me_kaddr
= KM_ALLOC(ksize
, M_DEVBUF
, M_INTWAIT
| M_NULLOK
);
455 mep
->me_kaddr
= KM_ALLOC(ksize
, M_DEVBUF
, M_INTWAIT
| M_NULLOK
);
458 if (mep
->me_kaddr
== NULL
) {
459 log(LOG_ERR
, "atm_dev_alloc: %skernel memory unavailable\n",
460 (flags
& ATM_DEV_NONCACHE
) ? "non-cacheable " : "");
466 * Calculate correct alignment address to pass back to user
468 mep
->me_uaddr
= (void *) roundup((u_int
)mep
->me_kaddr
, align
);
469 mep
->me_ksize
= ksize
;
470 mep
->me_flags
= flags
;
473 * Clear memory for user
475 KM_ZERO(mep
->me_uaddr
, size
);
477 ATM_DEBUG4("atm_dev_alloc: size=%d, align=%d, flags=%d, uaddr=%p\n",
478 size
, align
, flags
, mep
->me_uaddr
);
482 return (mep
->me_uaddr
);
487 * Free kernel memory block
489 * This function will free a kernel memory block previously allocated by
490 * the atm_dev_alloc function.
492 * This function should not be called from interrupt level.
495 * uaddr pointer to allocated aligned memory block
502 atm_dev_free(volatile void *uaddr
)
508 ATM_DEBUG1("atm_dev_free: uaddr=%p\n", uaddr
);
513 * Protect ourselves...
516 panic("atm_dev_free: trying to free null address");
519 * Find our associated entry
522 for (mbp
= atm_mem_head
; mbp
&& mep
== NULL
; mbp
= mbp
->mb_next
) {
523 for (i
= 0; i
< MEM_NMEMENT
; i
++) {
524 if (mbp
->mb_mement
[i
].me_uaddr
== uaddr
) {
525 mep
= &mbp
->mb_mement
[i
];
532 * If we didn't find our entry, then unceremoniously let the caller
533 * know they screwed up (it certainly couldn't be a bug here...)
536 panic("atm_dev_free: trying to free unknown address");
539 * Give the memory space back to the kernel
541 if (mep
->me_flags
& ATM_DEV_NONCACHE
) {
542 KM_FREE(mep
->me_kaddr
, mep
->me_ksize
, M_DEVBUF
);
544 KM_FREE(mep
->me_kaddr
, mep
->me_ksize
, M_DEVBUF
);
550 mep
->me_uaddr
= NULL
;
558 * Compress buffer chain
560 * This function will compress a supplied buffer chain into a minimum number
561 * of kernel buffers. Typically, this function will be used because the
562 * number of buffers in an output buffer chain is too large for a device's
563 * DMA capabilities. This should only be called as a last resort, since
564 * all the data copying will surely kill any hopes of decent performance.
567 * m pointer to source buffer chain
570 * n pointer to compressed buffer chain
574 atm_dev_compress(KBuffer
*m
)
576 KBuffer
*n
, *n0
, **np
;
586 * Copy each source buffer into compressed chain
593 * Allocate another buffer for compressed chain
595 KB_ALLOCEXT(n
, ATM_DEV_CMPR_LG
, KB_F_NOWAIT
, KB_T_DATA
);
597 space
= ATM_DEV_CMPR_LG
;
599 KB_ALLOC(n
, ATM_DEV_CMPR_SM
, KB_F_NOWAIT
,
602 space
= ATM_DEV_CMPR_SM
;
605 * Unable to get any new buffers, so
606 * just return the partially compressed
616 KB_BFRSTART(n
, dst
, caddr_t
);
623 * Copy what we can from source buffer
625 len
= MIN(space
, KB_LEN(m
));
626 KB_DATASTART(m
, src
, caddr_t
);
627 KM_COPY(src
, dst
, len
);
630 * Adjust for copied data
639 * If we've exhausted our current source buffer, free it
640 * and move to the next one
642 if (KB_LEN(m
) == 0) {
654 * This function will return the VCC entry for a specified interface and
658 * cup pointer to interface unit structure
664 * vcp pointer to located VCC entry matching
669 atm_dev_vcc_find(Cmn_unit
*cup
, u_int vpi
, u_int vci
, u_int type
)
677 * (Probably should stick in a hash table some time)
679 for (cvp
= cup
->cu_vcc
; cvp
; cvp
= cvp
->cv_next
) {
682 vcp
= cvp
->cv_connvc
->cvc_vcc
;
683 if ((vcp
->vc_vci
== vci
) && (vcp
->vc_vpi
== vpi
) &&
684 ((vcp
->vc_type
& type
) == type
))
694 * Module unloading notification
696 * This function must be called just prior to unloading the module from
697 * memory. All allocated memory will be freed here and anything else that
717 * Free up all of our memory management storage
719 while (mbp
= atm_mem_head
) {
722 * Make sure users have freed up all of their memory
724 for (i
= 0; i
< MEM_NMEMENT
; i
++) {
725 if (mbp
->mb_mement
[i
].me_uaddr
!= NULL
) {
726 panic("atm_unload: unfreed memory");
730 atm_mem_head
= mbp
->mb_next
;
733 * Hand this block back to the kernel
735 KM_FREE((caddr_t
) mbp
, sizeof(Mem_blk
), M_DEVBUF
);
749 * cup pointer to device unit
750 * cvp pointer to VCC control block
751 * m pointer to pdu buffer chain
752 * msg pointer to message string
759 atm_dev_pdu_print(Cmn_unit
*cup
, Cmn_vcc
*cvp
, KBuffer
*m
, char *msg
)
763 ksnprintf(buf
, sizeof(buf
), "%s vcc=(%d,%d)", msg
,
764 cvp
->cv_connvc
->cvc_vcc
->vc_vpi
,
765 cvp
->cv_connvc
->cvc_vcc
->vc_vci
);
767 atm_pdu_print(m
, buf
);