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 22 /* 23 * Copyright (c) 2002-2005 Neterion, Inc. 24 * All right Reserved. 25 * 26 * FileName : xgehal-channel-fp.c 27 * 28 * Description: HAL channel object functionality (fast path) 29 * 30 * Created: 10 June 2004 31 */ 32 33 #ifdef XGE_DEBUG_FP 34 #include "xgehal-channel.h" 35 #endif 36 37 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e 38 __hal_channel_dtr_alloc(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh) 39 { 40 void **tmp_arr; 41 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 42 unsigned long flags = 0; 43 44 if (channel->reserve_length - channel->reserve_top > 45 channel->reserve_threshold) { 46 47 _alloc_after_swap: 48 *dtrh = channel->reserve_arr[--channel->reserve_length]; 49 50 xge_debug_channel(XGE_TRACE, "dtrh 0x%llx allocated, " 51 "channel %d:%d:%d, reserve_idx %d", 52 (unsigned long long)(ulong_t)*dtrh, 53 channel->type, channel->post_qid, 54 channel->compl_qid, channel->reserve_length); 55 56 return XGE_HAL_OK; 57 } 58 59 xge_os_spin_lock_irq(&channel->free_lock, flags); 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 xge_os_spin_unlock_irq(&channel->free_lock, flags); 86 87 goto _alloc_after_swap; 88 } 89 90 xge_os_spin_unlock_irq(&channel->free_lock, flags); 91 92 xge_debug_channel(XGE_TRACE, "channel %d:%d:%d is empty!", 93 channel->type, channel->post_qid, 94 channel->compl_qid); 95 96 channel->stats.out_of_dtrs_cnt++; 97 98 *dtrh = NULL; 99 return XGE_HAL_INF_OUT_OF_DESCRIPTORS; 100 } 101 102 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void 103 __hal_channel_dtr_restore(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh, 104 int offset) 105 { 106 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 107 108 /* restore a previously allocated dtrh at current offset and update 109 * the available reserve length accordingly. If dtrh is null just 110 * update the reserve length, only */ 111 112 if (dtrh) { 113 channel->reserve_arr[channel->reserve_length + offset] = dtrh; 114 xge_debug_channel(XGE_TRACE, "dtrh 0x%llx restored for " 115 "channel %d:%d:%d, offset %d at reserve index %d, ", 116 (unsigned long long)(ulong_t)dtrh, channel->type, 117 channel->post_qid, channel->compl_qid, offset, 118 channel->reserve_length + offset); 119 } 120 else { 121 channel->reserve_length += offset; 122 xge_debug_channel(XGE_TRACE, "channel %d:%d:%d, restored " 123 "for offset %d, new reserve_length %d, free length %d", 124 channel->type, channel->post_qid, channel->compl_qid, 125 offset, channel->reserve_length, channel->free_length); 126 } 127 } 128 129 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void 130 __hal_channel_dtr_post(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh) 131 { 132 xge_hal_channel_t *channel = (xge_hal_channel_t*)channelh; 133 134 xge_assert(channel->work_arr[channel->post_index] == NULL); 135 136 channel->work_arr[channel->post_index++] = dtrh; 137 138 /* wrap-around */ 139 if (channel->post_index == channel->length) 140 channel->post_index = 0; 141 } 142 143 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void 144 __hal_channel_dtr_try_complete(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh) 145 { 146 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 147 148 xge_assert(channel->work_arr); 149 xge_assert(channel->compl_index < channel->length); 150 151 *dtrh = channel->work_arr[channel->compl_index]; 152 } 153 154 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void 155 __hal_channel_dtr_complete(xge_hal_channel_h channelh) 156 { 157 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 158 159 channel->work_arr[channel->compl_index] = NULL; 160 161 /* wrap-around */ 162 if (++channel->compl_index == channel->length) 163 channel->compl_index = 0; 164 165 channel->stats.total_compl_cnt++; 166 } 167 168 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void 169 __hal_channel_dtr_free(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh) 170 { 171 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 172 173 channel->free_arr[--channel->free_length] = dtrh; 174 175 xge_debug_channel(XGE_TRACE, "dtrh 0x%llx freed, " 176 "channel %d:%d:%d, new free_length %d", 177 (unsigned long long)(ulong_t)dtrh, 178 channel->type, channel->post_qid, 179 channel->compl_qid, channel->free_length); 180 } 181 182 /** 183 * xge_hal_channel_userdata - Get user-specified channel context. 184 * @channelh: Channel handle. Obtained via xge_hal_channel_open(). 185 * 186 * Returns: per-channel "user data", which can be any ULD-defined context. 187 * The %userdata "gets" into the channel at open time 188 * (see xge_hal_channel_open()). 189 * 190 * See also: xge_hal_channel_open(). 191 */ 192 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void* 193 xge_hal_channel_userdata(xge_hal_channel_h channelh) 194 { 195 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 196 197 return channel->userdata; 198 } 199 200 /** 201 * xge_hal_channel_id - Get channel ID. 202 * @channelh: Channel handle. Obtained via xge_hal_channel_open(). 203 * 204 * Returns: channel ID. For link layer channel id is the number 205 * in the range from 0 to 7 that identifies hardware ring or fifo, 206 * depending on the channel type. 207 */ 208 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int 209 xge_hal_channel_id(xge_hal_channel_h channelh) 210 { 211 xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 212 213 return channel->post_qid; 214 } 215 216 /** 217 * xge_hal_check_alignment - Check buffer alignment and calculate the 218 * "misaligned" portion. 219 * @dma_pointer: DMA address of the buffer. 220 * @size: Buffer size, in bytes. 221 * @alignment: Alignment "granularity" (see below), in bytes. 222 * @copy_size: Maximum number of bytes to "extract" from the buffer 223 * (in order to spost it as a separate scatter-gather entry). See below. 224 * 225 * Check buffer alignment and calculate "misaligned" portion, if exists. 226 * The buffer is considered aligned if its address is multiple of 227 * the specified @alignment. If this is the case, 228 * xge_hal_check_alignment() returns zero. 229 * Otherwise, xge_hal_check_alignment() uses the last argument, 230 * @copy_size, 231 * to calculate the size to "extract" from the buffer. The @copy_size 232 * may or may not be equal @alignment. The difference between these two 233 * arguments is that the @alignment is used to make the decision: aligned 234 * or not aligned. While the @copy_size is used to calculate the portion 235 * of the buffer to "extract", i.e. to post as a separate entry in the 236 * transmit descriptor. For example, the combination 237 * @alignment=8 and @copy_size=64 will work okay on AMD Opteron boxes. 238 * 239 * Note: @copy_size should be a multiple of @alignment. In many practical 240 * cases @copy_size and @alignment will probably be equal. 241 * 242 * See also: xge_hal_fifo_dtr_buffer_set_aligned(). 243 */ 244 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int 245 xge_hal_check_alignment(dma_addr_t dma_pointer, int size, int alignment, 246 int copy_size) 247 { 248 int misaligned_size; 249 250 misaligned_size = (int)(dma_pointer & (alignment - 1)); 251 if (!misaligned_size) { 252 return 0; 253 } 254 255 if (size > copy_size) { 256 misaligned_size = (int)(dma_pointer & (copy_size - 1)); 257 misaligned_size = copy_size - misaligned_size; 258 } else { 259 misaligned_size = size; 260 } 261 262 return misaligned_size; 263 } 264