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 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 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 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 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 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 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 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* 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 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 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