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.2 2003/06/17 04:28:48 dillon Exp $
34 * ATM device support functions
38 #include <netatm/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
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;
231 if ( cvp->cv_state != CVS_INST ) {
233 "atm_dev_lower: INIT: tok=%p, state=%d\n",
234 tok, cvp->cv_state );
238 vcp = cvp->cv_connvc->cvc_vcc;
241 * Validate SVC vpi.vci
243 if ( vcp->vc_type & VCC_SVC ) {
245 if (atm_dev_vcc_find(cup, vcp->vc_vpi, vcp->vc_vci,
246 vcp->vc_type & (VCC_IN | VCC_OUT))
249 "atm_dev_lower: dup SVC (%d,%d) tok=%p\n",
250 vcp->vc_vpi, vcp->vc_vci, tok );
251 atm_cm_abort(cvp->cv_connvc, &atm_dev_cause);
257 * Tell the device to open the VCC
259 cvp->cv_state = CVS_INITED;
261 if ((*cup->cu_openvcc)(cup, cvp)) {
262 atm_cm_abort(cvp->cv_connvc, &atm_dev_cause);
270 KBuffer *m, *prev, *next;
276 * Disconnect the VCC - ignore return code
278 if ((cvp->cv_state == CVS_INITED) ||
279 (cvp->cv_state == CVS_ACTIVE)) {
280 (void) (*cup->cu_closevcc)(cup, cvp);
282 cvp->cv_state = CVS_TERM;
285 * Remove from interface list
287 UNLINK ( cvp, Cmn_vcc, cup->cu_vcc, cv_next );
290 * Free any buffers from this VCC on the ATM interrupt queue
293 for (m = atm_intrq.ifq_head; m; m = next) {
297 * See if this entry is for the terminating VCC
299 KB_DATASTART(m, ip, int *);
301 if (*ip == (int)cvp) {
303 * Yep, so dequeue the entry
306 atm_intrq.ifq_head = next;
308 KB_QNEXT(prev) = next;
311 atm_intrq.ifq_tail = prev;
316 * Free the unwanted buffers
328 (void) atm_free((caddr_t)cvp);
332 case CPCS_UNITDATA_INV:
337 * Use temp state variable since we dont want to lock out
338 * interrupts, but initial VC activation interrupt may
339 * happen here, changing state somewhere in the middle.
341 state = cvp->cv_state;
342 if ((state != CVS_ACTIVE) &&
343 (state != CVS_INITED)) {
345 "atm_dev_lower: UNITDATA: tok=%p, state=%d\n",
347 KB_FREEALL((KBuffer *)arg1);
352 * Hand the data off to the device
354 (*cup->cu_output)(cup, cvp, (KBuffer *)arg1);
358 case CPCS_UABORT_INV:
360 "atm_dev_lower: unimplemented stack cmd 0x%x, tok=%p\n",
366 "atm_dev_lower: unknown stack cmd 0x%x, tok=%p\n",
377 * Allocate kernel memory block
379 * This function will allocate a kernel memory block of the type specified
380 * in the flags parameter. The returned address will point to a memory
381 * block of the requested size and alignment. The memory block will also
382 * be zeroed. The alloc/free functions will manage/mask both the OS-specific
383 * kernel memory management requirements and the bookkeeping required to
384 * deal with data alignment issues.
386 * This function should not be called from interrupt level.
389 * size size of memory block to allocate
390 * align data alignment requirement
391 * flags allocation flags (ATM_DEV_*)
394 * uaddr pointer to aligned memory block
395 * NULL unable to allocate memory
399 atm_dev_alloc(size, align, flags)
412 * Find a free Mem_ent
415 for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) {
416 for (i = 0; i < MEM_NMEMENT; i++) {
417 if (mbp->mb_mement[i].me_uaddr == NULL) {
418 mep = &mbp->mb_mement[i];
425 * If there are no free Mem_ent's, then allocate a new Mem_blk
426 * and link it into the chain
429 mbp = (Mem_blk *) KM_ALLOC(sizeof(Mem_blk), M_DEVBUF, M_NOWAIT);
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
448 if (flags & ATM_DEV_NONCACHE) {
450 kalign = sizeof(long);
452 /* Doubleword-aligned */
453 kalign = sizeof(double);
455 #elif (defined(BSD) && (BSD >= 199103))
456 kalign = MINALLOCSIZE;
458 #error Unsupported/unconfigured OS
462 * Figure out how much memory we must allocate to satify the
463 * user's size and alignment needs
468 ksize = size + align - kalign;
471 * Finally, go get the memory
473 if (flags & ATM_DEV_NONCACHE) {
475 mep->me_kaddr = IOPBALLOC(ksize);
476 #elif defined(__i386__)
477 mep->me_kaddr = KM_ALLOC(ksize, M_DEVBUF, M_NOWAIT);
479 #error Unsupported/unconfigured OS
482 mep->me_kaddr = KM_ALLOC(ksize, M_DEVBUF, M_NOWAIT);
485 if (mep->me_kaddr == NULL) {
486 log(LOG_ERR, "atm_dev_alloc: %skernel memory unavailable\n",
487 (flags & ATM_DEV_NONCACHE) ? "non-cacheable " : "");
493 * Calculate correct alignment address to pass back to user
495 mep->me_uaddr = (void *) roundup((u_int)mep->me_kaddr, align);
496 mep->me_ksize = ksize;
497 mep->me_flags = flags;
500 * Clear memory for user
502 KM_ZERO(mep->me_uaddr, size);
504 ATM_DEBUG4("atm_dev_alloc: size=%d, align=%d, flags=%d, uaddr=%p\n",
505 size, align, flags, mep->me_uaddr);
509 return (mep->me_uaddr);
514 * Free kernel memory block
516 * This function will free a kernel memory block previously allocated by
517 * the atm_dev_alloc function.
519 * This function should not be called from interrupt level.
522 * uaddr pointer to allocated aligned memory block
536 ATM_DEBUG1("atm_dev_free: uaddr=%p\n", uaddr);
541 * Protect ourselves...
544 panic("atm_dev_free: trying to free null address");
547 * Find our associated entry
550 for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) {
551 for (i = 0; i < MEM_NMEMENT; i++) {
552 if (mbp->mb_mement[i].me_uaddr == uaddr) {
553 mep = &mbp->mb_mement[i];
560 * If we didn't find our entry, then unceremoniously let the caller
561 * know they screwed up (it certainly couldn't be a bug here...)
564 panic("atm_dev_free: trying to free unknown address");
567 * Give the memory space back to the kernel
569 if (mep->me_flags & ATM_DEV_NONCACHE) {
571 IOPBFREE(mep->me_kaddr, mep->me_ksize);
572 #elif defined(__i386__)
573 KM_FREE(mep->me_kaddr, mep->me_ksize, M_DEVBUF);
575 #error Unsupported/unconfigured OS
578 KM_FREE(mep->me_kaddr, mep->me_ksize, M_DEVBUF);
584 mep->me_uaddr = NULL;
594 typedef int (*func_t)();
597 * Map an address into DVMA space
599 * This function will take a kernel virtual address and map it to
600 * a DMA virtual address which can be used during SBus DMA cycles.
603 * addr kernel virtual address
604 * len length of DVMA space requested
605 * flags allocation flags (ATM_DEV_*)
609 * NULL unable to map into DMA space
613 atm_dma_map(addr, len, flags)
618 if (flags & ATM_DEV_NONCACHE)
620 * Non-cacheable memory is already DMA'able
622 return ((void *)addr);
624 return ((void *)mb_nbmapalloc(bigsbusmap, addr, len,
625 MDR_BIGSBUS|MB_CANTWAIT, (func_t)NULL, (caddr_t)NULL));
630 * Free a DVMA map address
632 * This function will free DVMA map resources (addresses) previously
633 * allocated with atm_dma_map().
636 * addr DMA virtual address
637 * flags allocation flags (ATM_DEV_*)
644 atm_dma_free(addr, flags)
648 if ((flags & ATM_DEV_NONCACHE) == 0)
649 mb_mapfree(bigsbusmap, (int)&addr);
657 * Compress buffer chain
659 * This function will compress a supplied buffer chain into a minimum number
660 * of kernel buffers. Typically, this function will be used because the
661 * number of buffers in an output buffer chain is too large for a device's
662 * DMA capabilities. This should only be called as a last resort, since
663 * all the data copying will surely kill any hopes of decent performance.
666 * m pointer to source buffer chain
669 * n pointer to compressed buffer chain
676 KBuffer *n, *n0, **np;
686 * Copy each source buffer into compressed chain
693 * Allocate another buffer for compressed chain
695 KB_ALLOCEXT(n, ATM_DEV_CMPR_LG, KB_F_NOWAIT, KB_T_DATA);
697 space = ATM_DEV_CMPR_LG;
699 KB_ALLOC(n, ATM_DEV_CMPR_SM, KB_F_NOWAIT,
702 space = ATM_DEV_CMPR_SM;
705 * Unable to get any new buffers, so
706 * just return the partially compressed
716 KB_BFRSTART(n, dst, caddr_t);
723 * Copy what we can from source buffer
725 len = MIN(space, KB_LEN(m));
726 KB_DATASTART(m, src, caddr_t);
727 KM_COPY(src, dst, len);
730 * Adjust for copied data
739 * If we've exhausted our current source buffer, free it
740 * and move to the next one
742 if (KB_LEN(m) == 0) {
754 * This function will return the VCC entry for a specified interface and
758 * cup pointer to interface unit structure
764 * vcp pointer to located VCC entry matching
769 atm_dev_vcc_find(cup, vpi, vci, type)
781 * (Probably should stick in a hash table some time)
783 for (cvp = cup->cu_vcc; cvp; cvp = cvp->cv_next) {
786 vcp = cvp->cv_connvc->cvc_vcc;
787 if ((vcp->vc_vci == vci) && (vcp->vc_vpi == vpi) &&
788 ((vcp->vc_type & type) == type))
799 * Module unloading notification
801 * This function must be called just prior to unloading the module from
802 * memory. All allocated memory will be freed here and anything else that
822 * Free up all of our memory management storage
824 while (mbp = atm_mem_head) {
827 * Make sure users have freed up all of their memory
829 for (i = 0; i < MEM_NMEMENT; i++) {
830 if (mbp->mb_mement[i].me_uaddr != NULL) {
831 panic("atm_unload: unfreed memory");
835 atm_mem_head = mbp->mb_next;
838 * Hand this block back to the kernel
840 KM_FREE((caddr_t) mbp, sizeof(Mem_blk), M_DEVBUF);
854 * cup pointer to device unit
855 * cvp pointer to VCC control block
856 * m pointer to pdu buffer chain
857 * msg pointer to message string
864 atm_dev_pdu_print(cup, cvp, m, msg)
872 snprintf(buf, sizeof(buf), "%s vcc=(%d,%d)", msg,
873 cvp->cv_connvc->cvc_vcc->vc_vpi,
874 cvp->cv_connvc->cvc_vcc->vc_vci);
876 atm_pdu_print(m, buf);