freebsd-dev/sys/dev/vxge/vxgehal/vxgehal-fifo.c
George V. Neville-Neil 548d35fd69 Exar driver for X3100 10GbE Server/Storage adapters
Features: Jumbo frames (up to 9600), LRO (Large Receive Offload),
          TSO (TCP segmentation offload), RTH (Receive Traffic Hash).

Submitted by: Sriram Rapuru at Exar
MFC after:	2 weeks
2011-04-28 14:33:15 +00:00

1897 lines
54 KiB
C

/*-
* Copyright(c) 2002-2011 Exar Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification are permitted provided the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Exar Corporation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*$FreeBSD$*/
#include <dev/vxge/vxgehal/vxgehal.h>
/*
* __hal_fifo_mempool_item_alloc - Allocate List blocks for TxD list callback
* @mempoolh: Handle to memory pool
* @memblock: Address of this memory block
* @memblock_index: Index of this memory block
* @dma_object: dma object for this block
* @item: Pointer to this item
* @index: Index of this item in memory block
* @is_last: If this is last item in the block
* @userdata: Specific data of user
*
* This function is callback passed to __hal_mempool_create to create memory
* pool for TxD list
*/
static vxge_hal_status_e
__hal_fifo_mempool_item_alloc(
vxge_hal_mempool_h mempoolh,
void *memblock,
u32 memblock_index,
vxge_hal_mempool_dma_t *dma_object,
void *item,
u32 item_index,
u32 is_last,
void *userdata)
{
u32 i;
void *block_priv;
u32 memblock_item_idx;
__hal_fifo_t *fifo = (__hal_fifo_t *) userdata;
vxge_assert(fifo != NULL);
vxge_assert(item);
#if (VXGE_COMPONENT_HAL_POOL & VXGE_DEBUG_MODULE_MASK)
{
__hal_device_t *hldev = (__hal_device_t *) fifo->channel.devh;
vxge_hal_trace_log_pool("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_pool(
"mempoolh = 0x"VXGE_OS_STXFMT", "
"memblock = 0x"VXGE_OS_STXFMT", memblock_index = %d, "
"dma_object = 0x"VXGE_OS_STXFMT", \
item = 0x"VXGE_OS_STXFMT", "
"item_index = %d, is_last = %d, userdata = 0x"VXGE_OS_STXFMT,
(ptr_t) mempoolh, (ptr_t) memblock, memblock_index,
(ptr_t) dma_object, (ptr_t) item, item_index, is_last,
(ptr_t) userdata);
}
#endif
block_priv = __hal_mempool_item_priv((vxge_hal_mempool_t *) mempoolh,
memblock_index, item, &memblock_item_idx);
vxge_assert(block_priv != NULL);
for (i = 0; i < fifo->txdl_per_memblock; i++) {
__hal_fifo_txdl_priv_t *txdl_priv;
vxge_hal_fifo_txd_t *txdp;
int dtr_index = item_index * fifo->txdl_per_memblock + i;
txdp = (vxge_hal_fifo_txd_t *) ((void *)
((char *) item + i * fifo->txdl_size));
txdp->host_control = dtr_index;
fifo->channel.dtr_arr[dtr_index].dtr = txdp;
fifo->channel.dtr_arr[dtr_index].uld_priv = (void *)
((char *) block_priv + fifo->txdl_priv_size * i);
fifo->channel.dtr_arr[dtr_index].hal_priv = (void *)
(((char *) fifo->channel.dtr_arr[dtr_index].uld_priv) +
fifo->per_txdl_space);
txdl_priv = (__hal_fifo_txdl_priv_t *)
fifo->channel.dtr_arr[dtr_index].hal_priv;
vxge_assert(txdl_priv);
/* pre-format HAL's TxDL's private */
/* LINTED */
txdl_priv->dma_offset = (char *) txdp - (char *) memblock;
txdl_priv->dma_addr = dma_object->addr + txdl_priv->dma_offset;
txdl_priv->dma_handle = dma_object->handle;
txdl_priv->memblock = memblock;
txdl_priv->first_txdp = (vxge_hal_fifo_txd_t *) txdp;
txdl_priv->next_txdl_priv = NULL;
txdl_priv->dang_txdl = NULL;
txdl_priv->dang_frags = 0;
txdl_priv->alloc_frags = 0;
#if defined(VXGE_DEBUG_ASSERT)
txdl_priv->dma_object = dma_object;
#endif
#if defined(VXGE_HAL_ALIGN_XMIT)
txdl_priv->align_vaddr = NULL;
txdl_priv->align_dma_addr = (dma_addr_t) 0;
#ifndef VXGE_HAL_ALIGN_XMIT_ALLOC_RT
/* CONSTCOND */
if (TRUE) {
vxge_hal_status_e status;
if (fifo->config->alignment_size) {
status = __hal_fifo_txdl_align_alloc_map(fifo,
txdp);
if (status != VXGE_HAL_OK) {
#if (VXGE_COMPONENT_HAL_POOL & VXGE_DEBUG_MODULE_MASK)
__hal_device_t *hldev;
hldev = (__hal_device_t *)
fifo->channel.devh;
vxge_hal_err_log_pool(
"align buffer[%d] %d bytes, \
status %d",
(item_index * fifo->txdl_per_memblock + i),
fifo->align_size, status);
vxge_hal_trace_log_pool(
"<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
#endif
return (status);
}
}
}
#endif
#endif
if (fifo->txdl_init) {
fifo->txdl_init(fifo->channel.vph,
(vxge_hal_txdl_h) txdp,
VXGE_HAL_FIFO_ULD_PRIV(fifo, txdp),
VXGE_HAL_FIFO_TXDL_INDEX(txdp),
fifo->channel.userdata, VXGE_HAL_OPEN_NORMAL);
}
}
#if (VXGE_COMPONENT_HAL_POOL & VXGE_DEBUG_MODULE_MASK)
{
__hal_device_t *hldev = (__hal_device_t *) fifo->channel.devh;
vxge_hal_trace_log_pool("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
}
#endif
return (VXGE_HAL_OK);
}
/*
* __hal_fifo_mempool_item_free - Free List blocks for TxD list callback
* @mempoolh: Handle to memory pool
* @memblock: Address of this memory block
* @memblock_index: Index of this memory block
* @dma_object: dma object for this block
* @item: Pointer to this item
* @index: Index of this item in memory block
* @is_last: If this is last item in the block
* @userdata: Specific data of user
*
* This function is callback passed to __hal_mempool_free to destroy memory
* pool for TxD list
*/
static vxge_hal_status_e
__hal_fifo_mempool_item_free(
vxge_hal_mempool_h mempoolh,
void *memblock,
u32 memblock_index,
vxge_hal_mempool_dma_t *dma_object,
void *item,
u32 item_index,
u32 is_last,
void *userdata)
{
vxge_assert(item);
#if (VXGE_COMPONENT_HAL_POOL & VXGE_DEBUG_MODULE_MASK)
{
__hal_fifo_t *fifo = (__hal_fifo_t *) userdata;
vxge_assert(fifo != NULL);
__hal_device_t *hldev = (__hal_device_t *) fifo->channel.devh;
vxge_hal_trace_log_pool("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_pool("mempoolh = 0x"VXGE_OS_STXFMT", "
"memblock = 0x"VXGE_OS_STXFMT", memblock_index = %d, "
"dma_object = 0x"VXGE_OS_STXFMT", \
item = 0x"VXGE_OS_STXFMT", "
"item_index = %d, is_last = %d, userdata = 0x"VXGE_OS_STXFMT,
(ptr_t) mempoolh, (ptr_t) memblock, memblock_index,
(ptr_t) dma_object, (ptr_t) item, item_index, is_last,
(ptr_t) userdata);
}
#endif
#if defined(VXGE_HAL_ALIGN_XMIT)
{
__hal_fifo_t *fifo = (__hal_fifo_t *) userdata;
vxge_assert(fifo != NULL);
if (fifo->config->alignment_size) {
int i;
vxge_hal_fifo_txd_t *txdp;
for (i = 0; i < fifo->txdl_per_memblock; i++) {
txdp = (void *)
((char *) item + i * fifo->txdl_size);
__hal_fifo_txdl_align_free_unmap(fifo, txdp);
}
}
}
#endif
#if (VXGE_COMPONENT_HAL_POOL & VXGE_DEBUG_MODULE_MASK)
{
__hal_fifo_t *fifo = (__hal_fifo_t *) userdata;
vxge_assert(fifo != NULL);
__hal_device_t *hldev = (__hal_device_t *) fifo->channel.devh;
vxge_hal_trace_log_pool("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
}
#endif
return (VXGE_HAL_OK);
}
/*
* __hal_fifo_create - Create a FIFO
* @vpath_handle: Handle returned by virtual path open
* @attr: FIFO configuration parameters structure
*
* This function creates FIFO and initializes it.
*
*/
vxge_hal_status_e
__hal_fifo_create(
vxge_hal_vpath_h vpath_handle,
vxge_hal_fifo_attr_t *attr)
{
vxge_hal_status_e status;
__hal_fifo_t *fifo;
vxge_hal_fifo_config_t *config;
u32 txdl_size, memblock_size, txdl_per_memblock;
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
__hal_device_t *hldev;
vxge_assert((vpath_handle != NULL) && (attr != NULL));
hldev = (__hal_device_t *) vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo(
"vpath_handle = 0x"VXGE_OS_STXFMT", attr = 0x"VXGE_OS_STXFMT,
(ptr_t) vpath_handle, (ptr_t) attr);
if ((vpath_handle == NULL) || (attr == NULL)) {
vxge_hal_err_log_fifo("null pointer passed == > %s : %d",
__func__, __LINE__);
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: %d",
__FILE__, __func__, __LINE__,
VXGE_HAL_ERR_INVALID_HANDLE);
return (VXGE_HAL_ERR_INVALID_HANDLE);
}
config =
&vp->vpath->hldev->header.config.vp_config[vp->vpath->vp_id].fifo;
txdl_size = config->max_frags * sizeof(vxge_hal_fifo_txd_t);
if (txdl_size <= VXGE_OS_HOST_PAGE_SIZE)
memblock_size = VXGE_OS_HOST_PAGE_SIZE;
else
memblock_size = txdl_size;
txdl_per_memblock = memblock_size / txdl_size;
config->fifo_length = ((config->fifo_length + txdl_per_memblock - 1) /
txdl_per_memblock) * txdl_per_memblock;
fifo = (__hal_fifo_t *) vxge_hal_channel_allocate(
(vxge_hal_device_h) vp->vpath->hldev,
vpath_handle,
VXGE_HAL_CHANNEL_TYPE_FIFO,
config->fifo_length,
attr->per_txdl_space,
attr->userdata);
if (fifo == NULL) {
vxge_hal_err_log_fifo("Memory allocation failed == > %s : %d",
__func__, __LINE__);
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: %d",
__FILE__, __func__, __LINE__,
VXGE_HAL_ERR_OUT_OF_MEMORY);
return (VXGE_HAL_ERR_OUT_OF_MEMORY);
}
vp->vpath->fifoh = fifo;
fifo->stats = &vp->vpath->sw_stats->fifo_stats;
fifo->config = config;
fifo->memblock_size = memblock_size;
#if defined(VXGE_HAL_TX_MULTI_POST)
vxge_os_spin_lock_init(&fifo->channel.post_lock,
vp->vpath->hldev->header.pdev);
#elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
vxge_os_spin_lock_init_irq(&fifo->channel.post_lock,
vp->vpath->hldev->header.irqh);
#endif
fifo->align_size =
fifo->config->alignment_size * fifo->config->max_aligned_frags;
/* apply "interrupts per txdl" attribute */
fifo->interrupt_type = VXGE_HAL_FIFO_TXD_INT_TYPE_UTILZ;
if (fifo->config->intr) {
fifo->interrupt_type = VXGE_HAL_FIFO_TXD_INT_TYPE_PER_LIST;
}
fifo->no_snoop_bits = config->no_snoop_bits;
/*
* FIFO memory management strategy:
*
* TxDL splitted into three independent parts:
* - set of TxD's
* - TxD HAL private part
* - upper layer private part
*
* Adaptative memory allocation used. i.e. Memory allocated on
* demand with the size which will fit into one memory block.
* One memory block may contain more than one TxDL. In simple case
* memory block size can be equal to CPU page size. On more
* sophisticated OS's memory block can be contigious across
* several pages.
*
* During "reserve" operations more memory can be allocated on demand
* for example due to FIFO full condition.
*
* Pool of memory memblocks never shrinks except __hal_fifo_close
* routine which will essentially stop channel and free the resources.
*/
/* TxDL common private size == TxDL private + ULD private */
fifo->txdl_priv_size =
sizeof(__hal_fifo_txdl_priv_t) + attr->per_txdl_space;
fifo->txdl_priv_size =
((fifo->txdl_priv_size + __vxge_os_cacheline_size - 1) /
__vxge_os_cacheline_size) * __vxge_os_cacheline_size;
fifo->per_txdl_space = attr->per_txdl_space;
/* recompute txdl size to be cacheline aligned */
fifo->txdl_size = txdl_size;
fifo->txdl_per_memblock = txdl_per_memblock;
/*
* since txdl_init() callback will be called from item_alloc(),
* the same way channels userdata might be used prior to
* channel_initialize()
*/
fifo->txdl_init = attr->txdl_init;
fifo->txdl_term = attr->txdl_term;
fifo->callback = attr->callback;
if (fifo->txdl_per_memblock == 0) {
__hal_fifo_delete(vpath_handle);
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: %d",
__FILE__, __func__, __LINE__,
VXGE_HAL_ERR_INVALID_BLOCK_SIZE);
return (VXGE_HAL_ERR_INVALID_BLOCK_SIZE);
}
/* calculate actual TxDL block private size */
fifo->txdlblock_priv_size =
fifo->txdl_priv_size * fifo->txdl_per_memblock;
fifo->mempool =
vxge_hal_mempool_create((vxge_hal_device_h) vp->vpath->hldev,
fifo->memblock_size,
fifo->memblock_size,
fifo->txdlblock_priv_size,
fifo->config->fifo_length /
fifo->txdl_per_memblock,
fifo->config->fifo_length /
fifo->txdl_per_memblock,
__hal_fifo_mempool_item_alloc,
__hal_fifo_mempool_item_free,
fifo);
if (fifo->mempool == NULL) {
__hal_fifo_delete(vpath_handle);
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: %d",
__FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
return (VXGE_HAL_ERR_OUT_OF_MEMORY);
}
status = vxge_hal_channel_initialize(&fifo->channel);
if (status != VXGE_HAL_OK) {
__hal_fifo_delete(vpath_handle);
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: %d",
__FILE__, __func__, __LINE__, status);
return (status);
}
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
return (VXGE_HAL_OK);
}
/*
* __hal_fifo_abort - Returns the TxD
* @fifoh: Fifo to be reset
* @reopen: See vxge_hal_reopen_e {}.
*
* This function terminates the TxDs of fifo
*/
void
__hal_fifo_abort(
vxge_hal_fifo_h fifoh,
vxge_hal_reopen_e reopen)
{
u32 i = 0;
__hal_fifo_t *fifo = (__hal_fifo_t *) fifoh;
__hal_device_t *hldev;
vxge_hal_txdl_h txdlh;
vxge_assert(fifoh != NULL);
hldev = (__hal_device_t *) fifo->channel.devh;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("fifo = 0x"VXGE_OS_STXFMT", reopen = %d",
(ptr_t) fifoh, reopen);
if (fifo->txdl_term) {
__hal_channel_for_each_dtr(&fifo->channel, txdlh, i) {
if (!__hal_channel_is_posted_dtr(&fifo->channel,
i)) {
fifo->txdl_term(fifo->channel.vph, txdlh,
VXGE_HAL_FIFO_ULD_PRIV(fifo, txdlh),
VXGE_HAL_TXDL_STATE_FREED,
fifo->channel.userdata,
reopen);
}
}
}
for (;;) {
__hal_channel_dtr_try_complete(&fifo->channel, &txdlh);
if (txdlh == NULL)
break;
__hal_channel_dtr_complete(&fifo->channel);
if (fifo->txdl_term) {
fifo->txdl_term(fifo->channel.vph, txdlh,
VXGE_HAL_FIFO_ULD_PRIV(fifo, txdlh),
VXGE_HAL_TXDL_STATE_POSTED,
fifo->channel.userdata,
reopen);
}
__hal_channel_dtr_free(&fifo->channel,
VXGE_HAL_FIFO_TXDL_INDEX(txdlh));
}
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
}
/*
* __hal_fifo_reset - Resets the fifo
* @fifoh: Fifo to be reset
*
* This function resets the fifo during vpath reset operation
*/
vxge_hal_status_e
__hal_fifo_reset(
vxge_hal_fifo_h fifoh)
{
vxge_hal_status_e status;
__hal_device_t *hldev;
__hal_fifo_t *fifo = (__hal_fifo_t *) fifoh;
vxge_assert(fifoh != NULL);
hldev = (__hal_device_t *) fifo->channel.devh;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("fifo = 0x"VXGE_OS_STXFMT,
(ptr_t) fifoh);
__hal_fifo_abort(fifoh, VXGE_HAL_RESET_ONLY);
status = __hal_channel_reset(&fifo->channel);
if (status != VXGE_HAL_OK) {
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: %d",
__FILE__, __func__, __LINE__, status);
return (status);
}
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
return (VXGE_HAL_OK);
}
/*
* vxge_hal_fifo_doorbell_reset - Resets the doorbell fifo
* @vapth_handle: Vpath Handle
*
* This function resets the doorbell fifo during if fifo error occurs
*/
vxge_hal_status_e
vxge_hal_fifo_doorbell_reset(
vxge_hal_vpath_h vpath_handle)
{
u32 i;
vxge_hal_txdl_h txdlh;
__hal_fifo_t *fifo;
__hal_virtualpath_t *vpath;
__hal_fifo_txdl_priv_t *txdl_priv;
__hal_device_t *hldev;
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
vxge_hal_status_e status = VXGE_HAL_OK;
vxge_assert(vpath_handle != NULL);
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT,
(ptr_t) vpath_handle);
fifo = (__hal_fifo_t *) vp->vpath->fifoh;
vpath = ((__hal_vpath_handle_t *) fifo->channel.vph)->vpath;
status = __hal_non_offload_db_reset(fifo->channel.vph);
if (status != VXGE_HAL_OK) {
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
return (status);
}
__hal_channel_for_each_posted_dtr(&fifo->channel, txdlh, i) {
txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
__hal_non_offload_db_post(fifo->channel.vph,
((VXGE_HAL_FIFO_TXD_NO_BW_LIMIT_GET(
((vxge_hal_fifo_txd_t *) txdlh)->control_1)) ?
(((u64) txdl_priv->dma_addr) | 0x1) :
(u64) txdl_priv->dma_addr),
txdl_priv->frags - 1,
vpath->vp_config->fifo.no_snoop_bits);
}
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
return (status);
}
/*
* __hal_fifo_delete - Removes the FIFO
* @vpath_handle: Virtual path handle to which this queue belongs
*
* This function freeup the memory pool and removes the FIFO
*/
void
__hal_fifo_delete(
vxge_hal_vpath_h vpath_handle)
{
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
__hal_fifo_t *fifo;
__hal_device_t *hldev;
vxge_assert(vpath_handle != NULL);
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT,
(ptr_t) vpath_handle);
fifo = (__hal_fifo_t *) vp->vpath->fifoh;
vxge_assert(fifo != NULL);
if (fifo->mempool) {
__hal_fifo_abort(vp->vpath->fifoh, VXGE_HAL_OPEN_NORMAL);
vxge_hal_mempool_destroy(fifo->mempool);
}
vxge_hal_channel_terminate(&fifo->channel);
#if defined(VXGE_HAL_TX_MULTI_POST)
vxge_os_spin_lock_destroy(&fifo->channel.post_lock,
vp->vpath->hldev->header.pdev);
#elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
vxge_os_spin_lock_destroy_irq(&fifo->channel.post_lock,
vp->vpath->hldev->header.pdev);
#endif
vxge_hal_channel_free(&fifo->channel);
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
}
#if defined(VXGE_HAL_ALIGN_XMIT)
/*
* __hal_fifo_txdl_align_free_unmap - Unmap the alignement buffers
* @fifo: Fifo
* @txdp: txdl
*
* This function unmaps dma memory for the alignment buffers
*/
void
__hal_fifo_txdl_align_free_unmap(
__hal_fifo_t *fifo,
vxge_hal_fifo_txd_t *txdp)
{
__hal_device_t *hldev;
__hal_fifo_txdl_priv_t *txdl_priv;
vxge_assert((fifo != NULL) && (txdp != NULL));
hldev = (__hal_device_t *) fifo->channel.devh;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo(
"fifo = 0x"VXGE_OS_STXFMT", txdp = 0x"VXGE_OS_STXFMT,
(ptr_t) fifo, (ptr_t) txdp);
txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdp);
if (txdl_priv->align_vaddr != NULL) {
__hal_blockpool_free(fifo->channel.devh,
txdl_priv->align_vaddr,
fifo->align_size,
&txdl_priv->align_dma_addr,
&txdl_priv->align_dma_handle,
&txdl_priv->align_dma_acch);
txdl_priv->align_vaddr = NULL;
txdl_priv->align_dma_addr = 0;
}
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
}
/*
* __hal_fifo_txdl_align_alloc_map - Maps the alignement buffers
* @fifo: Fifo
* @txdp: txdl
*
* This function maps dma memory for the alignment buffers
*/
vxge_hal_status_e
__hal_fifo_txdl_align_alloc_map(
__hal_fifo_t *fifo,
vxge_hal_fifo_txd_t *txdp)
{
__hal_device_t *hldev;
__hal_fifo_txdl_priv_t *txdl_priv;
vxge_assert((fifo != NULL) && (txdp != NULL));
hldev = (__hal_device_t *) fifo->channel.devh;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo(
"fifo = 0x"VXGE_OS_STXFMT", txdp = 0x"VXGE_OS_STXFMT,
(ptr_t) fifo, (ptr_t) txdp);
txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdp);
/* allocate alignment DMA-buffer */
txdl_priv->align_vaddr =
(u8 *) __hal_blockpool_malloc(fifo->channel.devh,
fifo->align_size,
&txdl_priv->align_dma_addr,
&txdl_priv->align_dma_handle,
&txdl_priv->align_dma_acch);
if (txdl_priv->align_vaddr == NULL) {
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: %d",
__FILE__, __func__, __LINE__, VXGE_HAL_ERR_OUT_OF_MEMORY);
return (VXGE_HAL_ERR_OUT_OF_MEMORY);
}
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
return (VXGE_HAL_OK);
}
#endif
/*
* vxge_hal_fifo_free_txdl_count_get - returns the number of txdls
* available in the fifo
* @vpath_handle: Virtual path handle.
*/
u32
vxge_hal_fifo_free_txdl_count_get(vxge_hal_vpath_h vpath_handle)
{
return __hal_channel_free_dtr_count(&((__hal_fifo_t *)
((__hal_vpath_handle_t *) vpath_handle)->vpath->fifoh)->channel);
}
/*
* vxge_hal_fifo_txdl_private_get - Retrieve per-descriptor private data.
* @vpath_handle: Virtual path handle.
* @txdlh: Descriptor handle.
*
* Retrieve per-descriptor private data.
* Note that ULD requests per-descriptor space via
* vxge_hal_fifo_attr_t passed to
* vxge_hal_vpath_open().
*
* Returns: private ULD data associated with the descriptor.
*/
void *
vxge_hal_fifo_txdl_private_get(
vxge_hal_vpath_h vpath_handle,
vxge_hal_txdl_h txdlh)
{
return (VXGE_HAL_FIFO_ULD_PRIV(((__hal_fifo_t *)
((__hal_vpath_handle_t *) vpath_handle)->vpath->fifoh), txdlh));
}
/*
* vxge_hal_fifo_txdl_reserve - Reserve fifo descriptor.
* @vapth_handle: virtual path handle.
* @txdlh: Reserved descriptor. On success HAL fills this "out" parameter
* with a valid handle.
* @txdl_priv: Buffer to return the pointer to per txdl space
*
* Reserve a single TxDL (that is, fifo descriptor)
* for the subsequent filling-in by upper layerdriver (ULD))
* and posting on the corresponding channel (@channelh)
* via vxge_hal_fifo_txdl_post().
*
* Note: it is the responsibility of ULD to reserve multiple descriptors
* for lengthy (e.g., LSO) transmit operation. A single fifo descriptor
* carries up to configured number (fifo.max_frags) of contiguous buffers.
*
* Returns: VXGE_HAL_OK - success;
* VXGE_HAL_INF_OUT_OF_DESCRIPTORS - Currently no descriptors available
*
*/
vxge_hal_status_e
vxge_hal_fifo_txdl_reserve(
vxge_hal_vpath_h vpath_handle,
vxge_hal_txdl_h *txdlh,
void **txdl_priv)
{
u32 i;
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
__hal_device_t *hldev;
__hal_fifo_t *fifo;
vxge_hal_status_e status;
#if defined(VXGE_HAL_TX_MULTI_POST_IRQ)
unsigned long flags = 0;
#endif
vxge_assert((vpath_handle != NULL) && (txdlh != NULL));
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo(
"vpath_handle = 0x"VXGE_OS_STXFMT", txdlh = 0x"VXGE_OS_STXFMT,
(ptr_t) vpath_handle, (ptr_t) txdlh);
fifo = (__hal_fifo_t *) vp->vpath->fifoh;
vxge_assert(fifo != NULL);
#if defined(VXGE_HAL_TX_MULTI_POST)
vxge_os_spin_lock(&fifo->channel.post_lock);
#elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
vxge_os_spin_lock_irq(&fifo->channel.post_lock, flags);
#endif
status = __hal_channel_dtr_reserve(&fifo->channel, txdlh);
#if defined(VXGE_HAL_TX_MULTI_POST)
vxge_os_spin_unlock(&fifo->channel.post_lock);
#elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
vxge_os_spin_unlock_irq(&fifo->channel.post_lock, flags);
#endif
if (status == VXGE_HAL_OK) {
vxge_hal_fifo_txd_t *txdp = (vxge_hal_fifo_txd_t *)*txdlh;
__hal_fifo_txdl_priv_t *priv;
priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdp);
/* reset the TxDL's private */
priv->align_dma_offset = 0;
priv->align_vaddr_start = priv->align_vaddr;
priv->align_used_frags = 0;
priv->frags = 0;
priv->alloc_frags = fifo->config->max_frags;
priv->dang_txdl = NULL;
priv->dang_frags = 0;
priv->next_txdl_priv = NULL;
priv->bytes_sent = 0;
*txdl_priv = VXGE_HAL_FIFO_ULD_PRIV(fifo, txdp);
for (i = 0; i < fifo->config->max_frags; i++) {
txdp = ((vxge_hal_fifo_txd_t *)*txdlh) + i;
txdp->control_0 = txdp->control_1 = 0;
}
#if defined(VXGE_OS_MEMORY_CHECK)
priv->allocated = 1;
#endif
}
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
return (status);
}
/*
* vxge_hal_fifo_txdl_buffer_set - Set transmit buffer pointer in the
* descriptor.
* @vpath_handle: virtual path handle.
* @txdlh: Descriptor handle.
* @frag_idx: Index of the data buffer in the caller's scatter-gather list
* (of buffers).
* @dma_pointer: DMA address of the data buffer referenced by @frag_idx.
* @size: Size of the data buffer (in bytes).
*
* This API is part of the preparation of the transmit descriptor for posting
* (via vxge_hal_fifo_txdl_post()). The related "preparation" APIs include
* vxge_hal_fifo_txdl_mss_set() and vxge_hal_fifo_txdl_cksum_set_bits().
* All three APIs fill in the fields of the fifo descriptor,
* in accordance with the X3100 specification.
*
*/
void
vxge_hal_fifo_txdl_buffer_set(
vxge_hal_vpath_h vpath_handle,
vxge_hal_txdl_h txdlh,
u32 frag_idx,
dma_addr_t dma_pointer,
unsigned long size)
{
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
__hal_fifo_t *fifo;
__hal_device_t *hldev;
__hal_fifo_txdl_priv_t *txdl_priv;
vxge_hal_fifo_txd_t *txdp;
vxge_assert((vpath_handle != NULL) && (txdlh != NULL) &&
(dma_pointer != 0) && (size != 0));
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
"txdlh = 0x"VXGE_OS_STXFMT", frag_idx = %d, "
"dma_pointer = 0x"VXGE_OS_LLXFMT", size = %lu",
(ptr_t) vpath_handle, (ptr_t) txdlh,
frag_idx, (u64) dma_pointer, size);
fifo = (__hal_fifo_t *) vp->vpath->fifoh;
vxge_assert(fifo != NULL);
txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
txdp = (vxge_hal_fifo_txd_t *) txdlh + txdl_priv->frags;
/*
* Note:
* it is the responsibility of upper layers and not HAL
* detect it and skip zero-size fragment
*/
vxge_assert(size > 0);
vxge_assert(frag_idx < txdl_priv->alloc_frags);
txdp->buffer_pointer = (u64) dma_pointer;
txdp->control_0 |= VXGE_HAL_FIFO_TXD_BUFFER_SIZE(size);
txdl_priv->bytes_sent += size;
fifo->stats->total_buffers++;
txdl_priv->frags++;
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
}
/*
* vxge_hal_fifo_txdl_buffer_set_aligned - Align transmit buffer and fill
* in fifo descriptor.
* @vpath_handle: Virtual path handle.
* @txdlh: Descriptor handle.
* @frag_idx: Index of the data buffer in the caller's scatter-gather list
* (of buffers).
* @vaddr: Virtual address of the data buffer.
* @dma_pointer: DMA address of the data buffer referenced by @frag_idx.
* @size: Size of the data buffer (in bytes).
* @misaligned_size: Size (in bytes) of the misaligned portion of the
* data buffer. Calculated by the caller, based on the platform/OS/other
* specific criteria, which is outside of HAL's domain. See notes below.
*
* This API is part of the transmit descriptor preparation for posting
* (via vxge_hal_fifo_txdl_post()). The related "preparation" APIs include
* vxge_hal_fifo_txdl_mss_set() and vxge_hal_fifo_txdl_cksum_set_bits().
* All three APIs fill in the fields of the fifo descriptor,
* in accordance with the X3100 specification.
* On the PCI-X based systems aligning transmit data typically provides better
* transmit performance. The typical alignment granularity: L2 cacheline size.
* However, HAL does not make assumptions in terms of the alignment granularity;
* this is specified via additional @misaligned_size parameter described above.
* Prior to calling vxge_hal_fifo_txdl_buffer_set_aligned(),
* ULD is supposed to check alignment of a given fragment/buffer. For this HAL
* provides a separate vxge_hal_check_alignment() API sufficient to cover
* most (but not all) possible alignment criteria.
* If the buffer appears to be aligned, the ULD calls
* vxge_hal_fifo_txdl_buffer_set().
* Otherwise, ULD calls vxge_hal_fifo_txdl_buffer_set_aligned().
*
* Note; This API is a "superset" of vxge_hal_fifo_txdl_buffer_set(). In
* addition to filling in the specified descriptor it aligns transmit data on
* the specified boundary.
* Note: Decision on whether to align or not to align a given contiguous
* transmit buffer is outside of HAL's domain. To this end ULD can use any
* programmable criteria, which can help to 1) boost transmit performance,
* and/or 2) provide a workaround for PCI bridge bugs, if any.
*
*/
vxge_hal_status_e
vxge_hal_fifo_txdl_buffer_set_aligned(
vxge_hal_vpath_h vpath_handle,
vxge_hal_txdl_h txdlh,
u32 frag_idx,
void *vaddr,
dma_addr_t dma_pointer,
u32 size,
u32 misaligned_size)
{
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
__hal_fifo_t *fifo;
__hal_device_t *hldev;
__hal_fifo_txdl_priv_t *txdl_priv;
vxge_hal_fifo_txd_t *txdp;
int remaining_size;
ptrdiff_t prev_boff;
vxge_assert((vpath_handle != NULL) && (txdlh != NULL) &&
(vaddr != 0) && (dma_pointer != 0) &&
(size != 0) && (misaligned_size != 0));
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo(
"vpath_handle = 0x"VXGE_OS_STXFMT", txdlh = 0x"VXGE_OS_STXFMT", "
"frag_idx = %d, vaddr = 0x"VXGE_OS_STXFMT", "
"dma_pointer = 0x"VXGE_OS_LLXFMT", size = %d, "
"misaligned_size = %d", (ptr_t) vpath_handle,
(ptr_t) txdlh, frag_idx, (ptr_t) vaddr, (u64) dma_pointer, size,
misaligned_size);
fifo = (__hal_fifo_t *) vp->vpath->fifoh;
vxge_assert(fifo != NULL);
txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
txdp = (vxge_hal_fifo_txd_t *) txdlh + txdl_priv->frags;
/*
* On some systems buffer size could be zero.
* It is the responsibility of ULD and *not HAL* to
* detect it and skip it.
*/
vxge_assert(size > 0);
vxge_assert(frag_idx < txdl_priv->alloc_frags);
vxge_assert(misaligned_size != 0 &&
misaligned_size <= fifo->config->alignment_size);
remaining_size = size - misaligned_size;
vxge_assert(remaining_size >= 0);
vxge_os_memcpy((char *) txdl_priv->align_vaddr_start,
vaddr, misaligned_size);
if (txdl_priv->align_used_frags >= fifo->config->max_aligned_frags) {
return (VXGE_HAL_ERR_OUT_ALIGNED_FRAGS);
}
/* setup new buffer */
/* LINTED */
prev_boff = txdl_priv->align_vaddr_start - txdl_priv->align_vaddr;
txdp->buffer_pointer = (u64) txdl_priv->align_dma_addr + prev_boff;
txdp->control_0 |= VXGE_HAL_FIFO_TXD_BUFFER_SIZE(misaligned_size);
txdl_priv->bytes_sent += misaligned_size;
fifo->stats->total_buffers++;
txdl_priv->frags++;
txdl_priv->align_used_frags++;
txdl_priv->align_vaddr_start += fifo->config->alignment_size;
txdl_priv->align_dma_offset = 0;
#if defined(VXGE_OS_DMA_REQUIRES_SYNC)
/* sync new buffer */
vxge_os_dma_sync(fifo->channel.pdev,
txdl_priv->align_dma_handle,
txdp->buffer_pointer,
0,
misaligned_size,
VXGE_OS_DMA_DIR_TODEVICE);
#endif
if (remaining_size) {
vxge_assert(frag_idx < txdl_priv->alloc_frags);
txdp++;
txdp->buffer_pointer = (u64) dma_pointer + misaligned_size;
txdp->control_0 |=
VXGE_HAL_FIFO_TXD_BUFFER_SIZE(remaining_size);
txdl_priv->bytes_sent += remaining_size;
fifo->stats->total_buffers++;
txdl_priv->frags++;
}
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
return (VXGE_HAL_OK);
}
/*
* vxge_hal_fifo_txdl_buffer_append - Append the contents of virtually
* contiguous data buffer to a single physically contiguous buffer.
* @vpath_handle: Virtual path handle.
* @txdlh: Descriptor handle.
* @vaddr: Virtual address of the data buffer.
* @size: Size of the data buffer (in bytes).
*
* This API is part of the transmit descriptor preparation for posting
* (via vxge_hal_fifo_txdl_post()).
* The main difference of this API wrt to the APIs
* vxge_hal_fifo_txdl_buffer_set_aligned() is that this API appends the
* contents of virtually contiguous data buffers received from
* upper layer into a single physically contiguous data buffer and the
* device will do a DMA from this buffer.
*
* See Also: vxge_hal_fifo_txdl_buffer_finalize(),
* vxge_hal_fifo_txdl_buffer_set(),
* vxge_hal_fifo_txdl_buffer_set_aligned().
*/
vxge_hal_status_e
vxge_hal_fifo_txdl_buffer_append(
vxge_hal_vpath_h vpath_handle,
vxge_hal_txdl_h txdlh,
void *vaddr,
u32 size)
{
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
__hal_fifo_t *fifo;
__hal_device_t *hldev;
__hal_fifo_txdl_priv_t *txdl_priv;
ptrdiff_t used;
vxge_assert((vpath_handle != NULL) && (txdlh != NULL) && (vaddr != 0) &&
(size == 0));
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
"txdlh = 0x"VXGE_OS_STXFMT", vaddr = 0x"VXGE_OS_STXFMT", "
"size = %d", (ptr_t) vpath_handle, (ptr_t) txdlh,
(ptr_t) vaddr, size);
fifo = (__hal_fifo_t *) vp->vpath->fifoh;
vxge_assert(fifo != NULL);
txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
/* LINTED */
used = txdl_priv->align_vaddr_start - txdl_priv->align_vaddr;
used += txdl_priv->align_dma_offset;
if (used + (unsigned int)size > (unsigned int)fifo->align_size)
return (VXGE_HAL_ERR_OUT_ALIGNED_FRAGS);
vxge_os_memcpy((char *) txdl_priv->align_vaddr_start +
txdl_priv->align_dma_offset, vaddr, size);
fifo->stats->copied_frags++;
txdl_priv->align_dma_offset += size;
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
return (VXGE_HAL_OK);
}
/*
* vxge_hal_fifo_txdl_buffer_finalize - Prepares a descriptor that contains the
* single physically contiguous buffer.
*
* @vpath_handle: Virtual path handle.
* @txdlh: Descriptor handle.
* @frag_idx: Index of the data buffer in the Txdl list.
*
* This API in conjuction with vxge_hal_fifo_txdl_buffer_append() prepares
* a descriptor that consists of a single physically contiguous buffer
* which inturn contains the contents of one or more virtually contiguous
* buffers received from the upper layer.
*
* See Also: vxge_hal_fifo_txdl_buffer_append().
*/
void
vxge_hal_fifo_txdl_buffer_finalize(
vxge_hal_vpath_h vpath_handle,
vxge_hal_txdl_h txdlh,
u32 frag_idx)
{
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
__hal_fifo_t *fifo;
__hal_device_t *hldev;
__hal_fifo_txdl_priv_t *txdl_priv;
vxge_hal_fifo_txd_t *txdp;
ptrdiff_t prev_boff;
vxge_assert((vpath_handle != NULL) &&
(txdlh != NULL) && (frag_idx != 0));
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
"txdlh = 0x"VXGE_OS_STXFMT", frag_idx = %d", (ptr_t) vpath_handle,
(ptr_t) txdlh, frag_idx);
fifo = (__hal_fifo_t *) vp->vpath->fifoh;
vxge_assert(fifo != NULL);
txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
txdp = (vxge_hal_fifo_txd_t *) txdlh + txdl_priv->frags;
/* LINTED */
prev_boff = txdl_priv->align_vaddr_start - txdl_priv->align_vaddr;
txdp->buffer_pointer = (u64) txdl_priv->align_dma_addr + prev_boff;
txdp->control_0 |=
VXGE_HAL_FIFO_TXD_BUFFER_SIZE(txdl_priv->align_dma_offset);
txdl_priv->bytes_sent += (unsigned int)txdl_priv->align_dma_offset;
fifo->stats->total_buffers++;
fifo->stats->copied_buffers++;
txdl_priv->frags++;
txdl_priv->align_used_frags++;
#if defined(VXGE_OS_DMA_REQUIRES_SYNC)
/* sync pre-mapped buffer */
vxge_os_dma_sync(fifo->channel.pdev,
txdl_priv->align_dma_handle,
txdp->buffer_pointer,
0,
txdl_priv->align_dma_offset,
VXGE_OS_DMA_DIR_TODEVICE);
#endif
/* increment vaddr_start for the next buffer_append() iteration */
txdl_priv->align_vaddr_start += txdl_priv->align_dma_offset;
txdl_priv->align_dma_offset = 0;
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
}
/*
* vxge_hal_fifo_txdl_new_frame_set - Start the new packet by setting TXDL flags
* @vpath_handle: virtual path handle.
* @txdlh: Descriptor handle.
* @tagged: Is the frame tagged
*
* This API is part of the preparation of the transmit descriptor for posting
* (via vxge_hal_fifo_txdl_post()). This api is used to mark the end of previous
* frame and start of a new frame.
*
*/
void
vxge_hal_fifo_txdl_new_frame_set(
vxge_hal_vpath_h vpath_handle,
vxge_hal_txdl_h txdlh,
u32 tagged)
{
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
__hal_fifo_t *fifo;
__hal_device_t *hldev;
__hal_fifo_txdl_priv_t *txdl_priv;
vxge_hal_fifo_txd_t *txdp;
vxge_assert((vpath_handle != NULL) && (txdlh != NULL));
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
"txdlh = 0x"VXGE_OS_STXFMT", tagged = %d",
(ptr_t) vpath_handle, (ptr_t) txdlh, tagged);
fifo = (__hal_fifo_t *) vp->vpath->fifoh;
vxge_assert(fifo != NULL);
txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
txdp = (vxge_hal_fifo_txd_t *) txdlh + txdl_priv->frags;
txdp->control_0 |=
VXGE_HAL_FIFO_TXD_HOST_STEER(vp->vpath->vp_config->wire_port);
txdp->control_0 |= VXGE_HAL_FIFO_TXD_GATHER_CODE(
VXGE_HAL_FIFO_TXD_GATHER_CODE_FIRST);
txdp->control_1 |= fifo->interrupt_type;
txdp->control_1 |= VXGE_HAL_FIFO_TXD_INT_NUMBER(
vp->vpath->tx_intr_num);
if (tagged)
txdp->control_1 |= VXGE_HAL_FIFO_TXD_NO_BW_LIMIT;
if (txdl_priv->frags) {
txdp = (vxge_hal_fifo_txd_t *) txdlh + (txdl_priv->frags - 1);
txdp->control_0 |= VXGE_HAL_FIFO_TXD_GATHER_CODE(
VXGE_HAL_FIFO_TXD_GATHER_CODE_LAST);
}
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
}
/*
* vxge_hal_fifo_txdl_post - Post descriptor on the fifo channel.
* @vpath_handle: Virtual path handle.
* @txdlh: Descriptor obtained via vxge_hal_fifo_txdl_reserve()
* @tagged: Is the frame tagged
*
* Post descriptor on the 'fifo' type channel for transmission.
* Prior to posting the descriptor should be filled in accordance with
* Host/X3100 interface specification for a given service (LL, etc.).
*
*/
void
vxge_hal_fifo_txdl_post(
vxge_hal_vpath_h vpath_handle,
vxge_hal_txdl_h txdlh,
u32 tagged)
{
u64 list_ptr;
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
__hal_fifo_t *fifo;
__hal_device_t *hldev;
__hal_fifo_txdl_priv_t *txdl_priv;
vxge_hal_fifo_txd_t *txdp_last;
vxge_hal_fifo_txd_t *txdp_first;
#if defined(VXGE_HAL_TX_MULTI_POST_IRQ)
unsigned long flags = 0;
#endif
vxge_assert((vpath_handle != NULL) && (txdlh != NULL));
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
"txdlh = 0x"VXGE_OS_STXFMT", tagged = %d",
(ptr_t) vpath_handle, (ptr_t) txdlh, tagged);
fifo = (__hal_fifo_t *) vp->vpath->fifoh;
vxge_assert(fifo != NULL);
txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
txdp_first = (vxge_hal_fifo_txd_t *) txdlh;
txdp_first->control_0 |=
VXGE_HAL_FIFO_TXD_HOST_STEER(vp->vpath->vp_config->wire_port);
txdp_first->control_0 |=
VXGE_HAL_FIFO_TXD_GATHER_CODE(VXGE_HAL_FIFO_TXD_GATHER_CODE_FIRST);
txdp_first->control_1 |=
VXGE_HAL_FIFO_TXD_INT_NUMBER(vp->vpath->tx_intr_num);
txdp_first->control_1 |= fifo->interrupt_type;
list_ptr = (u64) txdl_priv->dma_addr;
if (tagged) {
txdp_first->control_1 |= VXGE_HAL_FIFO_TXD_NO_BW_LIMIT;
list_ptr |= 0x1;
}
txdp_last =
(vxge_hal_fifo_txd_t *) txdlh + (txdl_priv->frags - 1);
txdp_last->control_0 |=
VXGE_HAL_FIFO_TXD_GATHER_CODE(VXGE_HAL_FIFO_TXD_GATHER_CODE_LAST);
#if defined(VXGE_HAL_TX_MULTI_POST)
vxge_os_spin_lock(&fifo->channel.post_lock);
#elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
vxge_os_spin_lock_irq(&fifo->channel.post_lock, flags);
#endif
txdp_first->control_0 |= VXGE_HAL_FIFO_TXD_LIST_OWN_ADAPTER;
#if defined(VXGE_DEBUG_ASSERT)
/* make sure device overwrites the t_code value on completion */
txdp_first->control_0 |=
VXGE_HAL_FIFO_TXD_T_CODE(VXGE_HAL_FIFO_TXD_T_CODE_UNUSED);
#endif
#if defined(VXGE_OS_DMA_REQUIRES_SYNC) && defined(VXGE_HAL_DMA_TXDL_STREAMING)
/* sync the TxDL to device */
vxge_os_dma_sync(fifo->channel.pdev,
txdl_priv->dma_handle,
txdl_priv->dma_addr,
txdl_priv->dma_offset,
txdl_priv->frags << 5, /* sizeof(vxge_hal_fifo_txd_t) */
VXGE_OS_DMA_DIR_TODEVICE);
#endif
/*
* we want touch dtr_arr in order with ownership bit set to HW
*/
__hal_channel_dtr_post(&fifo->channel, VXGE_HAL_FIFO_TXDL_INDEX(txdlh));
__hal_non_offload_db_post(vpath_handle,
list_ptr,
txdl_priv->frags - 1,
vp->vpath->vp_config->fifo.no_snoop_bits);
#if defined(VXGE_HAL_FIFO_DUMP_TXD)
vxge_hal_info_log_fifo(
""VXGE_OS_LLXFMT":"VXGE_OS_LLXFMT":"VXGE_OS_LLXFMT":"
VXGE_OS_LLXFMT" dma "VXGE_OS_LLXFMT,
txdp_first->control_0, txdp_first->control_1,
txdp_first->buffer_pointer, VXGE_HAL_FIFO_TXDL_INDEX(txdp_first),
txdl_priv->dma_addr);
#endif
fifo->stats->total_posts++;
fifo->stats->common_stats.usage_cnt++;
if (fifo->stats->common_stats.usage_max <
fifo->stats->common_stats.usage_cnt)
fifo->stats->common_stats.usage_max =
fifo->stats->common_stats.usage_cnt;
#if defined(VXGE_HAL_TX_MULTI_POST)
vxge_os_spin_unlock(&fifo->channel.post_lock);
#elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
vxge_os_spin_unlock_irq(&fifo->channel.post_lock, flags);
#endif
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
}
/*
* vxge_hal_fifo_is_next_txdl_completed - Checks if the next txdl is completed
* @vpath_handle: Virtual path handle.
*/
vxge_hal_status_e
vxge_hal_fifo_is_next_txdl_completed(vxge_hal_vpath_h vpath_handle)
{
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
__hal_fifo_t *fifo;
__hal_device_t *hldev;
vxge_hal_fifo_txd_t *txdp;
vxge_hal_txdl_h txdlh;
vxge_hal_status_e status = VXGE_HAL_INF_NO_MORE_COMPLETED_DESCRIPTORS;
#if defined(VXGE_HAL_TX_MULTI_POST_IRQ)
unsigned long flags = 0;
#endif
vxge_assert(vpath_handle != NULL);
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT,
(ptr_t) vpath_handle);
fifo = (__hal_fifo_t *) vp->vpath->fifoh;
vxge_assert(fifo != NULL);
#if defined(VXGE_HAL_TX_MULTI_POST)
vxge_os_spin_lock(&fifo->channel.post_lock);
#elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
vxge_os_spin_lock_irq(&fifo->channel.post_lock, flags);
#endif
__hal_channel_dtr_try_complete(&fifo->channel, &txdlh);
txdp = (vxge_hal_fifo_txd_t *) txdlh;
if ((txdp != NULL) &&
(!(txdp->control_0 & VXGE_HAL_FIFO_TXD_LIST_OWN_ADAPTER))) {
status = VXGE_HAL_OK;
}
#if defined(VXGE_HAL_TX_MULTI_POST)
vxge_os_spin_unlock(&fifo->channel.post_lock);
#elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
vxge_os_spin_unlock_irq(&fifo->channel.post_lock, flags);
#endif
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: %d",
__FILE__, __func__, __LINE__, status);
/* no more completions */
return (status);
}
/*
* vxge_hal_fifo_txdl_next_completed - Retrieve next completed descriptor.
* @vpath_handle: Virtual path handle.
* @txdlh: Descriptor handle. Returned by HAL.
* @txdl_priv: Buffer to return the pointer to per txdl space
* @t_code: Transfer code, as per X3100 User Guide,
* Transmit Descriptor Format.
* Returned by HAL.
*
* Retrieve the _next_ completed descriptor.
* HAL uses channel callback (*vxge_hal_channel_callback_f) to notifiy
* upper-layer driver (ULD) of new completed descriptors. After that
* the ULD can use vxge_hal_fifo_txdl_next_completed to retrieve the rest
* completions (the very first completion is passed by HAL via
* vxge_hal_channel_callback_f).
*
* Implementation-wise, the upper-layer driver is free to call
* vxge_hal_fifo_txdl_next_completed either immediately from inside the
* channel callback, or in a deferred fashion and separate (from HAL)
* context.
*
* Non-zero @t_code means failure to process the descriptor.
* The failure could happen, for instance, when the link is
* down, in which case X3100 completes the descriptor because it
* is not able to send the data out.
*
* For details please refer to X3100 User Guide.
*
* Returns: VXGE_HAL_OK - success.
* VXGE_HAL_INF_NO_MORE_COMPLETED_DESCRIPTORS - No completed descriptors
* are currently available for processing.
*
*/
vxge_hal_status_e
vxge_hal_fifo_txdl_next_completed(
vxge_hal_vpath_h vpath_handle,
vxge_hal_txdl_h * txdlh,
void **txdl_priv,
vxge_hal_fifo_tcode_e * t_code)
{
__hal_fifo_t *fifo;
__hal_device_t *hldev;
vxge_hal_fifo_txd_t *txdp;
#if defined(VXGE_OS_DMA_REQUIRES_SYNC) && defined(VXGE_HAL_DMA_TXDL_STREAMING)
__hal_fifo_txdl_priv_t *priv;
#endif
#if defined(VXGE_HAL_TX_MULTI_POST_IRQ)
unsigned long flags = 0;
#endif
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
vxge_hal_status_e status = VXGE_HAL_INF_NO_MORE_COMPLETED_DESCRIPTORS;
vxge_assert((vpath_handle != NULL) &&
(txdlh != NULL) && (t_code != NULL));
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
"txdlh = 0x"VXGE_OS_STXFMT", t_code = 0x"VXGE_OS_STXFMT,
(ptr_t) vpath_handle, (ptr_t) txdlh, (ptr_t) t_code);
fifo = (__hal_fifo_t *) vp->vpath->fifoh;
vxge_assert(fifo != NULL);
*txdlh = 0;
#if defined(VXGE_HAL_TX_MULTI_POST)
vxge_os_spin_lock(&fifo->channel.post_lock);
#elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
vxge_os_spin_lock_irq(&fifo->channel.post_lock, flags);
#endif
__hal_channel_dtr_try_complete(&fifo->channel, txdlh);
txdp = (vxge_hal_fifo_txd_t *) * txdlh;
if (txdp != NULL) {
#if defined(VXGE_OS_DMA_REQUIRES_SYNC) && defined(VXGE_HAL_DMA_TXDL_STREAMING)
priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdp);
/*
* sync TxDL to read the ownership
*
* Note: 16bytes means Control_1 & Control_2
*/
vxge_os_dma_sync(fifo->channel.pdev,
priv->dma_handle,
priv->dma_addr,
priv->dma_offset,
16,
VXGE_OS_DMA_DIR_FROMDEVICE);
#endif
/* check whether host owns it */
if (!(txdp->control_0 & VXGE_HAL_FIFO_TXD_LIST_OWN_ADAPTER)) {
__hal_channel_dtr_complete(&fifo->channel);
*txdl_priv = VXGE_HAL_FIFO_ULD_PRIV(fifo, txdp);
*t_code = (vxge_hal_fifo_tcode_e)
VXGE_HAL_FIFO_TXD_T_CODE_GET(txdp->control_0);
if (fifo->stats->common_stats.usage_cnt > 0)
fifo->stats->common_stats.usage_cnt--;
status = VXGE_HAL_OK;
}
}
/* no more completions */
#if defined(VXGE_HAL_TX_MULTI_POST)
vxge_os_spin_unlock(&fifo->channel.post_lock);
#elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
vxge_os_spin_unlock_irq(&fifo->channel.post_lock, flags);
#endif
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: %d",
__FILE__, __func__, __LINE__, status);
return (status);
}
/*
* vxge_hal_fifo_handle_tcode - Handle transfer code.
* @vpath_handle: Virtual Path handle.
* @txdlh: Descriptor handle.
* @t_code: One of the enumerated (and documented in the X3100 user guide)
* "transfer codes".
*
* Handle descriptor's transfer code. The latter comes with each completed
* descriptor.
*
* Returns: one of the vxge_hal_status_e {} enumerated types.
* VXGE_HAL_OK - for success.
* VXGE_HAL_ERR_CRITICAL - when encounters critical error.
*/
vxge_hal_status_e
vxge_hal_fifo_handle_tcode(
vxge_hal_vpath_h vpath_handle,
vxge_hal_txdl_h txdlh,
vxge_hal_fifo_tcode_e t_code)
{
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
__hal_device_t *hldev;
vxge_assert((vpath_handle != NULL) && (txdlh != NULL));
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
"txdlh = 0x"VXGE_OS_STXFMT", t_code = 0x%d",
(ptr_t) vpath_handle, (ptr_t) txdlh, t_code);
switch ((t_code & 0x7)) {
case 0:
/* 000: Transfer operation completed successfully. */
break;
case 1:
/*
* 001: a PCI read transaction (either TxD or frame data)
* returned with corrupt data.
*/
break;
case 2:
/* 010: a PCI read transaction was returned with no data. */
break;
case 3:
/*
* 011: The host attempted to send either a frame or LSO
* MSS that was too long (>9800B).
*/
break;
case 4:
/*
* 100: Error detected during TCP/UDP Large Send
* Offload operation, due to improper header template,
* unsupported protocol, etc.
*/
break;
default:
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: %d",
__FILE__, __func__, __LINE__, VXGE_HAL_ERR_INVALID_TCODE);
return (VXGE_HAL_ERR_INVALID_TCODE);
}
vp->vpath->sw_stats->fifo_stats.txd_t_code_err_cnt[t_code]++;
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: %d",
__FILE__, __func__, __LINE__, VXGE_HAL_OK);
return (VXGE_HAL_OK);
}
/*
* __hal_fifo_txdl_free_many - Free the fragments
* @fifo: FIFO
* @txdp: Poniter to a TxD
* @list_size: List size
* @frags: Number of fragments
*
* This routinf frees the fragments in a txdl
*/
void
__hal_fifo_txdl_free_many(
__hal_fifo_t *fifo,
vxge_hal_fifo_txd_t * txdp,
u32 list_size,
u32 frags)
{
__hal_fifo_txdl_priv_t *current_txdl_priv;
__hal_fifo_txdl_priv_t *next_txdl_priv;
u32 invalid_frags = frags % list_size;
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) fifo->channel.vph;
__hal_device_t *hldev;
vxge_assert((fifo != NULL) && (txdp != NULL));
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo(
"fifo = 0x"VXGE_OS_STXFMT", txdp = 0x"VXGE_OS_STXFMT", "
"list_size = %d, frags = %d", (ptr_t) fifo, (ptr_t) txdp,
list_size, frags);
if (invalid_frags) {
vxge_hal_trace_log_fifo(
"freeing corrupt txdlh 0x"VXGE_OS_STXFMT", "
"fragments %d list size %d",
(ptr_t) txdp, frags, list_size);
vxge_assert(invalid_frags == 0);
}
while (txdp) {
vxge_hal_trace_log_fifo("freeing linked txdlh 0x"VXGE_OS_STXFMT
", " "fragments %d list size %d",
(ptr_t) txdp, frags, list_size);
current_txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdp);
#if defined(VXGE_DEBUG_ASSERT) && defined(VXGE_OS_MEMORY_CHECK)
current_txdl_priv->allocated = 0;
#endif
__hal_channel_dtr_free(&fifo->channel,
VXGE_HAL_FIFO_TXDL_INDEX(txdp));
next_txdl_priv = current_txdl_priv->next_txdl_priv;
vxge_assert(frags);
frags -= list_size;
if (next_txdl_priv) {
current_txdl_priv->next_txdl_priv = NULL;
txdp = next_txdl_priv->first_txdp;
} else {
vxge_hal_trace_log_fifo(
"freed linked txdlh fragments %d list size %d",
frags, list_size);
break;
}
}
vxge_assert(frags == 0);
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
}
/*
* vxge_hal_fifo_txdl_free - Free descriptor.
* @vpath_handle: Virtual path handle.
* @txdlh: Descriptor handle.
*
* Free the reserved descriptor. This operation is "symmetrical" to
* vxge_hal_fifo_txdl_reserve. The "free-ing" completes the descriptor's
* lifecycle.
*
* After free-ing (see vxge_hal_fifo_txdl_free()) the descriptor again can
* be:
*
* - reserved (vxge_hal_fifo_txdl_reserve);
*
* - posted (vxge_hal_fifo_txdl_post);
*
* - completed (vxge_hal_fifo_txdl_next_completed);
*
* - and recycled again (vxge_hal_fifo_txdl_free).
*
* For alternative state transitions and more details please refer to
* the design doc.
*
*/
void
vxge_hal_fifo_txdl_free(
vxge_hal_vpath_h vpath_handle,
vxge_hal_txdl_h txdlh)
{
__hal_vpath_handle_t *vp = (__hal_vpath_handle_t *) vpath_handle;
__hal_fifo_t *fifo;
__hal_device_t *hldev;
__hal_fifo_txdl_priv_t *txdl_priv;
u32 max_frags;
#if defined(VXGE_HAL_TX_MULTI_POST_IRQ)
u32 flags = 0;
#endif
vxge_assert((vpath_handle != NULL) && (txdlh != NULL));
hldev = vp->vpath->hldev;
vxge_hal_trace_log_fifo("==> %s:%s:%d",
__FILE__, __func__, __LINE__);
vxge_hal_trace_log_fifo("vpath_handle = 0x"VXGE_OS_STXFMT", "
"txdlh = 0x"VXGE_OS_STXFMT, (ptr_t) vpath_handle, (ptr_t) txdlh);
fifo = (__hal_fifo_t *) vp->vpath->fifoh;
vxge_assert(fifo != NULL);
txdl_priv = VXGE_HAL_FIFO_HAL_PRIV(fifo, txdlh);
max_frags = fifo->config->max_frags;
#if defined(VXGE_HAL_TX_MULTI_POST)
vxge_os_spin_lock(&fifo->channel.post_lock);
#elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
vxge_os_spin_lock_irq(&fifo->channel.post_lock, flags);
#endif
if (txdl_priv->alloc_frags > max_frags) {
vxge_hal_fifo_txd_t *dang_txdp = (vxge_hal_fifo_txd_t *)
txdl_priv->dang_txdl;
u32 dang_frags = txdl_priv->dang_frags;
u32 alloc_frags = txdl_priv->alloc_frags;
txdl_priv->dang_txdl = NULL;
txdl_priv->dang_frags = 0;
txdl_priv->alloc_frags = 0;
/* txdlh must have a linked list of txdlh */
vxge_assert(txdl_priv->next_txdl_priv);
/* free any dangling txdlh first */
if (dang_txdp) {
vxge_hal_info_log_fifo(
"freeing dangled txdlh 0x"VXGE_OS_STXFMT" for %d "
"fragments", (ptr_t) dang_txdp, dang_frags);
__hal_fifo_txdl_free_many(fifo, dang_txdp,
max_frags, dang_frags);
}
/* now free the reserved txdlh list */
vxge_hal_info_log_fifo(
"freeing txdlh 0x"VXGE_OS_STXFMT" list of %d fragments",
(ptr_t) txdlh, alloc_frags);
__hal_fifo_txdl_free_many(fifo,
(vxge_hal_fifo_txd_t *) txdlh, max_frags,
alloc_frags);
} else {
__hal_channel_dtr_free(&fifo->channel,
VXGE_HAL_FIFO_TXDL_INDEX(txdlh));
}
fifo->channel.poll_bytes += txdl_priv->bytes_sent;
#if defined(VXGE_DEBUG_ASSERT) && defined(VXGE_OS_MEMORY_CHECK)
txdl_priv->allocated = 0;
#endif
#if defined(VXGE_HAL_TX_MULTI_POST)
vxge_os_spin_unlock(&fifo->channel.post_lock);
#elif defined(VXGE_HAL_TX_MULTI_POST_IRQ)
vxge_os_spin_unlock_irq(&fifo->channel.post_lock, flags);
#endif
vxge_hal_trace_log_fifo("<== %s:%s:%d Result: 0",
__FILE__, __func__, __LINE__);
}