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