xgehal-channel-fp.c revision 331722
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: stable/11/sys/dev/nxge/xgehal/xgehal-channel-fp.c 331722 2018-03-29 02:50:57Z eadler $
27 */
28
29#ifdef XGE_DEBUG_FP
30#include <dev/nxge/include/xgehal-channel.h>
31#endif
32
33__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
34__hal_channel_dtr_alloc(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh)
35{
36	void **tmp_arr;
37	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
38#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
39	unsigned long flags = 0;
40#endif
41	if (channel->terminating) {
42	    return XGE_HAL_FAIL;
43	}
44
45	if (channel->reserve_length - channel->reserve_top >
46	                    channel->reserve_threshold) {
47
48_alloc_after_swap:
49	    *dtrh = channel->reserve_arr[--channel->reserve_length];
50
51	    xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" allocated, "
52	               "channel %d:%d:%d, reserve_idx %d",
53	               (unsigned long long)(ulong_t)*dtrh,
54	               channel->type, channel->post_qid,
55	               channel->compl_qid, channel->reserve_length);
56
57	    return XGE_HAL_OK;
58	}
59
60#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
61	xge_os_spin_lock_irq(&channel->free_lock, flags);
62#elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE)
63	xge_os_spin_lock(&channel->free_lock);
64#endif
65
66	/* switch between empty and full arrays */
67
68	/* the idea behind such a design is that by having free and reserved
69	 * arrays separated we basically separated irq and non-irq parts.
70	 * i.e. no additional lock need to be done when we free a resource */
71
72	if (channel->reserve_initial - channel->free_length >
73	                channel->reserve_threshold) {
74
75	    tmp_arr = channel->reserve_arr;
76	    channel->reserve_arr = channel->free_arr;
77	    channel->reserve_length = channel->reserve_initial;
78	    channel->free_arr = tmp_arr;
79	    channel->reserve_top = channel->free_length;
80	    channel->free_length = channel->reserve_initial;
81
82	    channel->stats.reserve_free_swaps_cnt++;
83
84	    xge_debug_channel(XGE_TRACE,
85	           "switch on channel %d:%d:%d, reserve_length %d, "
86	           "free_length %d", channel->type, channel->post_qid,
87	           channel->compl_qid, channel->reserve_length,
88	           channel->free_length);
89
90#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
91	    xge_os_spin_unlock_irq(&channel->free_lock, flags);
92#elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE)
93	    xge_os_spin_unlock(&channel->free_lock);
94#endif
95
96	    goto _alloc_after_swap;
97	}
98
99#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ)
100	xge_os_spin_unlock_irq(&channel->free_lock, flags);
101#elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE)
102	xge_os_spin_unlock(&channel->free_lock);
103#endif
104
105	xge_debug_channel(XGE_TRACE, "channel %d:%d:%d is empty!",
106	           channel->type, channel->post_qid,
107	           channel->compl_qid);
108
109	channel->stats.full_cnt++;
110
111	*dtrh = NULL;
112	return XGE_HAL_INF_OUT_OF_DESCRIPTORS;
113}
114
115__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
116__hal_channel_dtr_restore(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
117	          int offset)
118{
119	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
120
121	/* restore a previously allocated dtrh at current offset and update
122	 * the available reserve length accordingly. If dtrh is null just
123	 * update the reserve length, only */
124
125	if (dtrh) {
126	    channel->reserve_arr[channel->reserve_length + offset] = dtrh;
127	    xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" restored for "
128	        "channel %d:%d:%d, offset %d at reserve index %d, ",
129	        (unsigned long long)(ulong_t)dtrh, channel->type,
130	        channel->post_qid, channel->compl_qid, offset,
131	        channel->reserve_length + offset);
132	}
133	else {
134	    channel->reserve_length += offset;
135	    xge_debug_channel(XGE_TRACE, "channel %d:%d:%d, restored "
136	        "for offset %d, new reserve_length %d, free length %d",
137	        channel->type, channel->post_qid, channel->compl_qid,
138	        offset, channel->reserve_length, channel->free_length);
139	}
140}
141
142__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
143__hal_channel_dtr_post(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh)
144{
145	xge_hal_channel_t *channel    = (xge_hal_channel_t*)channelh;
146
147	xge_assert(channel->work_arr[channel->post_index] == NULL);
148
149	channel->work_arr[channel->post_index++] = dtrh;
150
151	    /* wrap-around */
152	if (channel->post_index == channel->length)
153	    channel->post_index = 0;
154}
155
156__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
157__hal_channel_dtr_try_complete(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh)
158{
159	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
160
161	xge_assert(channel->work_arr);
162	xge_assert(channel->compl_index < channel->length);
163
164	*dtrh = channel->work_arr[channel->compl_index];
165}
166
167__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
168__hal_channel_dtr_complete(xge_hal_channel_h channelh)
169{
170	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
171
172	channel->work_arr[channel->compl_index] = NULL;
173
174	/* wrap-around */
175	if (++channel->compl_index == channel->length)
176	    channel->compl_index = 0;
177
178	channel->stats.total_compl_cnt++;
179}
180
181__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
182__hal_channel_dtr_free(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh)
183{
184	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
185
186	channel->free_arr[--channel->free_length] = dtrh;
187
188	xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" freed, "
189	           "channel %d:%d:%d, new free_length %d",
190	           (unsigned long long)(ulong_t)dtrh,
191	           channel->type, channel->post_qid,
192	           channel->compl_qid, channel->free_length);
193}
194
195/**
196 * xge_hal_channel_dtr_count
197 * @channelh: Channel handle. Obtained via xge_hal_channel_open().
198 *
199 * Retreive number of DTRs available. This function can not be called
200 * from data path.
201 */
202__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
203xge_hal_channel_dtr_count(xge_hal_channel_h channelh)
204{
205	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
206
207	return ((channel->reserve_length - channel->reserve_top) +
208	    (channel->reserve_initial - channel->free_length) -
209	                    channel->reserve_threshold);
210}
211
212/**
213 * xge_hal_channel_userdata - Get user-specified channel context.
214 * @channelh: Channel handle. Obtained via xge_hal_channel_open().
215 *
216 * Returns: per-channel "user data", which can be any ULD-defined context.
217 * The %userdata "gets" into the channel at open time
218 * (see xge_hal_channel_open()).
219 *
220 * See also: xge_hal_channel_open().
221 */
222__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void*
223xge_hal_channel_userdata(xge_hal_channel_h channelh)
224{
225	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
226
227	return channel->userdata;
228}
229
230/**
231 * xge_hal_channel_id - Get channel ID.
232 * @channelh: Channel handle. Obtained via xge_hal_channel_open().
233 *
234 * Returns: channel ID. For link layer channel id is the number
235 * in the range from 0 to 7 that identifies hardware ring or fifo,
236 * depending on the channel type.
237 */
238__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
239xge_hal_channel_id(xge_hal_channel_h channelh)
240{
241	xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
242
243	return channel->post_qid;
244}
245
246/**
247 * xge_hal_check_alignment - Check buffer alignment and calculate the
248 * "misaligned" portion.
249 * @dma_pointer: DMA address of the buffer.
250 * @size: Buffer size, in bytes.
251 * @alignment: Alignment "granularity" (see below), in bytes.
252 * @copy_size: Maximum number of bytes to "extract" from the buffer
253 * (in order to spost it as a separate scatter-gather entry). See below.
254 *
255 * Check buffer alignment and calculate "misaligned" portion, if exists.
256 * The buffer is considered aligned if its address is multiple of
257 * the specified @alignment. If this is the case,
258 * xge_hal_check_alignment() returns zero.
259 * Otherwise, xge_hal_check_alignment() uses the last argument,
260 * @copy_size,
261 * to calculate the size to "extract" from the buffer. The @copy_size
262 * may or may not be equal @alignment. The difference between these two
263 * arguments is that the @alignment is used to make the decision: aligned
264 * or not aligned. While the @copy_size is used to calculate the portion
265 * of the buffer to "extract", i.e. to post as a separate entry in the
266 * transmit descriptor. For example, the combination
267 * @alignment=8 and @copy_size=64 will work okay on AMD Opteron boxes.
268 *
269 * Note: @copy_size should be a multiple of @alignment. In many practical
270 * cases @copy_size and @alignment will probably be equal.
271 *
272 * See also: xge_hal_fifo_dtr_buffer_set_aligned().
273 */
274__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
275xge_hal_check_alignment(dma_addr_t dma_pointer, int size, int alignment,
276	    int copy_size)
277{
278	int misaligned_size;
279
280	misaligned_size = (int)(dma_pointer & (alignment - 1));
281	if (!misaligned_size) {
282	    return 0;
283	}
284
285	if (size > copy_size) {
286	    misaligned_size = (int)(dma_pointer & (copy_size - 1));
287	    misaligned_size = copy_size - misaligned_size;
288	} else {
289	    misaligned_size = size;
290	}
291
292	return misaligned_size;
293}
294
295