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.
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.
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]
21 * Copyright (c) 2002-2006 Neterion, Inc.
25 #include "xgehal-channel.h"
28 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
29 __hal_channel_dtr_alloc(xge_hal_channel_h channelh
, xge_hal_dtr_h
*dtrh
)
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;
36 if (channel
->terminating
) {
40 if (channel
->reserve_length
- channel
->reserve_top
>
41 channel
->reserve_threshold
) {
44 *dtrh
= channel
->reserve_arr
[--channel
->reserve_length
];
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
);
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
);
61 /* switch between empty and full arrays */
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 */
67 if (channel
->reserve_initial
- channel
->free_length
>
68 channel
->reserve_threshold
) {
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
;
77 channel
->stats
.reserve_free_swaps_cnt
++;
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
);
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
);
91 goto _alloc_after_swap
;
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
);
100 xge_debug_channel(XGE_TRACE
, "channel %d:%d:%d is empty!",
101 channel
->type
, channel
->post_qid
,
104 channel
->stats
.full_cnt
++;
107 return XGE_HAL_INF_OUT_OF_DESCRIPTORS
;
110 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL
void
111 __hal_channel_dtr_restore(xge_hal_channel_h channelh
, xge_hal_dtr_h dtrh
,
114 xge_hal_channel_t
*channel
= (xge_hal_channel_t
*)channelh
;
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 */
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
);
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
);
137 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL
void
138 __hal_channel_dtr_post(xge_hal_channel_h channelh
, xge_hal_dtr_h dtrh
)
140 xge_hal_channel_t
*channel
= (xge_hal_channel_t
*)channelh
;
142 xge_assert(channel
->work_arr
[channel
->post_index
] == NULL
);
144 channel
->work_arr
[channel
->post_index
++] = dtrh
;
147 if (channel
->post_index
== channel
->length
)
148 channel
->post_index
= 0;
151 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL
void
152 __hal_channel_dtr_try_complete(xge_hal_channel_h channelh
, xge_hal_dtr_h
*dtrh
)
154 xge_hal_channel_t
*channel
= (xge_hal_channel_t
*)channelh
;
156 xge_assert(channel
->work_arr
);
157 xge_assert(channel
->compl_index
< channel
->length
);
159 *dtrh
= channel
->work_arr
[channel
->compl_index
];
162 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL
void
163 __hal_channel_dtr_complete(xge_hal_channel_h channelh
)
165 xge_hal_channel_t
*channel
= (xge_hal_channel_t
*)channelh
;
167 channel
->work_arr
[channel
->compl_index
] = NULL
;
170 if (++channel
->compl_index
== channel
->length
)
171 channel
->compl_index
= 0;
173 channel
->stats
.total_compl_cnt
++;
176 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL
void
177 __hal_channel_dtr_free(xge_hal_channel_h channelh
, xge_hal_dtr_h dtrh
)
179 xge_hal_channel_t
*channel
= (xge_hal_channel_t
*)channelh
;
181 channel
->free_arr
[--channel
->free_length
] = dtrh
;
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
);
191 * xge_hal_channel_dtr_count
192 * @channelh: Channel handle. Obtained via xge_hal_channel_open().
194 * Retreive number of DTRs available. This function can not be called
197 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL
int
198 xge_hal_channel_dtr_count(xge_hal_channel_h channelh
)
200 xge_hal_channel_t
*channel
= (xge_hal_channel_t
*)channelh
;
202 return ((channel
->reserve_length
- channel
->reserve_top
) +
203 (channel
->reserve_initial
- channel
->free_length
) -
204 channel
->reserve_threshold
);
208 * xge_hal_channel_userdata - Get user-specified channel context.
209 * @channelh: Channel handle. Obtained via xge_hal_channel_open().
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()).
215 * See also: xge_hal_channel_open().
217 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL
void*
218 xge_hal_channel_userdata(xge_hal_channel_h channelh
)
220 xge_hal_channel_t
*channel
= (xge_hal_channel_t
*)channelh
;
222 return channel
->userdata
;
226 * xge_hal_channel_id - Get channel ID.
227 * @channelh: Channel handle. Obtained via xge_hal_channel_open().
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.
233 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL
int
234 xge_hal_channel_id(xge_hal_channel_h channelh
)
236 xge_hal_channel_t
*channel
= (xge_hal_channel_t
*)channelh
;
238 return channel
->post_qid
;
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.
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,
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.
264 * Note: @copy_size should be a multiple of @alignment. In many practical
265 * cases @copy_size and @alignment will probably be equal.
267 * See also: xge_hal_fifo_dtr_buffer_set_aligned().
269 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL
int
270 xge_hal_check_alignment(dma_addr_t dma_pointer
, int size
, int alignment
,
275 misaligned_size
= (int)(dma_pointer
& (alignment
- 1));
276 if (!misaligned_size
) {
280 if (size
> copy_size
) {
281 misaligned_size
= (int)(dma_pointer
& (copy_size
- 1));
282 misaligned_size
= copy_size
- misaligned_size
;
284 misaligned_size
= size
;
287 return misaligned_size
;