1171095Ssam/*- 2171095Ssam * Copyright (c) 2002-2007 Neterion, Inc. 3171095Ssam * All rights reserved. 4171095Ssam * 5171095Ssam * Redistribution and use in source and binary forms, with or without 6171095Ssam * modification, are permitted provided that the following conditions 7171095Ssam * are met: 8171095Ssam * 1. Redistributions of source code must retain the above copyright 9171095Ssam * notice, this list of conditions and the following disclaimer. 10171095Ssam * 2. Redistributions in binary form must reproduce the above copyright 11171095Ssam * notice, this list of conditions and the following disclaimer in the 12171095Ssam * documentation and/or other materials provided with the distribution. 13171095Ssam * 14171095Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15171095Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16171095Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17171095Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18171095Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19171095Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20171095Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21171095Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22171095Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23171095Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24171095Ssam * SUCH DAMAGE. 25171095Ssam * 26171095Ssam * $FreeBSD$ 27171095Ssam */ 28171095Ssam 29171095Ssam#ifdef XGE_DEBUG_FP 30171095Ssam#include <dev/nxge/include/xgehal-channel.h> 31171095Ssam#endif 32171095Ssam 33171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e 34173139Srwatson__hal_channel_dtr_alloc(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh) 35171095Ssam{ 36171095Ssam void **tmp_arr; 37173139Srwatson xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 38173139Srwatson#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ) 39173139Srwatson unsigned long flags = 0; 40171095Ssam#endif 41173139Srwatson if (channel->terminating) { 42173139Srwatson return XGE_HAL_FAIL; 43173139Srwatson } 44171095Ssam 45173139Srwatson if (channel->reserve_length - channel->reserve_top > 46173139Srwatson channel->reserve_threshold) { 47171095Ssam 48171095Ssam_alloc_after_swap: 49173139Srwatson *dtrh = channel->reserve_arr[--channel->reserve_length]; 50171095Ssam 51173139Srwatson xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" allocated, " 52173139Srwatson "channel %d:%d:%d, reserve_idx %d", 53173139Srwatson (unsigned long long)(ulong_t)*dtrh, 54173139Srwatson channel->type, channel->post_qid, 55173139Srwatson channel->compl_qid, channel->reserve_length); 56171095Ssam 57173139Srwatson return XGE_HAL_OK; 58171095Ssam } 59171095Ssam 60173139Srwatson#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ) 61171095Ssam xge_os_spin_lock_irq(&channel->free_lock, flags); 62173139Srwatson#elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE) 63171095Ssam xge_os_spin_lock(&channel->free_lock); 64171095Ssam#endif 65171095Ssam 66173139Srwatson /* switch between empty and full arrays */ 67171095Ssam 68173139Srwatson /* the idea behind such a design is that by having free and reserved 69173139Srwatson * arrays separated we basically separated irq and non-irq parts. 70173139Srwatson * i.e. no additional lock need to be done when we free a resource */ 71171095Ssam 72173139Srwatson if (channel->reserve_initial - channel->free_length > 73173139Srwatson channel->reserve_threshold) { 74171095Ssam 75173139Srwatson tmp_arr = channel->reserve_arr; 76173139Srwatson channel->reserve_arr = channel->free_arr; 77173139Srwatson channel->reserve_length = channel->reserve_initial; 78173139Srwatson channel->free_arr = tmp_arr; 79173139Srwatson channel->reserve_top = channel->free_length; 80173139Srwatson channel->free_length = channel->reserve_initial; 81171095Ssam 82173139Srwatson channel->stats.reserve_free_swaps_cnt++; 83171095Ssam 84173139Srwatson xge_debug_channel(XGE_TRACE, 85173139Srwatson "switch on channel %d:%d:%d, reserve_length %d, " 86173139Srwatson "free_length %d", channel->type, channel->post_qid, 87173139Srwatson channel->compl_qid, channel->reserve_length, 88173139Srwatson channel->free_length); 89171095Ssam 90173139Srwatson#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ) 91173139Srwatson xge_os_spin_unlock_irq(&channel->free_lock, flags); 92173139Srwatson#elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE) 93173139Srwatson xge_os_spin_unlock(&channel->free_lock); 94171095Ssam#endif 95171095Ssam 96173139Srwatson goto _alloc_after_swap; 97171095Ssam } 98171095Ssam 99173139Srwatson#if defined(XGE_HAL_RX_MULTI_FREE_IRQ) || defined(XGE_HAL_TX_MULTI_FREE_IRQ) 100173139Srwatson xge_os_spin_unlock_irq(&channel->free_lock, flags); 101173139Srwatson#elif defined(XGE_HAL_RX_MULTI_FREE) || defined(XGE_HAL_TX_MULTI_FREE) 102171095Ssam xge_os_spin_unlock(&channel->free_lock); 103171095Ssam#endif 104171095Ssam 105171095Ssam xge_debug_channel(XGE_TRACE, "channel %d:%d:%d is empty!", 106173139Srwatson channel->type, channel->post_qid, 107173139Srwatson channel->compl_qid); 108171095Ssam 109171095Ssam channel->stats.full_cnt++; 110171095Ssam 111173139Srwatson *dtrh = NULL; 112171095Ssam return XGE_HAL_INF_OUT_OF_DESCRIPTORS; 113171095Ssam} 114171095Ssam 115171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void 116173139Srwatson__hal_channel_dtr_restore(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh, 117173139Srwatson int offset) 118171095Ssam{ 119173139Srwatson xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 120171095Ssam 121173139Srwatson /* restore a previously allocated dtrh at current offset and update 122173139Srwatson * the available reserve length accordingly. If dtrh is null just 123171095Ssam * update the reserve length, only */ 124171095Ssam 125171095Ssam if (dtrh) { 126173139Srwatson channel->reserve_arr[channel->reserve_length + offset] = dtrh; 127173139Srwatson xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" restored for " 128173139Srwatson "channel %d:%d:%d, offset %d at reserve index %d, ", 129173139Srwatson (unsigned long long)(ulong_t)dtrh, channel->type, 130173139Srwatson channel->post_qid, channel->compl_qid, offset, 131173139Srwatson channel->reserve_length + offset); 132171095Ssam } 133171095Ssam else { 134173139Srwatson channel->reserve_length += offset; 135173139Srwatson xge_debug_channel(XGE_TRACE, "channel %d:%d:%d, restored " 136173139Srwatson "for offset %d, new reserve_length %d, free length %d", 137173139Srwatson channel->type, channel->post_qid, channel->compl_qid, 138173139Srwatson offset, channel->reserve_length, channel->free_length); 139171095Ssam } 140171095Ssam} 141171095Ssam 142171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void 143171095Ssam__hal_channel_dtr_post(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh) 144171095Ssam{ 145173139Srwatson xge_hal_channel_t *channel = (xge_hal_channel_t*)channelh; 146171095Ssam 147171095Ssam xge_assert(channel->work_arr[channel->post_index] == NULL); 148171095Ssam 149171095Ssam channel->work_arr[channel->post_index++] = dtrh; 150171095Ssam 151173139Srwatson /* wrap-around */ 152173139Srwatson if (channel->post_index == channel->length) 153173139Srwatson channel->post_index = 0; 154171095Ssam} 155171095Ssam 156171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void 157171095Ssam__hal_channel_dtr_try_complete(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh) 158171095Ssam{ 159173139Srwatson xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 160171095Ssam 161171095Ssam xge_assert(channel->work_arr); 162173139Srwatson xge_assert(channel->compl_index < channel->length); 163171095Ssam 164173139Srwatson *dtrh = channel->work_arr[channel->compl_index]; 165171095Ssam} 166171095Ssam 167171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void 168171095Ssam__hal_channel_dtr_complete(xge_hal_channel_h channelh) 169171095Ssam{ 170173139Srwatson xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 171171095Ssam 172173139Srwatson channel->work_arr[channel->compl_index] = NULL; 173171095Ssam 174171095Ssam /* wrap-around */ 175171095Ssam if (++channel->compl_index == channel->length) 176173139Srwatson channel->compl_index = 0; 177171095Ssam 178171095Ssam channel->stats.total_compl_cnt++; 179171095Ssam} 180171095Ssam 181171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void 182171095Ssam__hal_channel_dtr_free(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh) 183171095Ssam{ 184173139Srwatson xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 185171095Ssam 186173139Srwatson channel->free_arr[--channel->free_length] = dtrh; 187171095Ssam 188173139Srwatson xge_debug_channel(XGE_TRACE, "dtrh 0x"XGE_OS_LLXFMT" freed, " 189173139Srwatson "channel %d:%d:%d, new free_length %d", 190173139Srwatson (unsigned long long)(ulong_t)dtrh, 191173139Srwatson channel->type, channel->post_qid, 192173139Srwatson channel->compl_qid, channel->free_length); 193171095Ssam} 194171095Ssam 195171095Ssam/** 196171095Ssam * xge_hal_channel_dtr_count 197171095Ssam * @channelh: Channel handle. Obtained via xge_hal_channel_open(). 198171095Ssam * 199171095Ssam * Retreive number of DTRs available. This function can not be called 200171095Ssam * from data path. 201171095Ssam */ 202171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int 203171095Ssamxge_hal_channel_dtr_count(xge_hal_channel_h channelh) 204171095Ssam{ 205171095Ssam xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 206171095Ssam 207171095Ssam return ((channel->reserve_length - channel->reserve_top) + 208173139Srwatson (channel->reserve_initial - channel->free_length) - 209173139Srwatson channel->reserve_threshold); 210171095Ssam} 211171095Ssam 212171095Ssam/** 213173139Srwatson * xge_hal_channel_userdata - Get user-specified channel context. 214171095Ssam * @channelh: Channel handle. Obtained via xge_hal_channel_open(). 215171095Ssam * 216173139Srwatson * Returns: per-channel "user data", which can be any ULD-defined context. 217173139Srwatson * The %userdata "gets" into the channel at open time 218173139Srwatson * (see xge_hal_channel_open()). 219171095Ssam * 220171095Ssam * See also: xge_hal_channel_open(). 221171095Ssam */ 222171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void* 223171095Ssamxge_hal_channel_userdata(xge_hal_channel_h channelh) 224171095Ssam{ 225173139Srwatson xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 226171095Ssam 227171095Ssam return channel->userdata; 228171095Ssam} 229171095Ssam 230171095Ssam/** 231173139Srwatson * xge_hal_channel_id - Get channel ID. 232171095Ssam * @channelh: Channel handle. Obtained via xge_hal_channel_open(). 233171095Ssam * 234173139Srwatson * Returns: channel ID. For link layer channel id is the number 235173139Srwatson * in the range from 0 to 7 that identifies hardware ring or fifo, 236173139Srwatson * depending on the channel type. 237171095Ssam */ 238171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int 239171095Ssamxge_hal_channel_id(xge_hal_channel_h channelh) 240171095Ssam{ 241173139Srwatson xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh; 242171095Ssam 243171095Ssam return channel->post_qid; 244171095Ssam} 245171095Ssam 246171095Ssam/** 247173139Srwatson * xge_hal_check_alignment - Check buffer alignment and calculate the 248173139Srwatson * "misaligned" portion. 249173139Srwatson * @dma_pointer: DMA address of the buffer. 250171095Ssam * @size: Buffer size, in bytes. 251173139Srwatson * @alignment: Alignment "granularity" (see below), in bytes. 252173139Srwatson * @copy_size: Maximum number of bytes to "extract" from the buffer 253173139Srwatson * (in order to spost it as a separate scatter-gather entry). See below. 254171095Ssam * 255173139Srwatson * Check buffer alignment and calculate "misaligned" portion, if exists. 256173139Srwatson * The buffer is considered aligned if its address is multiple of 257173139Srwatson * the specified @alignment. If this is the case, 258171095Ssam * xge_hal_check_alignment() returns zero. 259173139Srwatson * Otherwise, xge_hal_check_alignment() uses the last argument, 260171095Ssam * @copy_size, 261173139Srwatson * to calculate the size to "extract" from the buffer. The @copy_size 262173139Srwatson * may or may not be equal @alignment. The difference between these two 263173139Srwatson * arguments is that the @alignment is used to make the decision: aligned 264173139Srwatson * or not aligned. While the @copy_size is used to calculate the portion 265173139Srwatson * of the buffer to "extract", i.e. to post as a separate entry in the 266173139Srwatson * transmit descriptor. For example, the combination 267173139Srwatson * @alignment=8 and @copy_size=64 will work okay on AMD Opteron boxes. 268171095Ssam * 269173139Srwatson * Note: @copy_size should be a multiple of @alignment. In many practical 270173139Srwatson * cases @copy_size and @alignment will probably be equal. 271171095Ssam * 272171095Ssam * See also: xge_hal_fifo_dtr_buffer_set_aligned(). 273171095Ssam */ 274171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int 275173139Srwatsonxge_hal_check_alignment(dma_addr_t dma_pointer, int size, int alignment, 276173139Srwatson int copy_size) 277171095Ssam{ 278173139Srwatson int misaligned_size; 279171095Ssam 280173139Srwatson misaligned_size = (int)(dma_pointer & (alignment - 1)); 281171095Ssam if (!misaligned_size) { 282173139Srwatson return 0; 283171095Ssam } 284171095Ssam 285171095Ssam if (size > copy_size) { 286173139Srwatson misaligned_size = (int)(dma_pointer & (copy_size - 1)); 287173139Srwatson misaligned_size = copy_size - misaligned_size; 288171095Ssam } else { 289173139Srwatson misaligned_size = size; 290171095Ssam } 291171095Ssam 292171095Ssam return misaligned_size; 293171095Ssam} 294171095Ssam 295