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