xgehal-channel-fp.c revision 171095
1/*-
2 * Copyright (c) 2002-2007 Neterion, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/nxge/xgehal/xgehal-channel-fp.c 171095 2007-06-29 22:47:18Z sam $
27 */
28
29/*
30 *	FileName :	  xgehal-channel-fp.c
31 *
32 *	Description:  HAL channel object functionality (fast path)
33 *
34 *	Created:	  10 June 2004
35 */
36
37#ifdef XGE_DEBUG_FP
38#include <dev/nxge/include/xgehal-channel.h>
39#endif
40
41__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
42__hal_channel_dtr_alloc(xge_hal_channel_h channelh,	xge_hal_dtr_h *dtrh)
43{
44	void **tmp_arr;
45	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
46#if	defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
47	unsigned long flags	= 0;
48#endif
49
50	if (channel->reserve_length	- channel->reserve_top >
51						channel->reserve_threshold)	{
52
53_alloc_after_swap:
54		*dtrh =	channel->reserve_arr[--channel->reserve_length];
55
56		xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" allocated,	"
57				   "channel	%d:%d:%d, reserve_idx %d",
58				   (unsigned long long)(ulong_t)*dtrh,
59				   channel->type, channel->post_qid,
60				   channel->compl_qid, channel->reserve_length);
61
62		return XGE_HAL_OK;
63	}
64
65#if	defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
66	xge_os_spin_lock_irq(&channel->free_lock, flags);
67#elif defined(XGE_HAL_RX_MULTI_FREE) ||	defined(XGE_HAL_TX_MULTI_FREE)
68	xge_os_spin_lock(&channel->free_lock);
69#endif
70
71	/* switch between empty	and	full arrays	*/
72
73	/* the idea	behind such	a design is	that by	having free	and	reserved
74	 * arrays separated	we basically separated irq and non-irq parts.
75	 * i.e.	no additional lock need	to be done when	we free	a resource */
76
77	if (channel->reserve_initial - channel->free_length	>
78					channel->reserve_threshold)	{
79
80		tmp_arr	= channel->reserve_arr;
81		channel->reserve_arr = channel->free_arr;
82		channel->reserve_length	= channel->reserve_initial;
83		channel->free_arr =	tmp_arr;
84		channel->reserve_top = channel->free_length;
85		channel->free_length = channel->reserve_initial;
86
87		channel->stats.reserve_free_swaps_cnt++;
88
89		xge_debug_channel(XGE_TRACE,
90			   "switch on channel %d:%d:%d,	reserve_length %d, "
91			   "free_length	%d", channel->type,	channel->post_qid,
92			   channel->compl_qid, channel->reserve_length,
93			   channel->free_length);
94
95#if	defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
96		xge_os_spin_unlock_irq(&channel->free_lock,	flags);
97#elif defined(XGE_HAL_RX_MULTI_FREE) ||	defined(XGE_HAL_TX_MULTI_FREE)
98		xge_os_spin_unlock(&channel->free_lock);
99#endif
100
101		goto _alloc_after_swap;
102	}
103
104#if	defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
105	xge_os_spin_unlock_irq(&channel->free_lock,	flags);
106#elif defined(XGE_HAL_RX_MULTI_FREE) ||	defined(XGE_HAL_TX_MULTI_FREE)
107	xge_os_spin_unlock(&channel->free_lock);
108#endif
109
110	xge_debug_channel(XGE_TRACE, "channel %d:%d:%d is empty!",
111			   channel->type, channel->post_qid,
112			   channel->compl_qid);
113
114	channel->stats.full_cnt++;
115
116	*dtrh =	NULL;
117	return XGE_HAL_INF_OUT_OF_DESCRIPTORS;
118}
119
120__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
121__hal_channel_dtr_restore(xge_hal_channel_h	channelh, xge_hal_dtr_h	dtrh,
122			  int offset)
123{
124	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
125
126	/* restore a previously	allocated dtrh at current offset and update
127	 * the available reserve length	accordingly. If	dtrh is	null just
128	 * update the reserve length, only */
129
130	if (dtrh) {
131		channel->reserve_arr[channel->reserve_length + offset] = dtrh;
132		xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" restored for "
133			"channel %d:%d:%d, offset %d at	reserve	index %d, ",
134			(unsigned long long)(ulong_t)dtrh, channel->type,
135			channel->post_qid, channel->compl_qid, offset,
136			channel->reserve_length	+ offset);
137	}
138	else {
139		channel->reserve_length	+= offset;
140		xge_debug_channel(XGE_TRACE, "channel %d:%d:%d,	restored "
141			"for offset	%d,	new	reserve_length %d, free	length %d",
142			channel->type, channel->post_qid, channel->compl_qid,
143			offset,	channel->reserve_length, channel->free_length);
144	}
145}
146
147__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
148__hal_channel_dtr_post(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh)
149{
150	xge_hal_channel_t *channel	  =	(xge_hal_channel_t*)channelh;
151
152	xge_assert(channel->work_arr[channel->post_index] == NULL);
153
154	channel->work_arr[channel->post_index++] = dtrh;
155
156		/* wrap-around */
157	if (channel->post_index	== channel->length)
158		channel->post_index	= 0;
159}
160
161__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
162__hal_channel_dtr_try_complete(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh)
163{
164	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
165
166	xge_assert(channel->work_arr);
167	xge_assert(channel->compl_index	< channel->length);
168
169	*dtrh =	channel->work_arr[channel->compl_index];
170}
171
172__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
173__hal_channel_dtr_complete(xge_hal_channel_h channelh)
174{
175	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
176
177	channel->work_arr[channel->compl_index]	= NULL;
178
179	/* wrap-around */
180	if (++channel->compl_index == channel->length)
181		channel->compl_index = 0;
182
183	channel->stats.total_compl_cnt++;
184}
185
186__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
187__hal_channel_dtr_free(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh)
188{
189	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
190
191	channel->free_arr[--channel->free_length] =	dtrh;
192
193	xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" freed,	"
194			   "channel	%d:%d:%d, new free_length %d",
195			   (unsigned long long)(ulong_t)dtrh,
196			   channel->type, channel->post_qid,
197			   channel->compl_qid, channel->free_length);
198}
199
200/**
201 * xge_hal_channel_dtr_count
202 * @channelh: Channel handle. Obtained via xge_hal_channel_open().
203 *
204 * Retreive number of DTRs available. This function can not be called
205 * from data path.
206 */
207__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
208xge_hal_channel_dtr_count(xge_hal_channel_h channelh)
209{
210	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
211
212	return ((channel->reserve_length - channel->reserve_top) +
213		(channel->reserve_initial - channel->free_length) -
214						channel->reserve_threshold);
215}
216
217/**
218 * xge_hal_channel_userdata	- Get user-specified channel context.
219 * @channelh: Channel handle. Obtained via xge_hal_channel_open().
220 *
221 * Returns:	per-channel	"user data", which can be any ULD-defined context.
222 * The %userdata "gets"	into the channel at	open time
223 * (see	xge_hal_channel_open()).
224 *
225 * See also: xge_hal_channel_open().
226 */
227__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void*
228xge_hal_channel_userdata(xge_hal_channel_h channelh)
229{
230	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
231
232	return channel->userdata;
233}
234
235/**
236 * xge_hal_channel_id -	Get	channel	ID.
237 * @channelh: Channel handle. Obtained via xge_hal_channel_open().
238 *
239 * Returns:	channel	ID.	For	link layer channel id is the number
240 * in the range	from 0 to 7	that identifies	hardware ring or fifo,
241 * depending on	the	channel	type.
242 */
243__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
244xge_hal_channel_id(xge_hal_channel_h channelh)
245{
246	xge_hal_channel_t *channel = (xge_hal_channel_t	*)channelh;
247
248	return channel->post_qid;
249}
250
251/**
252 * xge_hal_check_alignment - Check buffer alignment	and	calculate the
253 * "misaligned"	portion.
254 * @dma_pointer: DMA address of	the	buffer.
255 * @size: Buffer size, in bytes.
256 * @alignment: Alignment "granularity" (see	below),	in bytes.
257 * @copy_size: Maximum number of bytes to "extract"	from the buffer
258 * (in order to	spost it as	a separate scatter-gather entry). See below.
259 *
260 * Check buffer	alignment and calculate	"misaligned" portion, if exists.
261 * The buffer is considered	aligned	if its address is multiple of
262 * the specified @alignment. If	this is	the	case,
263 * xge_hal_check_alignment() returns zero.
264 * Otherwise, xge_hal_check_alignment()	uses the last argument,
265 * @copy_size,
266 * to calculate	the	size to	"extract" from the buffer. The @copy_size
267 * may or may not be equal @alignment. The difference between these	two
268 * arguments is	that the @alignment	is used	to make	the	decision: aligned
269 * or not aligned. While the @copy_size	is used	to calculate the portion
270 * of the buffer to	"extract", i.e.	to post	as a separate entry	in the
271 * transmit	descriptor.	For	example, the combination
272 * @alignment=8	and	@copy_size=64 will work	okay on	AMD	Opteron	boxes.
273 *
274 * Note: @copy_size	should be a	multiple of	@alignment.	In many	practical
275 * cases @copy_size	and	@alignment will	probably be	equal.
276 *
277 * See also: xge_hal_fifo_dtr_buffer_set_aligned().
278 */
279__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
280xge_hal_check_alignment(dma_addr_t dma_pointer,	int	size, int alignment,
281		int	copy_size)
282{
283	int	misaligned_size;
284
285	misaligned_size	= (int)(dma_pointer	& (alignment - 1));
286	if (!misaligned_size) {
287		return 0;
288	}
289
290	if (size > copy_size) {
291		misaligned_size	= (int)(dma_pointer	& (copy_size - 1));
292		misaligned_size	= copy_size	- misaligned_size;
293	} else {
294		misaligned_size	= size;
295	}
296
297	return misaligned_size;
298}
299
300