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 $
34 * ATM device support functions
38 #include <netatm/kern_include.h>
41 __RCSID("@(#) $FreeBSD: src/sys/netatm/atm_device.c,v 1.5 1999/08/28 00:48:35 peter Exp $");
46 * Private structures for managing allocated kernel memory resources
48 * For each allocation of kernel memory, one Mem_ent will be used.
49 * The Mem_ent structures will be allocated in blocks inside of a
52 #define MEM_NMEMENT 10 /* How many Mem_ent's in a Mem_blk */
55 void *me_kaddr; /* Allocated memory address */
56 u_int me_ksize; /* Allocated memory length */
57 void *me_uaddr; /* Memory address returned to caller */
58 u_int me_flags; /* Flags (see below) */
60 typedef struct mem_ent Mem_ent;
65 #define MEF_NONCACHE 1 /* Memory is noncacheable */
69 struct mem_blk *mb_next; /* Next block in chain */
70 Mem_ent mb_mement[MEM_NMEMENT]; /* Allocated memory entries */
72 typedef struct mem_blk Mem_blk;
74 static Mem_blk *atm_mem_head = NULL;
76 static struct t_atm_cause atm_dev_cause = {
79 T_ATM_CAUSE_VPCI_VCI_ASSIGNMENT_FAILURE,
85 * ATM Device Stack Instantiation
90 * ssp pointer to array of stack definition pointers
92 * ssp[0] points to upper layer's stack definition
93 * ssp[1] points to this layer's stack definition
94 * ssp[2] points to lower layer's stack definition
95 * cvcp pointer to connection vcc for this stack
98 * 0 instantiation successful
99 * err instantiation failed - reason indicated
103 atm_dev_inst(ssp, cvcp)
104 struct stack_defn **ssp;
107 Cmn_unit *cup = (Cmn_unit *)cvcp->cvc_attr.nif->nif_pif;
112 * Check to see if device has been initialized
114 if ((cup->cu_flags & CUF_INITED) == 0)
121 * Device driver is the lowest layer - no need to validate
125 * Validate PVC vpi.vci
127 if (cvcp->cvc_attr.called.addr.address_format == T_ATM_PVC_ADDR) {
129 * Look through existing circuits - return error if found
133 pp = (Atm_addr_pvc *)cvcp->cvc_attr.called.addr.address;
134 if (atm_dev_vcc_find(cup, ATM_PVC_GET_VPI(pp),
135 ATM_PVC_GET_VCI(pp), 0))
136 return ( EADDRINUSE );
140 * Validate our SAP type
142 switch ((*(ssp+1))->sd_sap) {
143 case SAP_CPCS_AAL3_4:
152 * Allocate a VCC control block
154 if ( ( cvp = (Cmn_vcc *)atm_allocate(cup->cu_vcc_pool) ) == NULL )
157 cvp->cv_state = CVS_INST;
158 cvp->cv_toku = (*ssp)->sd_toku;
159 cvp->cv_upper = (*ssp)->sd_upper;
160 cvp->cv_connvc = cvcp;
163 * Let device have a look at the connection request
165 err = (*cup->cu_instvcc)(cup, cvp);
167 atm_free((caddr_t)cvp);
172 * Looks good so far, so link in device VCC
174 LINK2TAIL ( cvp, Cmn_vcc, cup->cu_vcc, cv_next );
179 (*++ssp)->sd_toku = cvp;
182 * Pass instantiation down the stack
185 * No need - we're the lowest point.
187 /* err = (*(ssp + 1))->sd_inst(ssp, cvcp); */
190 * Save the lower layer's interface info
193 * No need - we're the lowest point
195 /* cvp->cv_lower = (*++ssp)->sd_lower; */
196 /* cvp->cv_tok1 = (*ssp)->sd_toku; */
203 * ATM Device Stack Command Handler
206 * cmd stack command code
207 * tok session token (Cmn_vcc)
208 * arg1 command specific argument
209 * arg2 command specific argument
217 atm_dev_lower(cmd, tok, arg1, arg2)
223 Cmn_vcc *cvp = (Cmn_vcc *)tok;
224 Atm_connvc *cvcp = cvp->cv_connvc;
225 Cmn_unit *cup = (Cmn_unit *)cvcp->cvc_attr.nif->nif_pif;
236 if ( cvp->cv_state != CVS_INST ) {
238 "atm_dev_lower: INIT: tok=%p, state=%d\n",
239 tok, cvp->cv_state );
243 vcp = cvp->cv_connvc->cvc_vcc;
246 * Validate SVC vpi.vci
248 if ( vcp->vc_type & VCC_SVC ) {
250 if (atm_dev_vcc_find(cup, vcp->vc_vpi, vcp->vc_vci,
251 vcp->vc_type & (VCC_IN | VCC_OUT))
254 "atm_dev_lower: dup SVC (%d,%d) tok=%p\n",
255 vcp->vc_vpi, vcp->vc_vci, tok );
256 atm_cm_abort(cvp->cv_connvc, &atm_dev_cause);
262 * Tell the device to open the VCC
264 cvp->cv_state = CVS_INITED;
266 if ((*cup->cu_openvcc)(cup, cvp)) {
267 atm_cm_abort(cvp->cv_connvc, &atm_dev_cause);
275 KBuffer *m, *prev, *next;
281 * Disconnect the VCC - ignore return code
283 if ((cvp->cv_state == CVS_INITED) ||
284 (cvp->cv_state == CVS_ACTIVE)) {
285 (void) (*cup->cu_closevcc)(cup, cvp);
287 cvp->cv_state = CVS_TERM;
290 * Remove from interface list
292 UNLINK ( cvp, Cmn_vcc, cup->cu_vcc, cv_next );
295 * Free any buffers from this VCC on the ATM interrupt queue
298 for (m = atm_intrq.ifq_head; m; m = next) {
302 * See if this entry is for the terminating VCC
304 KB_DATASTART(m, ip, int *);
306 if (*ip == (int)cvp) {
308 * Yep, so dequeue the entry
311 atm_intrq.ifq_head = next;
313 KB_QNEXT(prev) = next;
316 atm_intrq.ifq_tail = prev;
321 * Free the unwanted buffers
333 (void) atm_free((caddr_t)cvp);
337 case CPCS_UNITDATA_INV:
342 * Use temp state variable since we dont want to lock out
343 * interrupts, but initial VC activation interrupt may
344 * happen here, changing state somewhere in the middle.
346 state = cvp->cv_state;
347 if ((state != CVS_ACTIVE) &&
348 (state != CVS_INITED)) {
350 "atm_dev_lower: UNITDATA: tok=%p, state=%d\n",
352 KB_FREEALL((KBuffer *)arg1);
357 * Hand the data off to the device
359 (*cup->cu_output)(cup, cvp, (KBuffer *)arg1);
363 case CPCS_UABORT_INV:
365 "atm_dev_lower: unimplemented stack cmd 0x%x, tok=%p\n",
371 "atm_dev_lower: unknown stack cmd 0x%x, tok=%p\n",
382 * Allocate kernel memory block
384 * This function will allocate a kernel memory block of the type specified
385 * in the flags parameter. The returned address will point to a memory
386 * block of the requested size and alignment. The memory block will also
387 * be zeroed. The alloc/free functions will manage/mask both the OS-specific
388 * kernel memory management requirements and the bookkeeping required to
389 * deal with data alignment issues.
391 * This function should not be called from interrupt level.
394 * size size of memory block to allocate
395 * align data alignment requirement
396 * flags allocation flags (ATM_DEV_*)
399 * uaddr pointer to aligned memory block
400 * NULL unable to allocate memory
404 atm_dev_alloc(size, align, flags)
417 * Find a free Mem_ent
420 for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) {
421 for (i = 0; i < MEM_NMEMENT; i++) {
422 if (mbp->mb_mement[i].me_uaddr == NULL) {
423 mep = &mbp->mb_mement[i];
430 * If there are no free Mem_ent's, then allocate a new Mem_blk
431 * and link it into the chain
434 mbp = (Mem_blk *) KM_ALLOC(sizeof(Mem_blk), M_DEVBUF, M_NOWAIT);
436 log(LOG_ERR, "atm_dev_alloc: Mem_blk failure\n");
440 KM_ZERO(mbp, sizeof(Mem_blk));
442 mbp->mb_next = atm_mem_head;
444 mep = mbp->mb_mement;
448 * Now we need to get the kernel's allocation alignment minimum
450 * This is obviously very OS-specific stuff
453 if (flags & ATM_DEV_NONCACHE) {
455 kalign = sizeof(long);
457 /* Doubleword-aligned */
458 kalign = sizeof(double);
460 #elif (defined(BSD) && (BSD >= 199103))
461 kalign = MINALLOCSIZE;
463 #error Unsupported/unconfigured OS
467 * Figure out how much memory we must allocate to satify the
468 * user's size and alignment needs
473 ksize = size + align - kalign;
476 * Finally, go get the memory
478 if (flags & ATM_DEV_NONCACHE) {
480 mep->me_kaddr = IOPBALLOC(ksize);
481 #elif defined(__i386__)
482 mep->me_kaddr = KM_ALLOC(ksize, M_DEVBUF, M_NOWAIT);
484 #error Unsupported/unconfigured OS
487 mep->me_kaddr = KM_ALLOC(ksize, M_DEVBUF, M_NOWAIT);
490 if (mep->me_kaddr == NULL) {
491 log(LOG_ERR, "atm_dev_alloc: %skernel memory unavailable\n",
492 (flags & ATM_DEV_NONCACHE) ? "non-cacheable " : "");
498 * Calculate correct alignment address to pass back to user
500 mep->me_uaddr = (void *) roundup((u_int)mep->me_kaddr, align);
501 mep->me_ksize = ksize;
502 mep->me_flags = flags;
505 * Clear memory for user
507 KM_ZERO(mep->me_uaddr, size);
509 ATM_DEBUG4("atm_dev_alloc: size=%d, align=%d, flags=%d, uaddr=%p\n",
510 size, align, flags, mep->me_uaddr);
514 return (mep->me_uaddr);
519 * Free kernel memory block
521 * This function will free a kernel memory block previously allocated by
522 * the atm_dev_alloc function.
524 * This function should not be called from interrupt level.
527 * uaddr pointer to allocated aligned memory block
541 ATM_DEBUG1("atm_dev_free: uaddr=%p\n", uaddr);
546 * Protect ourselves...
549 panic("atm_dev_free: trying to free null address");
552 * Find our associated entry
555 for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) {
556 for (i = 0; i < MEM_NMEMENT; i++) {
557 if (mbp->mb_mement[i].me_uaddr == uaddr) {
558 mep = &mbp->mb_mement[i];
565 * If we didn't find our entry, then unceremoniously let the caller
566 * know they screwed up (it certainly couldn't be a bug here...)
569 panic("atm_dev_free: trying to free unknown address");
572 * Give the memory space back to the kernel
574 if (mep->me_flags & ATM_DEV_NONCACHE) {
576 IOPBFREE(mep->me_kaddr, mep->me_ksize);
577 #elif defined(__i386__)
578 KM_FREE(mep->me_kaddr, mep->me_ksize, M_DEVBUF);
580 #error Unsupported/unconfigured OS
583 KM_FREE(mep->me_kaddr, mep->me_ksize, M_DEVBUF);
589 mep->me_uaddr = NULL;
599 typedef int (*func_t)();
602 * Map an address into DVMA space
604 * This function will take a kernel virtual address and map it to
605 * a DMA virtual address which can be used during SBus DMA cycles.
608 * addr kernel virtual address
609 * len length of DVMA space requested
610 * flags allocation flags (ATM_DEV_*)
614 * NULL unable to map into DMA space
618 atm_dma_map(addr, len, flags)
623 if (flags & ATM_DEV_NONCACHE)
625 * Non-cacheable memory is already DMA'able
627 return ((void *)addr);
629 return ((void *)mb_nbmapalloc(bigsbusmap, addr, len,
630 MDR_BIGSBUS|MB_CANTWAIT, (func_t)NULL, (caddr_t)NULL));
635 * Free a DVMA map address
637 * This function will free DVMA map resources (addresses) previously
638 * allocated with atm_dma_map().
641 * addr DMA virtual address
642 * flags allocation flags (ATM_DEV_*)
649 atm_dma_free(addr, flags)
653 if ((flags & ATM_DEV_NONCACHE) == 0)
654 mb_mapfree(bigsbusmap, (int)&addr);
662 * Compress buffer chain
664 * This function will compress a supplied buffer chain into a minimum number
665 * of kernel buffers. Typically, this function will be used because the
666 * number of buffers in an output buffer chain is too large for a device's
667 * DMA capabilities. This should only be called as a last resort, since
668 * all the data copying will surely kill any hopes of decent performance.
671 * m pointer to source buffer chain
674 * n pointer to compressed buffer chain
681 KBuffer *n, *n0, **np;
691 * Copy each source buffer into compressed chain
698 * Allocate another buffer for compressed chain
700 KB_ALLOCEXT(n, ATM_DEV_CMPR_LG, KB_F_NOWAIT, KB_T_DATA);
702 space = ATM_DEV_CMPR_LG;
704 KB_ALLOC(n, ATM_DEV_CMPR_SM, KB_F_NOWAIT,
707 space = ATM_DEV_CMPR_SM;
710 * Unable to get any new buffers, so
711 * just return the partially compressed
721 KB_BFRSTART(n, dst, caddr_t);
728 * Copy what we can from source buffer
730 len = MIN(space, KB_LEN(m));
731 KB_DATASTART(m, src, caddr_t);
732 KM_COPY(src, dst, len);
735 * Adjust for copied data
744 * If we've exhausted our current source buffer, free it
745 * and move to the next one
747 if (KB_LEN(m) == 0) {
759 * This function will return the VCC entry for a specified interface and
763 * cup pointer to interface unit structure
769 * vcp pointer to located VCC entry matching
774 atm_dev_vcc_find(cup, vpi, vci, type)
786 * (Probably should stick in a hash table some time)
788 for (cvp = cup->cu_vcc; cvp; cvp = cvp->cv_next) {
791 vcp = cvp->cv_connvc->cvc_vcc;
792 if ((vcp->vc_vci == vci) && (vcp->vc_vpi == vpi) &&
793 ((vcp->vc_type & type) == type))
804 * Module unloading notification
806 * This function must be called just prior to unloading the module from
807 * memory. All allocated memory will be freed here and anything else that
827 * Free up all of our memory management storage
829 while (mbp = atm_mem_head) {
832 * Make sure users have freed up all of their memory
834 for (i = 0; i < MEM_NMEMENT; i++) {
835 if (mbp->mb_mement[i].me_uaddr != NULL) {
836 panic("atm_unload: unfreed memory");
840 atm_mem_head = mbp->mb_next;
843 * Hand this block back to the kernel
845 KM_FREE((caddr_t) mbp, sizeof(Mem_blk), M_DEVBUF);
859 * cup pointer to device unit
860 * cvp pointer to VCC control block
861 * m pointer to pdu buffer chain
862 * msg pointer to message string
869 atm_dev_pdu_print(cup, cvp, m, msg)
877 snprintf(buf, sizeof(buf), "%s vcc=(%d,%d)", msg,
878 cvp->cv_connvc->cvc_vcc->vc_vpi,
879 cvp->cv_connvc->cvc_vcc->vc_vci);
881 atm_pdu_print(m, buf);