1a23fd118Syl /*
2a23fd118Syl  * CDDL HEADER START
3a23fd118Syl  *
4a23fd118Syl  * The contents of this file are subject to the terms of the
5a23fd118Syl  * Common Development and Distribution License (the "License").
6a23fd118Syl  * You may not use this file except in compliance with the License.
7a23fd118Syl  *
8a23fd118Syl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a23fd118Syl  * or http://www.opensolaris.org/os/licensing.
10a23fd118Syl  * See the License for the specific language governing permissions
11a23fd118Syl  * and limitations under the License.
12a23fd118Syl  *
13a23fd118Syl  * When distributing Covered Code, include this CDDL HEADER in each
14a23fd118Syl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a23fd118Syl  * If applicable, add the following below this CDDL HEADER, with the
16a23fd118Syl  * fields enclosed by brackets "[]" replaced with your own identifying
17a23fd118Syl  * information: Portions Copyright [yyyy] [name of copyright owner]
18a23fd118Syl  *
19a23fd118Syl  * CDDL HEADER END
20a23fd118Syl  *
218347601bSyl  * Copyright (c) 2002-2006 Neterion, Inc.
22a23fd118Syl  */
23a23fd118Syl 
24a23fd118Syl #ifdef XGE_DEBUG_FP
25a23fd118Syl #include "xgehal-channel.h"
26a23fd118Syl #endif
27a23fd118Syl 
28a23fd118Syl __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
__hal_channel_dtr_alloc(xge_hal_channel_h channelh,xge_hal_dtr_h * dtrh)298347601bSyl __hal_channel_dtr_alloc(xge_hal_channel_h channelh,	xge_hal_dtr_h *dtrh)
30a23fd118Syl {
31a23fd118Syl 	void **tmp_arr;
328347601bSyl 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
338347601bSyl #if	defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
348347601bSyl 	unsigned long flags	= 0;
358347601bSyl #endif
36*7eced415Sxw 	if (channel->terminating) {
37*7eced415Sxw 		return XGE_HAL_FAIL;
38*7eced415Sxw 	}
39a23fd118Syl 
408347601bSyl 	if (channel->reserve_length	- channel->reserve_top >
418347601bSyl 						channel->reserve_threshold)	{
42a23fd118Syl 
43a23fd118Syl _alloc_after_swap:
448347601bSyl 		*dtrh =	channel->reserve_arr[--channel->reserve_length];
45a23fd118Syl 
468347601bSyl 		xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" allocated,	"
478347601bSyl 				   "channel	%d:%d:%d, reserve_idx %d",
48a23fd118Syl 				   (unsigned long long)(ulong_t)*dtrh,
49a23fd118Syl 				   channel->type, channel->post_qid,
50a23fd118Syl 				   channel->compl_qid, channel->reserve_length);
51a23fd118Syl 
52a23fd118Syl 		return XGE_HAL_OK;
53a23fd118Syl 	}
54a23fd118Syl 
558347601bSyl #if	defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
56a23fd118Syl 	xge_os_spin_lock_irq(&channel->free_lock, flags);
578347601bSyl #elif defined(XGE_HAL_RX_MULTI_FREE) ||	defined(XGE_HAL_TX_MULTI_FREE)
588347601bSyl 	xge_os_spin_lock(&channel->free_lock);
598347601bSyl #endif
60a23fd118Syl 
618347601bSyl 	/* switch between empty	and	full arrays	*/
62a23fd118Syl 
638347601bSyl 	/* the idea	behind such	a design is	that by	having free	and	reserved
648347601bSyl 	 * arrays separated	we basically separated irq and non-irq parts.
658347601bSyl 	 * i.e.	no additional lock need	to be done when	we free	a resource */
66a23fd118Syl 
678347601bSyl 	if (channel->reserve_initial - channel->free_length	>
688347601bSyl 					channel->reserve_threshold)	{
69a23fd118Syl 
708347601bSyl 		tmp_arr	= channel->reserve_arr;
71a23fd118Syl 		channel->reserve_arr = channel->free_arr;
728347601bSyl 		channel->reserve_length	= channel->reserve_initial;
738347601bSyl 		channel->free_arr =	tmp_arr;
74a23fd118Syl 		channel->reserve_top = channel->free_length;
75a23fd118Syl 		channel->free_length = channel->reserve_initial;
76a23fd118Syl 
77a23fd118Syl 		channel->stats.reserve_free_swaps_cnt++;
78a23fd118Syl 
79a23fd118Syl 		xge_debug_channel(XGE_TRACE,
808347601bSyl 			   "switch on channel %d:%d:%d,	reserve_length %d, "
818347601bSyl 			   "free_length	%d", channel->type,	channel->post_qid,
82a23fd118Syl 			   channel->compl_qid, channel->reserve_length,
83a23fd118Syl 			   channel->free_length);
84a23fd118Syl 
858347601bSyl #if	defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
868347601bSyl 		xge_os_spin_unlock_irq(&channel->free_lock,	flags);
878347601bSyl #elif defined(XGE_HAL_RX_MULTI_FREE) ||	defined(XGE_HAL_TX_MULTI_FREE)
888347601bSyl 		xge_os_spin_unlock(&channel->free_lock);
898347601bSyl #endif
90a23fd118Syl 
91a23fd118Syl 		goto _alloc_after_swap;
92a23fd118Syl 	}
93a23fd118Syl 
948347601bSyl #if	defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
958347601bSyl 	xge_os_spin_unlock_irq(&channel->free_lock,	flags);
968347601bSyl #elif defined(XGE_HAL_RX_MULTI_FREE) ||	defined(XGE_HAL_TX_MULTI_FREE)
978347601bSyl 	xge_os_spin_unlock(&channel->free_lock);
988347601bSyl #endif
99a23fd118Syl 
100a23fd118Syl 	xge_debug_channel(XGE_TRACE, "channel %d:%d:%d is empty!",
101a23fd118Syl 			   channel->type, channel->post_qid,
102a23fd118Syl 			   channel->compl_qid);
103a23fd118Syl 
1048347601bSyl 	channel->stats.full_cnt++;
105a23fd118Syl 
1068347601bSyl 	*dtrh =	NULL;
107a23fd118Syl 	return XGE_HAL_INF_OUT_OF_DESCRIPTORS;
108a23fd118Syl }
109a23fd118Syl 
110a23fd118Syl __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
__hal_channel_dtr_restore(xge_hal_channel_h channelh,xge_hal_dtr_h dtrh,int offset)1118347601bSyl __hal_channel_dtr_restore(xge_hal_channel_h	channelh, xge_hal_dtr_h	dtrh,
112a23fd118Syl 			  int offset)
113a23fd118Syl {
1148347601bSyl 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
115a23fd118Syl 
1168347601bSyl 	/* restore a previously	allocated dtrh at current offset and update
1178347601bSyl 	 * the available reserve length	accordingly. If	dtrh is	null just
118a23fd118Syl 	 * update the reserve length, only */
119a23fd118Syl 
120a23fd118Syl 	if (dtrh) {
121a23fd118Syl 		channel->reserve_arr[channel->reserve_length + offset] = dtrh;
1228347601bSyl 		xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" restored for "
1238347601bSyl 			"channel %d:%d:%d, offset %d at	reserve	index %d, ",
124a23fd118Syl 			(unsigned long long)(ulong_t)dtrh, channel->type,
125a23fd118Syl 			channel->post_qid, channel->compl_qid, offset,
1268347601bSyl 			channel->reserve_length	+ offset);
127a23fd118Syl 	}
128a23fd118Syl 	else {
1298347601bSyl 		channel->reserve_length	+= offset;
1308347601bSyl 		xge_debug_channel(XGE_TRACE, "channel %d:%d:%d,	restored "
1318347601bSyl 			"for offset	%d,	new	reserve_length %d, free	length %d",
132a23fd118Syl 			channel->type, channel->post_qid, channel->compl_qid,
1338347601bSyl 			offset,	channel->reserve_length, channel->free_length);
134a23fd118Syl 	}
135a23fd118Syl }
136a23fd118Syl 
137a23fd118Syl __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
__hal_channel_dtr_post(xge_hal_channel_h channelh,xge_hal_dtr_h dtrh)138a23fd118Syl __hal_channel_dtr_post(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh)
139a23fd118Syl {
1408347601bSyl 	xge_hal_channel_t *channel	  =	(xge_hal_channel_t*)channelh;
141a23fd118Syl 
142a23fd118Syl 	xge_assert(channel->work_arr[channel->post_index] == NULL);
143a23fd118Syl 
144a23fd118Syl 	channel->work_arr[channel->post_index++] = dtrh;
145a23fd118Syl 
1468347601bSyl 		/* wrap-around */
1478347601bSyl 	if (channel->post_index	== channel->length)
1488347601bSyl 		channel->post_index	= 0;
149a23fd118Syl }
150a23fd118Syl 
151a23fd118Syl __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
__hal_channel_dtr_try_complete(xge_hal_channel_h channelh,xge_hal_dtr_h * dtrh)152a23fd118Syl __hal_channel_dtr_try_complete(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh)
153a23fd118Syl {
1548347601bSyl 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
155a23fd118Syl 
156a23fd118Syl 	xge_assert(channel->work_arr);
1578347601bSyl 	xge_assert(channel->compl_index	< channel->length);
158a23fd118Syl 
1598347601bSyl 	*dtrh =	channel->work_arr[channel->compl_index];
160a23fd118Syl }
161a23fd118Syl 
162a23fd118Syl __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
__hal_channel_dtr_complete(xge_hal_channel_h channelh)163a23fd118Syl __hal_channel_dtr_complete(xge_hal_channel_h channelh)
164a23fd118Syl {
1658347601bSyl 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
166a23fd118Syl 
1678347601bSyl 	channel->work_arr[channel->compl_index]	= NULL;
168a23fd118Syl 
169a23fd118Syl 	/* wrap-around */
170a23fd118Syl 	if (++channel->compl_index == channel->length)
171a23fd118Syl 		channel->compl_index = 0;
172a23fd118Syl 
173a23fd118Syl 	channel->stats.total_compl_cnt++;
174a23fd118Syl }
175a23fd118Syl 
176a23fd118Syl __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
__hal_channel_dtr_free(xge_hal_channel_h channelh,xge_hal_dtr_h dtrh)177a23fd118Syl __hal_channel_dtr_free(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh)
178a23fd118Syl {
1798347601bSyl 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
180a23fd118Syl 
1818347601bSyl 	channel->free_arr[--channel->free_length] =	dtrh;
182a23fd118Syl 
1838347601bSyl 	xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" freed,	"
1848347601bSyl 			   "channel	%d:%d:%d, new free_length %d",
185a23fd118Syl 			   (unsigned long long)(ulong_t)dtrh,
186a23fd118Syl 			   channel->type, channel->post_qid,
187a23fd118Syl 			   channel->compl_qid, channel->free_length);
188a23fd118Syl }
189a23fd118Syl 
190a23fd118Syl /**
1918347601bSyl  * xge_hal_channel_dtr_count
192*7eced415Sxw  * @channelh: Channel handle. Obtained via xge_hal_channel_open().
1938347601bSyl  *
1948347601bSyl  * Retreive number of DTRs available. This function can not be called
195*7eced415Sxw  * from data path.
1968347601bSyl  */
1978347601bSyl __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
xge_hal_channel_dtr_count(xge_hal_channel_h channelh)1988347601bSyl xge_hal_channel_dtr_count(xge_hal_channel_h channelh)
1998347601bSyl {
2008347601bSyl 	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
2018347601bSyl 
2028347601bSyl 	return ((channel->reserve_length - channel->reserve_top) +
2038347601bSyl 		(channel->reserve_initial - channel->free_length) -
2048347601bSyl 						channel->reserve_threshold);
2058347601bSyl }
2068347601bSyl 
2078347601bSyl /**
2088347601bSyl  * xge_hal_channel_userdata	- Get user-specified channel context.
209a23fd118Syl  * @channelh: Channel handle. Obtained via xge_hal_channel_open().
210a23fd118Syl  *
2118347601bSyl  * Returns:	per-channel	"user data", which can be any ULD-defined context.
2128347601bSyl  * The %userdata "gets"	into the channel at	open time
2138347601bSyl  * (see	xge_hal_channel_open()).
214a23fd118Syl  *
215a23fd118Syl  * See also: xge_hal_channel_open().
216a23fd118Syl  */
217a23fd118Syl __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void*
xge_hal_channel_userdata(xge_hal_channel_h channelh)218a23fd118Syl xge_hal_channel_userdata(xge_hal_channel_h channelh)
219a23fd118Syl {
2208347601bSyl 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
221a23fd118Syl 
222a23fd118Syl 	return channel->userdata;
223a23fd118Syl }
224a23fd118Syl 
225a23fd118Syl /**
2268347601bSyl  * xge_hal_channel_id -	Get	channel	ID.
227a23fd118Syl  * @channelh: Channel handle. Obtained via xge_hal_channel_open().
228a23fd118Syl  *
2298347601bSyl  * Returns:	channel	ID.	For	link layer channel id is the number
2308347601bSyl  * in the range	from 0 to 7	that identifies	hardware ring or fifo,
2318347601bSyl  * depending on	the	channel	type.
232a23fd118Syl  */
233a23fd118Syl __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
xge_hal_channel_id(xge_hal_channel_h channelh)234a23fd118Syl xge_hal_channel_id(xge_hal_channel_h channelh)
235a23fd118Syl {
2368347601bSyl 	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
237a23fd118Syl 
238a23fd118Syl 	return channel->post_qid;
239a23fd118Syl }
240a23fd118Syl 
241a23fd118Syl /**
2428347601bSyl  * xge_hal_check_alignment - Check buffer alignment	and	calculate the
2438347601bSyl  * "misaligned"	portion.
2448347601bSyl  * @dma_pointer: DMA address of	the	buffer.
245a23fd118Syl  * @size: Buffer size, in bytes.
2468347601bSyl  * @alignment: Alignment "granularity" (see	below),	in bytes.
2478347601bSyl  * @copy_size: Maximum number of bytes to "extract"	from the buffer
2488347601bSyl  * (in order to	spost it as	a separate scatter-gather entry). See below.
249a23fd118Syl  *
2508347601bSyl  * Check buffer	alignment and calculate	"misaligned" portion, if exists.
2518347601bSyl  * The buffer is considered	aligned	if its address is multiple of
2528347601bSyl  * the specified @alignment. If	this is	the	case,
253a23fd118Syl  * xge_hal_check_alignment() returns zero.
2548347601bSyl  * Otherwise, xge_hal_check_alignment()	uses the last argument,
255a23fd118Syl  * @copy_size,
2568347601bSyl  * to calculate	the	size to	"extract" from the buffer. The @copy_size
2578347601bSyl  * may or may not be equal @alignment. The difference between these	two
2588347601bSyl  * arguments is	that the @alignment	is used	to make	the	decision: aligned
2598347601bSyl  * or not aligned. While the @copy_size	is used	to calculate the portion
2608347601bSyl  * of the buffer to	"extract", i.e.	to post	as a separate entry	in the
2618347601bSyl  * transmit	descriptor.	For	example, the combination
2628347601bSyl  * @alignment=8	and	@copy_size=64 will work	okay on	AMD	Opteron	boxes.
263a23fd118Syl  *
2648347601bSyl  * Note: @copy_size	should be a	multiple of	@alignment.	In many	practical
2658347601bSyl  * cases @copy_size	and	@alignment will	probably be	equal.
266a23fd118Syl  *
267a23fd118Syl  * See also: xge_hal_fifo_dtr_buffer_set_aligned().
268a23fd118Syl  */
269a23fd118Syl __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
xge_hal_check_alignment(dma_addr_t dma_pointer,int size,int alignment,int copy_size)2708347601bSyl xge_hal_check_alignment(dma_addr_t dma_pointer,	int	size, int alignment,
2718347601bSyl 		int	copy_size)
272a23fd118Syl {
2738347601bSyl 	int	misaligned_size;
274a23fd118Syl 
2758347601bSyl 	misaligned_size	= (int)(dma_pointer	& (alignment - 1));
276a23fd118Syl 	if (!misaligned_size) {
277a23fd118Syl 		return 0;
278a23fd118Syl 	}
279a23fd118Syl 
280a23fd118Syl 	if (size > copy_size) {
2818347601bSyl 		misaligned_size	= (int)(dma_pointer	& (copy_size - 1));
2828347601bSyl 		misaligned_size	= copy_size	- misaligned_size;
283a23fd118Syl 	} else {
2848347601bSyl 		misaligned_size	= size;
285a23fd118Syl 	}
286a23fd118Syl 
287a23fd118Syl 	return misaligned_size;
288a23fd118Syl }
2898347601bSyl 
290