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