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