xref: /onnv-gate/usr/src/uts/common/io/xge/hal/xgehal/xgehal-channel-fp.c (revision 6937:a5e2c8b5c817)
11256Syl150051 /*
21256Syl150051  * CDDL HEADER START
31256Syl150051  *
41256Syl150051  * The contents of this file are subject to the terms of the
51256Syl150051  * Common Development and Distribution License (the "License").
61256Syl150051  * You may not use this file except in compliance with the License.
71256Syl150051  *
81256Syl150051  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91256Syl150051  * or http://www.opensolaris.org/os/licensing.
101256Syl150051  * See the License for the specific language governing permissions
111256Syl150051  * and limitations under the License.
121256Syl150051  *
131256Syl150051  * When distributing Covered Code, include this CDDL HEADER in each
141256Syl150051  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151256Syl150051  * If applicable, add the following below this CDDL HEADER, with the
161256Syl150051  * fields enclosed by brackets "[]" replaced with your own identifying
171256Syl150051  * information: Portions Copyright [yyyy] [name of copyright owner]
181256Syl150051  *
191256Syl150051  * CDDL HEADER END
201256Syl150051  *
213115Syl150051  * Copyright (c) 2002-2006 Neterion, Inc.
221256Syl150051  */
231256Syl150051 
241256Syl150051 #ifdef XGE_DEBUG_FP
251256Syl150051 #include "xgehal-channel.h"
261256Syl150051 #endif
271256Syl150051 
281256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
__hal_channel_dtr_alloc(xge_hal_channel_h channelh,xge_hal_dtr_h * dtrh)293115Syl150051 __hal_channel_dtr_alloc(xge_hal_channel_h channelh,	xge_hal_dtr_h *dtrh)
301256Syl150051 {
311256Syl150051 	void **tmp_arr;
323115Syl150051 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
333115Syl150051 #if	defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
343115Syl150051 	unsigned long flags	= 0;
353115Syl150051 #endif
36*6937Sxw161283 	if (channel->terminating) {
37*6937Sxw161283 		return XGE_HAL_FAIL;
38*6937Sxw161283 	}
391256Syl150051 
403115Syl150051 	if (channel->reserve_length	- channel->reserve_top >
413115Syl150051 						channel->reserve_threshold)	{
421256Syl150051 
431256Syl150051 _alloc_after_swap:
443115Syl150051 		*dtrh =	channel->reserve_arr[--channel->reserve_length];
451256Syl150051 
463115Syl150051 		xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" allocated,	"
473115Syl150051 				   "channel	%d:%d:%d, reserve_idx %d",
481256Syl150051 				   (unsigned long long)(ulong_t)*dtrh,
491256Syl150051 				   channel->type, channel->post_qid,
501256Syl150051 				   channel->compl_qid, channel->reserve_length);
511256Syl150051 
521256Syl150051 		return XGE_HAL_OK;
531256Syl150051 	}
541256Syl150051 
553115Syl150051 #if	defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
561256Syl150051 	xge_os_spin_lock_irq(&channel->free_lock, flags);
573115Syl150051 #elif defined(XGE_HAL_RX_MULTI_FREE) ||	defined(XGE_HAL_TX_MULTI_FREE)
583115Syl150051 	xge_os_spin_lock(&channel->free_lock);
593115Syl150051 #endif
601256Syl150051 
613115Syl150051 	/* switch between empty	and	full arrays	*/
621256Syl150051 
633115Syl150051 	/* the idea	behind such	a design is	that by	having free	and	reserved
643115Syl150051 	 * arrays separated	we basically separated irq and non-irq parts.
653115Syl150051 	 * i.e.	no additional lock need	to be done when	we free	a resource */
661256Syl150051 
673115Syl150051 	if (channel->reserve_initial - channel->free_length	>
683115Syl150051 					channel->reserve_threshold)	{
693115Syl150051 
703115Syl150051 		tmp_arr	= channel->reserve_arr;
711256Syl150051 		channel->reserve_arr = channel->free_arr;
723115Syl150051 		channel->reserve_length	= channel->reserve_initial;
733115Syl150051 		channel->free_arr =	tmp_arr;
741256Syl150051 		channel->reserve_top = channel->free_length;
751256Syl150051 		channel->free_length = channel->reserve_initial;
761256Syl150051 
771256Syl150051 		channel->stats.reserve_free_swaps_cnt++;
781256Syl150051 
791256Syl150051 		xge_debug_channel(XGE_TRACE,
803115Syl150051 			   "switch on channel %d:%d:%d,	reserve_length %d, "
813115Syl150051 			   "free_length	%d", channel->type,	channel->post_qid,
821256Syl150051 			   channel->compl_qid, channel->reserve_length,
831256Syl150051 			   channel->free_length);
841256Syl150051 
853115Syl150051 #if	defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
863115Syl150051 		xge_os_spin_unlock_irq(&channel->free_lock,	flags);
873115Syl150051 #elif defined(XGE_HAL_RX_MULTI_FREE) ||	defined(XGE_HAL_TX_MULTI_FREE)
883115Syl150051 		xge_os_spin_unlock(&channel->free_lock);
893115Syl150051 #endif
901256Syl150051 
911256Syl150051 		goto _alloc_after_swap;
921256Syl150051 	}
931256Syl150051 
943115Syl150051 #if	defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
953115Syl150051 	xge_os_spin_unlock_irq(&channel->free_lock,	flags);
963115Syl150051 #elif defined(XGE_HAL_RX_MULTI_FREE) ||	defined(XGE_HAL_TX_MULTI_FREE)
973115Syl150051 	xge_os_spin_unlock(&channel->free_lock);
983115Syl150051 #endif
991256Syl150051 
1001256Syl150051 	xge_debug_channel(XGE_TRACE, "channel %d:%d:%d is empty!",
1011256Syl150051 			   channel->type, channel->post_qid,
1021256Syl150051 			   channel->compl_qid);
1031256Syl150051 
1043115Syl150051 	channel->stats.full_cnt++;
1051256Syl150051 
1063115Syl150051 	*dtrh =	NULL;
1071256Syl150051 	return XGE_HAL_INF_OUT_OF_DESCRIPTORS;
1081256Syl150051 }
1091256Syl150051 
1101256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
__hal_channel_dtr_restore(xge_hal_channel_h channelh,xge_hal_dtr_h dtrh,int offset)1113115Syl150051 __hal_channel_dtr_restore(xge_hal_channel_h	channelh, xge_hal_dtr_h	dtrh,
1121256Syl150051 			  int offset)
1131256Syl150051 {
1143115Syl150051 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
1151256Syl150051 
1163115Syl150051 	/* restore a previously	allocated dtrh at current offset and update
1173115Syl150051 	 * the available reserve length	accordingly. If	dtrh is	null just
1181256Syl150051 	 * update the reserve length, only */
1191256Syl150051 
1201256Syl150051 	if (dtrh) {
1211256Syl150051 		channel->reserve_arr[channel->reserve_length + offset] = dtrh;
1223115Syl150051 		xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" restored for "
1233115Syl150051 			"channel %d:%d:%d, offset %d at	reserve	index %d, ",
1241256Syl150051 			(unsigned long long)(ulong_t)dtrh, channel->type,
1251256Syl150051 			channel->post_qid, channel->compl_qid, offset,
1263115Syl150051 			channel->reserve_length	+ offset);
1271256Syl150051 	}
1281256Syl150051 	else {
1293115Syl150051 		channel->reserve_length	+= offset;
1303115Syl150051 		xge_debug_channel(XGE_TRACE, "channel %d:%d:%d,	restored "
1313115Syl150051 			"for offset	%d,	new	reserve_length %d, free	length %d",
1321256Syl150051 			channel->type, channel->post_qid, channel->compl_qid,
1333115Syl150051 			offset,	channel->reserve_length, channel->free_length);
1341256Syl150051 	}
1351256Syl150051 }
1361256Syl150051 
1371256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
__hal_channel_dtr_post(xge_hal_channel_h channelh,xge_hal_dtr_h dtrh)1381256Syl150051 __hal_channel_dtr_post(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh)
1391256Syl150051 {
1403115Syl150051 	xge_hal_channel_t *channel	  =	(xge_hal_channel_t*)channelh;
1411256Syl150051 
1421256Syl150051 	xge_assert(channel->work_arr[channel->post_index] == NULL);
1431256Syl150051 
1441256Syl150051 	channel->work_arr[channel->post_index++] = dtrh;
1451256Syl150051 
1463115Syl150051 		/* wrap-around */
1473115Syl150051 	if (channel->post_index	== channel->length)
1483115Syl150051 		channel->post_index	= 0;
1491256Syl150051 }
1501256Syl150051 
1511256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
__hal_channel_dtr_try_complete(xge_hal_channel_h channelh,xge_hal_dtr_h * dtrh)1521256Syl150051 __hal_channel_dtr_try_complete(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh)
1531256Syl150051 {
1543115Syl150051 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
1551256Syl150051 
1561256Syl150051 	xge_assert(channel->work_arr);
1573115Syl150051 	xge_assert(channel->compl_index	< channel->length);
1581256Syl150051 
1593115Syl150051 	*dtrh =	channel->work_arr[channel->compl_index];
1601256Syl150051 }
1611256Syl150051 
1621256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
__hal_channel_dtr_complete(xge_hal_channel_h channelh)1631256Syl150051 __hal_channel_dtr_complete(xge_hal_channel_h channelh)
1641256Syl150051 {
1653115Syl150051 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
1661256Syl150051 
1673115Syl150051 	channel->work_arr[channel->compl_index]	= NULL;
1681256Syl150051 
1691256Syl150051 	/* wrap-around */
1701256Syl150051 	if (++channel->compl_index == channel->length)
1711256Syl150051 		channel->compl_index = 0;
1721256Syl150051 
1731256Syl150051 	channel->stats.total_compl_cnt++;
1741256Syl150051 }
1751256Syl150051 
1761256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
__hal_channel_dtr_free(xge_hal_channel_h channelh,xge_hal_dtr_h dtrh)1771256Syl150051 __hal_channel_dtr_free(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh)
1781256Syl150051 {
1793115Syl150051 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
1801256Syl150051 
1813115Syl150051 	channel->free_arr[--channel->free_length] =	dtrh;
1821256Syl150051 
1833115Syl150051 	xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" freed,	"
1843115Syl150051 			   "channel	%d:%d:%d, new free_length %d",
1851256Syl150051 			   (unsigned long long)(ulong_t)dtrh,
1861256Syl150051 			   channel->type, channel->post_qid,
1871256Syl150051 			   channel->compl_qid, channel->free_length);
1881256Syl150051 }
1891256Syl150051 
1901256Syl150051 /**
1913115Syl150051  * xge_hal_channel_dtr_count
192*6937Sxw161283  * @channelh: Channel handle. Obtained via xge_hal_channel_open().
1933115Syl150051  *
1943115Syl150051  * Retreive number of DTRs available. This function can not be called
195*6937Sxw161283  * from data path.
1963115Syl150051  */
1973115Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
xge_hal_channel_dtr_count(xge_hal_channel_h channelh)1983115Syl150051 xge_hal_channel_dtr_count(xge_hal_channel_h channelh)
1993115Syl150051 {
2003115Syl150051 	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
2013115Syl150051 
2023115Syl150051 	return ((channel->reserve_length - channel->reserve_top) +
2033115Syl150051 		(channel->reserve_initial - channel->free_length) -
2043115Syl150051 						channel->reserve_threshold);
2053115Syl150051 }
2063115Syl150051 
2073115Syl150051 /**
2083115Syl150051  * xge_hal_channel_userdata	- Get user-specified channel context.
2091256Syl150051  * @channelh: Channel handle. Obtained via xge_hal_channel_open().
2101256Syl150051  *
2113115Syl150051  * Returns:	per-channel	"user data", which can be any ULD-defined context.
2123115Syl150051  * The %userdata "gets"	into the channel at	open time
2133115Syl150051  * (see	xge_hal_channel_open()).
2141256Syl150051  *
2151256Syl150051  * See also: xge_hal_channel_open().
2161256Syl150051  */
2171256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void*
xge_hal_channel_userdata(xge_hal_channel_h channelh)2181256Syl150051 xge_hal_channel_userdata(xge_hal_channel_h channelh)
2191256Syl150051 {
2203115Syl150051 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
2211256Syl150051 
2221256Syl150051 	return channel->userdata;
2231256Syl150051 }
2241256Syl150051 
2251256Syl150051 /**
2263115Syl150051  * xge_hal_channel_id -	Get	channel	ID.
2271256Syl150051  * @channelh: Channel handle. Obtained via xge_hal_channel_open().
2281256Syl150051  *
2293115Syl150051  * Returns:	channel	ID.	For	link layer channel id is the number
2303115Syl150051  * in the range	from 0 to 7	that identifies	hardware ring or fifo,
2313115Syl150051  * depending on	the	channel	type.
2321256Syl150051  */
2331256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
xge_hal_channel_id(xge_hal_channel_h channelh)2341256Syl150051 xge_hal_channel_id(xge_hal_channel_h channelh)
2351256Syl150051 {
2363115Syl150051 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
2371256Syl150051 
2381256Syl150051 	return channel->post_qid;
2391256Syl150051 }
2401256Syl150051 
2411256Syl150051 /**
2423115Syl150051  * xge_hal_check_alignment - Check buffer alignment	and	calculate the
2433115Syl150051  * "misaligned"	portion.
2443115Syl150051  * @dma_pointer: DMA address of	the	buffer.
2451256Syl150051  * @size: Buffer size, in bytes.
2463115Syl150051  * @alignment: Alignment "granularity" (see	below),	in bytes.
2473115Syl150051  * @copy_size: Maximum number of bytes to "extract"	from the buffer
2483115Syl150051  * (in order to	spost it as	a separate scatter-gather entry). See below.
2491256Syl150051  *
2503115Syl150051  * Check buffer	alignment and calculate	"misaligned" portion, if exists.
2513115Syl150051  * The buffer is considered	aligned	if its address is multiple of
2523115Syl150051  * the specified @alignment. If	this is	the	case,
2531256Syl150051  * xge_hal_check_alignment() returns zero.
2543115Syl150051  * Otherwise, xge_hal_check_alignment()	uses the last argument,
2551256Syl150051  * @copy_size,
2563115Syl150051  * to calculate	the	size to	"extract" from the buffer. The @copy_size
2573115Syl150051  * may or may not be equal @alignment. The difference between these	two
2583115Syl150051  * arguments is	that the @alignment	is used	to make	the	decision: aligned
2593115Syl150051  * or not aligned. While the @copy_size	is used	to calculate the portion
2603115Syl150051  * of the buffer to	"extract", i.e.	to post	as a separate entry	in the
2613115Syl150051  * transmit	descriptor.	For	example, the combination
2623115Syl150051  * @alignment=8	and	@copy_size=64 will work	okay on	AMD	Opteron	boxes.
2631256Syl150051  *
2643115Syl150051  * Note: @copy_size	should be a	multiple of	@alignment.	In many	practical
2653115Syl150051  * cases @copy_size	and	@alignment will	probably be	equal.
2661256Syl150051  *
2671256Syl150051  * See also: xge_hal_fifo_dtr_buffer_set_aligned().
2681256Syl150051  */
2691256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
xge_hal_check_alignment(dma_addr_t dma_pointer,int size,int alignment,int copy_size)2703115Syl150051 xge_hal_check_alignment(dma_addr_t dma_pointer,	int	size, int alignment,
2713115Syl150051 		int	copy_size)
2721256Syl150051 {
2733115Syl150051 	int	misaligned_size;
2741256Syl150051 
2753115Syl150051 	misaligned_size	= (int)(dma_pointer	& (alignment - 1));
2761256Syl150051 	if (!misaligned_size) {
2771256Syl150051 		return 0;
2781256Syl150051 	}
2791256Syl150051 
2801256Syl150051 	if (size > copy_size) {
2813115Syl150051 		misaligned_size	= (int)(dma_pointer	& (copy_size - 1));
2823115Syl150051 		misaligned_size	= copy_size	- misaligned_size;
2831256Syl150051 	} else {
2843115Syl150051 		misaligned_size	= size;
2851256Syl150051 	}
2861256Syl150051 
2871256Syl150051 	return misaligned_size;
2881256Syl150051 }
2893115Syl150051 
290