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