⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eni_transmit.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	long		j;	u_long		dma_avail;	u_long		dma_start;	Eni_mem		tx_send;	u_long		*up;	KBuffer		*m0 = m, *m1, *mprev = NULL;	caddr_t		cp, bfr;	u_int		len, align;	int		compressed = 0;#ifdef	DIAGNOSTIC	if ( eni_pdu_print )		atm_dev_pdu_print ( cup, cvp, m, "eni output" );#endif	/*	 * Re-entry point for after buffer compression (if needed)	 */retry:	/*	 * We can avoid traversing the buffer list twice by building	 * the middle (minus header and trailer) dma list at the	 * same time we massage address and size alignments. Since	 * this list remains local until we determine we've enough	 * room, we're not going to trash anything by not checking	 * sizes, etc. yet. Skip first entry to be used later to skip	 * descriptor word.	 */	j = 2;	/*	 * Do data positioning for address and length alignment	 */	while ( m ) {		u_long	buf_addr;	/* For passing addr to eni_set_dma() */		/*		 * Get rid of any zero length buffers		 */		if ( KB_LEN ( m ) == 0 ) {			if ( mprev ) {				KB_UNLINK ( m, mprev, m1 );			} else {				KB_UNLINKHEAD ( m, m1 );				m0 = m1;			}			m = m1;			continue;		}		/*		 * Get start of data onto full-word alignment		 */		KB_DATASTART ( m, cp, caddr_t );		if ( align = ((u_int)cp) & (sizeof(u_long)-1)) {			/*			 * Gotta slide the data up			 */			eup->eu_stats.eni_st_drv.drv_xm_segnoal++;			bfr = cp - align;			KM_COPY ( cp, bfr, KB_LEN ( m ) );			KB_HEADMOVE ( m, -align );		} else {			/*			 * Data already aligned			 */			bfr = cp;		}		/*		 * Now work on getting the data length correct		 */		len = KB_LEN ( m );		while ( ( align = ( len & (sizeof(u_long)-1))) &&			(m1 = KB_NEXT ( m ) ) ) {			/*			 * Have to move some data from following buffer(s)			 * to word-fill this buffer			 */			u_int ncopy = MIN ( sizeof(u_long) - align,				KB_LEN ( m1 ) );			if ( ncopy ) {				/*				 * Move data to current buffer				 */				caddr_t	dest;				eup->eu_stats.eni_st_drv.drv_xm_seglen++;				KB_DATASTART ( m1, cp, caddr_t );				dest = bfr + len;				KB_HEADADJ ( m1, -ncopy );				KB_TAILADJ ( m, ncopy );				len += ncopy;				while ( ncopy-- ) {					*dest++ = *cp++;				}			}			/*			 * If we've drained the buffer, free it			 */			if ( KB_LEN ( m1 ) == 0 ) {				KBuffer *m2;				KB_UNLINK ( m1, m, m2 );			}		}		/*		 * Address and size are now aligned. Build dma list		 * using TX channel 0. Also, round length up to a word		 * size which should only effect the last buffer in the		 * chain. This works because the PDU length is maintained		 * seperately and we're not really adjusting the buffer's		 * idea of its length.		 */		KB_DATASTART ( m, buf_addr, u_long );		if ( eni_set_dma ( eup, 0, dma, TEMP_DMA_SIZE, &j, 0,		    buf_addr, KB_LEN ( m ) ) < 0 ) {			/*			 * Failed to build DMA list. First, we'll try to			 * compress the buffer chain into a smaller number			 * of buffers. After compressing, we'll try to send			 * the new buffer chain. If we still fail, then			 * we'll drop the pdu.			 */			if ( compressed ) {#ifdef	DO_LOG				log ( LOG_ERR,					"eni_output: eni_set_dma failed\n" );#endif				eup->eu_pif.pif_oerrors++;				KB_FREEALL ( m0 );				return;			}			eup->eu_stats.eni_st_drv.drv_xm_maxpdu++;			m = atm_dev_compress ( m0 );			if ( m == NULL ) {#ifdef	DO_LOG				log ( LOG_ERR,				    "eni_output: atm_dev_compress() failed\n" );#endif				eup->eu_pif.pif_oerrors++;				return;			}			/*			 * Reset to new head of buffer chain			 */			m0 = m;			/*			 * Indicate we've been through here			 */			compressed = 1;			/*			 * Retry to build the DMA descriptors for the newly			 *  compressed buffer chain			 */			goto retry;		}		/*		 * Now count the length		 */		pdulen += KB_LEN ( m );		/*		 * Bump counters and get ready for next buffer		 */		mprev = m;		m = KB_NEXT ( m );	}	/*	 * Get a buffer to use in a private queue so that we can	 * reclaim resources after the DMA has finished.	 */	KB_ALLOC ( m, ENI_SMALL_BSIZE, KB_F_NOWAIT, KB_T_DATA );	if ( m ) {		/*		 * Link the PDU onto our new head		 */		KB_NEXT ( m ) = m0;	} else {		/*		 * Drop this PDU and let the sender try again.		 */		eup->eu_stats.eni_st_drv.drv_xm_norsc++;#ifdef	DO_LOG		log(LOG_ERR, "eni_output: Unable to allocate drain buffer.\n");#endif		eup->eu_pif.pif_oerrors++;		KB_FREEALL ( m0 );		return;	}	s = splnet();	/*	 * Calculate size of buffer necessary to store PDU. If this	 * is an AAL5 PDU, we'll need to know where to stuff the length	 * value in the trailer.	 */	/*	 * AAL5 PDUs need an extra two words for control/length and	 * CRC. Check for AAL5 and add requirements here.	 */	if (aal5 = (evp->ev_connvc->cvc_attr.aal.type == ATM_AAL5))		size = pdulen + 2 * sizeof(long);	else		size = pdulen;	/*	 * Pad to next complete cell boundary	 */	size += (BYTES_PER_CELL - 1);	size -= size % BYTES_PER_CELL;	/*	 * Convert size to words and add 2 words overhead for every	 * PDU (descriptor and cell header).	 */	size = (size >> 2) + 2;	/*	 * First, check to see if there's enough buffer space to	 * store the PDU. We do this by checking to see if the size	 * required crosses the eu_txfirst pointer.  However, we don't	 * want to exactly fill the buffer, because we won't be able to	 * distinguish between a full and empty buffer.	 */	if ( eup->eu_txpos == eup->eu_txfirst )		buf_avail = eup->eu_txsize;	else	    if ( eup->eu_txpos > eup->eu_txfirst )		buf_avail = eup->eu_txsize - ( eup->eu_txpos - eup->eu_txfirst );	    else		buf_avail = eup->eu_txfirst - eup->eu_txpos;	if ( size >= buf_avail )	{		/*		 * No buffer space in the adapter to store this PDU.		 * Drop PDU and return.		 */		eup->eu_stats.eni_st_drv.drv_xm_nobuf++;#ifdef	DO_LOG		log ( LOG_ERR,			"eni_output: not enough room in buffer\n" );#endif		eup->eu_pif.pif_oerrors++;	 	KB_FREEALL ( m );		(void) splx(s);		return;	}	/*	 * Find out where current DMA pointers are at	 */	dma_start = dma_wr = eup->eu_midway[MIDWAY_TX_WR];	dma_rd = eup->eu_midway[MIDWAY_TX_RD];	/*	 * Figure out how much DMA room we have available	 */	if ( dma_rd == dma_wr )	{		/* Queue is empty */		dma_avail = DMA_LIST_SIZE;	} else {		dma_avail = ( dma_rd + DMA_LIST_SIZE - dma_wr )		    & ( DMA_LIST_SIZE - 1 );	}	/*	 * Check to see if we can describe this PDU or if we're:	 * out of room, will wrap past recovered resources.	 */	if ( dma_avail < (j / 2 + 4) ||	    ( dma_wr + (j / 2 + 4) > eup->eu_txdmawr + DMA_LIST_SIZE ) ) {		/*		 * No space to insert DMA list into queue. Drop this PDU.		 */		eup->eu_stats.eni_st_drv.drv_xm_nodma++;#ifdef	DO_LOG		log ( LOG_ERR,			"eni_output: not enough room in DMA queue\n" );#endif		eup->eu_pif.pif_oerrors++;		KB_FREEALL( m );		(void) splx(s);		return;	}	/*	 * Create DMA descriptor for header. There is a descriptor word	 * and also a cell header word which we'll set manually.	 */	dma[0] = (((int)(eup->eu_txpos + 2) & (eup->eu_txsize-1)) <<	    DMA_COUNT_SHIFT) | DMA_JK;	dma[1] = 0;	/*	 * JK for AAL5 trailer. Set END bit as well.	 */	if ( aal5 ) {	    dma[j++] = (((int)(eup->eu_txpos+size) & (eup->eu_txsize-1)) <<		DMA_COUNT_SHIFT) | DMA_END_BIT | DMA_JK;	    dma[j++] = 0;	} else {		dma[j-2] |= DMA_END_BIT;	/* Backup and set END bit */	}	/*	 * Find out where in adapter memory this TX buffer starts.	 */	tx_send = (Eni_mem)	    ((((int)eup->eu_midway[MIDWAY_TXPLACE] & 0x7ff) << ENI_LOC_PREDIV) +		    (int)eup->eu_ram);	/*	 * Set descriptor word	 */	tx_send[eup->eu_txpos] =		(MIDWAY_UNQ_ID << 28) | (aal5 ? 1 << 27 : 0)			| (size / WORDS_PER_CELL);	/*	 * Set cell header	 */	tx_send[(eup->eu_txpos+1)&(eup->eu_txsize-1)] = 		evp->ev_connvc->cvc_vcc->vc_vci << 4;	/*	 * We've got all our resources, count the stats	 */	if ( aal5 ) {		/*		 * If this is an AAL5 PDU, we need to set the length		 */		tx_send[(eup->eu_txpos+size-2) &			(eup->eu_txsize-1)] = pdulen;		/*		 * Increment AAL5 stats		 */		eup->eu_stats.eni_st_aal5.aal5_pdu_xmit++;		eup->eu_stats.eni_st_aal5.aal5_xmit += (size - 2) / WORDS_PER_CELL;	} else {		/*		 * Increment AAL0 stats		 */		eup->eu_stats.eni_st_aal0.aal0_xmit += (size - 2) / WORDS_PER_CELL;	}	/*	 * Increment ATM stats	 */	eup->eu_stats.eni_st_atm.atm_xmit += (size - 2) / WORDS_PER_CELL;	/*	 * Store the DMA list	 */	j = j >> 1;	for ( i = 0; i < j; i++ ) {		eup->eu_txdma[dma_wr*2] = dma[i*2];		eup->eu_txdma[dma_wr*2+1] = dma[i*2+1];		dma_wr = (dma_wr+1) & (DMA_LIST_SIZE-1);	}	/*	 * Build drain buffer	 *	 * We toss four words in to help keep track of this	 * PDU. The first is a pointer to the VC control block	 * so we can find which VCI this went out on, the second	 * is the start and stop pointers for the DMA list which	 * describes this PDU, the third is the PDU length	 * since we'll want to know that for stats gathering,	 * and the fourth is the number of DMA words.	 */	KB_DATASTART ( m, up, u_long * );	*up++ = (u_long)cvp;	*up++ = dma_start << 16 | dma_wr;	*up++ = pdulen;	*up = size;	/*	 * Set length of our buffer	 */	KB_LEN ( m ) = 4 * sizeof ( long );	/*	 * Place buffers onto transmit queue for draining	 */	s2 = splimp();	IF_ENQUEUE ( &eup->eu_txqueue, m );	(void) splx(s2);	/*	 * Update next word to be stored	 */	eup->eu_txpos = ((eup->eu_txpos + size) & (eup->eu_txsize - 1));	/*	 * Update MIDWAY_TX_WR pointer	 */	eup->eu_midway[MIDWAY_TX_WR] = dma_wr;		(void) splx ( s );	return;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -