#ifdef XGE_DEBUG_FP
#include "xgehal-fifo.h"
#endif
__HAL_STATIC_FIFO __HAL_INLINE_FIFO xge_hal_fifo_txdl_priv_t*
__hal_fifo_txdl_priv(xge_hal_dtr_h dtrh)
{
xge_hal_fifo_txd_t *txdp = (xge_hal_fifo_txd_t*)dtrh;
xge_hal_fifo_txdl_priv_t *txdl_priv;
xge_assert(txdp);
txdl_priv = (xge_hal_fifo_txdl_priv_t *)
(ulong_t)txdp->host_control;
xge_assert(txdl_priv);
xge_assert(txdl_priv->dma_object);
xge_assert(txdl_priv->dma_addr);
xge_assert(txdl_priv->dma_object->handle == txdl_priv->dma_handle);
return txdl_priv;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO void
__hal_fifo_dtr_post_single(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
u64 ctrl_1)
{
xge_hal_fifo_t *fifo = (xge_hal_fifo_t *)channelh;
xge_hal_fifo_hw_pair_t *hw_pair = fifo->hw_pair;
xge_hal_fifo_txd_t *txdp = (xge_hal_fifo_txd_t *)dtrh;
xge_hal_fifo_txdl_priv_t *txdl_priv;
u64 ctrl;
txdp->control_1 |= XGE_HAL_TXD_LIST_OWN_XENA;
#ifdef XGE_DEBUG_ASSERT
XGE_HAL_SET_TXD_T_CODE(txdp->control_1, XGE_HAL_TXD_T_CODE_UNUSED_5);
#endif
txdl_priv = __hal_fifo_txdl_priv(dtrh);
#if defined(XGE_OS_DMA_REQUIRES_SYNC) && defined(XGE_HAL_DMA_DTR_STREAMING)
xge_os_dma_sync(fifo->channel.pdev,
txdl_priv->dma_handle,
txdl_priv->dma_addr,
txdl_priv->dma_offset,
txdl_priv->frags << 5 ,
XGE_OS_DMA_DIR_TODEVICE);
#endif
xge_os_pio_mem_write64(fifo->channel.pdev,
fifo->channel.regh1,
txdl_priv->dma_addr,
&hw_pair->txdl_pointer);
ctrl = XGE_HAL_TX_FIFO_LAST_TXD_NUM(txdl_priv->frags - 1);
ctrl |= ctrl_1;
ctrl |= fifo->no_snoop_bits;
if (txdp->control_1 & XGE_HAL_TXD_LSO_COF_CTRL(XGE_HAL_TXD_TCP_LSO)) {
ctrl |= XGE_HAL_TX_FIFO_SPECIAL_FUNC;
}
xge_os_wmb();
__hal_channel_dtr_post(channelh, dtrh);
xge_os_pio_mem_write64(fifo->channel.pdev, fifo->channel.regh1,
ctrl, &hw_pair->list_control);
xge_debug_fifo(XGE_TRACE, "posted txdl 0x"XGE_OS_LLXFMT" ctrl 0x"XGE_OS_LLXFMT" "
"into 0x"XGE_OS_LLXFMT"", (unsigned long long)txdl_priv->dma_addr,
(unsigned long long)ctrl,
(unsigned long long)(ulong_t)&hw_pair->txdl_pointer);
#ifdef XGE_HAL_FIFO_DUMP_TXD
xge_os_printf(""XGE_OS_LLXFMT":"XGE_OS_LLXFMT":"XGE_OS_LLXFMT":"
XGE_OS_LLXFMT" dma "XGE_OS_LLXFMT,
txdp->control_1, txdp->control_2, txdp->buffer_pointer,
txdp->host_control, txdl_priv->dma_addr);
#endif
fifo->channel.stats.total_posts++;
fifo->channel.usage_cnt++;
if (fifo->channel.stats.usage_max < fifo->channel.usage_cnt)
fifo->channel.stats.usage_max = fifo->channel.usage_cnt;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO void
__hal_fifo_txdl_free_many(xge_hal_channel_h channelh,
xge_hal_fifo_txd_t *txdp, int list_size, int frags)
{
xge_hal_fifo_txdl_priv_t *current_txdl_priv;
xge_hal_fifo_txdl_priv_t *next_txdl_priv;
int invalid_frags = frags % list_size;
if (invalid_frags){
xge_debug_fifo(XGE_ERR,
"freeing corrupt dtrh %p, fragments %d list size %d",
txdp, frags, list_size);
xge_assert(invalid_frags == 0);
}
while(txdp){
xge_debug_fifo(XGE_TRACE,
"freeing linked dtrh %p, fragments %d list size %d",
txdp, frags, list_size);
current_txdl_priv = __hal_fifo_txdl_priv(txdp);
#if defined(XGE_DEBUG_ASSERT) && defined(XGE_OS_MEMORY_CHECK)
current_txdl_priv->allocated = 0;
#endif
__hal_channel_dtr_free(channelh, txdp);
next_txdl_priv = current_txdl_priv->next_txdl_priv;
xge_assert(frags);
frags -= list_size;
if (next_txdl_priv) {
current_txdl_priv->next_txdl_priv = NULL;
txdp = next_txdl_priv->first_txdp;
}
else {
xge_debug_fifo(XGE_TRACE,
"freed linked dtrh fragments %d list size %d",
frags, list_size);
break;
}
}
xge_assert(frags == 0)
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO void
__hal_fifo_txdl_restore_many(xge_hal_channel_h channelh,
xge_hal_fifo_txd_t *txdp, int txdl_count)
{
xge_hal_fifo_txdl_priv_t *current_txdl_priv;
xge_hal_fifo_txdl_priv_t *next_txdl_priv;
int i = txdl_count;
xge_assert(((xge_hal_channel_t *)channelh)->reserve_length +
txdl_count <= ((xge_hal_channel_t *)channelh)->reserve_initial);
current_txdl_priv = __hal_fifo_txdl_priv(txdp);
do{
xge_assert(i);
#if defined(XGE_DEBUG_ASSERT) && defined(XGE_OS_MEMORY_CHECK)
current_txdl_priv->allocated = 0;
#endif
next_txdl_priv = current_txdl_priv->next_txdl_priv;
txdp = current_txdl_priv->first_txdp;
current_txdl_priv->next_txdl_priv = NULL;
__hal_channel_dtr_restore(channelh, (xge_hal_dtr_h )txdp, --i);
xge_debug_fifo(XGE_TRACE,
"dtrh %p restored at offset %d", txdp, i);
current_txdl_priv = next_txdl_priv;
} while(current_txdl_priv);
__hal_channel_dtr_restore(channelh, NULL, txdl_count);
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO void*
xge_hal_fifo_dtr_private(xge_hal_dtr_h dtrh)
{
xge_hal_fifo_txd_t *txdp = (xge_hal_fifo_txd_t *)dtrh;
return ((char *)(ulong_t)txdp->host_control) +
sizeof(xge_hal_fifo_txdl_priv_t);
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO int
xge_hal_fifo_dtr_buffer_cnt(xge_hal_dtr_h dtrh)
{
xge_hal_fifo_txdl_priv_t *txdl_priv;
txdl_priv = __hal_fifo_txdl_priv(dtrh);
return txdl_priv->frags;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO xge_hal_status_e
xge_hal_fifo_dtr_reserve_many(xge_hal_channel_h channelh,
xge_hal_dtr_h *dtrh, const int frags)
{
xge_hal_status_e status = XGE_HAL_OK;
int alloc_frags = 0, dang_frags = 0;
xge_hal_fifo_txd_t *curr_txdp = NULL;
xge_hal_fifo_txd_t *next_txdp;
xge_hal_fifo_txdl_priv_t *next_txdl_priv, *curr_txdl_priv = NULL;
xge_hal_fifo_t *fifo = (xge_hal_fifo_t *)channelh;
int max_frags = fifo->config->max_frags;
xge_hal_dtr_h dang_dtrh = NULL;
#if defined(XGE_HAL_TX_MULTI_RESERVE_IRQ)
unsigned long flags=0;
#endif
xge_debug_fifo(XGE_TRACE, "dtr_reserve_many called for frags %d",
frags);
xge_assert(frags < (fifo->txdl_per_memblock * max_frags));
#if defined(XGE_HAL_TX_MULTI_RESERVE)
xge_os_spin_lock(&fifo->channel.reserve_lock);
#elif defined(XGE_HAL_TX_MULTI_RESERVE_IRQ)
xge_os_spin_lock_irq(&fifo->channel.reserve_lock, flags);
#endif
while(alloc_frags < frags) {
status = __hal_channel_dtr_alloc(channelh,
(xge_hal_dtr_h *)(void*)&next_txdp);
if (status != XGE_HAL_OK){
xge_debug_fifo(XGE_ERR,
"failed to allocate linked fragments rc %d",
status);
xge_assert(status == XGE_HAL_INF_OUT_OF_DESCRIPTORS);
if (*dtrh) {
xge_assert(alloc_frags/max_frags);
__hal_fifo_txdl_restore_many(channelh,
(xge_hal_fifo_txd_t *) *dtrh, alloc_frags/max_frags);
}
if (dang_dtrh) {
xge_assert(dang_frags/max_frags);
__hal_fifo_txdl_restore_many(channelh,
(xge_hal_fifo_txd_t *) dang_dtrh, dang_frags/max_frags);
}
break;
}
xge_debug_fifo(XGE_TRACE, "allocated linked dtrh %p"
" for frags %d", next_txdp, frags);
next_txdl_priv = __hal_fifo_txdl_priv(next_txdp);
xge_assert(next_txdl_priv);
xge_assert(next_txdl_priv->first_txdp == next_txdp);
next_txdl_priv->dang_txdl = NULL;
next_txdl_priv->dang_frags = 0;
next_txdl_priv->next_txdl_priv = NULL;
#if defined(XGE_OS_MEMORY_CHECK)
next_txdl_priv->allocated = 1;
#endif
if (!curr_txdp || !curr_txdl_priv) {
curr_txdp = next_txdp;
curr_txdl_priv = next_txdl_priv;
*dtrh = (xge_hal_dtr_h)next_txdp;
alloc_frags = max_frags;
continue;
}
if (curr_txdl_priv->memblock ==
next_txdl_priv->memblock) {
xge_debug_fifo(XGE_TRACE,
"linking dtrh %p, with %p",
*dtrh, next_txdp);
xge_assert (next_txdp ==
curr_txdp + max_frags);
alloc_frags += max_frags;
curr_txdl_priv->next_txdl_priv = next_txdl_priv;
}
else {
xge_assert(*dtrh);
xge_assert(dang_dtrh == NULL);
dang_dtrh = *dtrh;
dang_frags = alloc_frags;
xge_debug_fifo(XGE_TRACE,
"dangling dtrh %p, linked with dtrh %p",
*dtrh, next_txdp);
next_txdl_priv->dang_txdl = (xge_hal_fifo_txd_t *) *dtrh;
next_txdl_priv->dang_frags = alloc_frags;
alloc_frags = max_frags;
*dtrh = next_txdp;
}
curr_txdp = next_txdp;
curr_txdl_priv = next_txdl_priv;
}
#if defined(XGE_HAL_TX_MULTI_RESERVE)
xge_os_spin_unlock(&fifo->channel.reserve_lock);
#elif defined(XGE_HAL_TX_MULTI_RESERVE_IRQ)
xge_os_spin_unlock_irq(&fifo->channel.reserve_lock, flags);
#endif
if (status == XGE_HAL_OK) {
xge_hal_fifo_txdl_priv_t * txdl_priv;
xge_hal_fifo_txd_t *txdp = (xge_hal_fifo_txd_t *)*dtrh;
xge_hal_stats_channel_info_t *statsp = &fifo->channel.stats;
txdl_priv = __hal_fifo_txdl_priv(txdp);
txdl_priv->align_dma_offset = 0;
txdl_priv->align_vaddr_start = txdl_priv->align_vaddr;
txdl_priv->align_used_frags = 0;
txdl_priv->frags = 0;
txdl_priv->bytes_sent = 0;
txdl_priv->alloc_frags = alloc_frags;
txdp->control_1 = txdp->control_2 = 0;
#if defined(XGE_OS_MEMORY_CHECK)
txdl_priv->allocated = 1;
#endif
statsp->total_posts_dtrs_many++;
statsp->total_posts_frags_many += txdl_priv->alloc_frags;
if (txdl_priv->dang_frags){
statsp->total_posts_dang_dtrs++;
statsp->total_posts_dang_frags += txdl_priv->dang_frags;
}
}
return status;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO xge_hal_status_e
xge_hal_fifo_dtr_reserve(xge_hal_channel_h channelh, xge_hal_dtr_h *dtrh)
{
xge_hal_status_e status;
#if defined(XGE_HAL_TX_MULTI_RESERVE_IRQ)
unsigned long flags=0;
#endif
#if defined(XGE_HAL_TX_MULTI_RESERVE)
xge_os_spin_lock(&((xge_hal_channel_t*)channelh)->reserve_lock);
#elif defined(XGE_HAL_TX_MULTI_RESERVE_IRQ)
xge_os_spin_lock_irq(&((xge_hal_channel_t*)channelh)->reserve_lock,
flags);
#endif
status = __hal_channel_dtr_alloc(channelh, dtrh);
#if defined(XGE_HAL_TX_MULTI_RESERVE)
xge_os_spin_unlock(&((xge_hal_channel_t*)channelh)->reserve_lock);
#elif defined(XGE_HAL_TX_MULTI_RESERVE_IRQ)
xge_os_spin_unlock_irq(&((xge_hal_channel_t*)channelh)->reserve_lock,
flags);
#endif
if (status == XGE_HAL_OK) {
xge_hal_fifo_txd_t *txdp = (xge_hal_fifo_txd_t *)*dtrh;
xge_hal_fifo_txdl_priv_t *txdl_priv;
txdl_priv = __hal_fifo_txdl_priv(txdp);
txdl_priv->align_dma_offset = 0;
txdl_priv->align_vaddr_start = txdl_priv->align_vaddr;
txdl_priv->align_used_frags = 0;
txdl_priv->frags = 0;
txdl_priv->alloc_frags =
((xge_hal_fifo_t *)channelh)->config->max_frags;
txdl_priv->dang_txdl = NULL;
txdl_priv->dang_frags = 0;
txdl_priv->next_txdl_priv = NULL;
txdl_priv->bytes_sent = 0;
txdp->control_1 = txdp->control_2 = 0;
#if defined(XGE_OS_MEMORY_CHECK)
txdl_priv->allocated = 1;
#endif
}
return status;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO xge_hal_status_e
xge_hal_fifo_dtr_reserve_sp(xge_hal_channel_h channelh, int dtr_sp_size,
xge_hal_dtr_h dtr_sp)
{
return XGE_HAL_OK;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO void
xge_hal_fifo_dtr_post(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh)
{
xge_hal_fifo_t *fifo = (xge_hal_fifo_t *)channelh;
xge_hal_fifo_txdl_priv_t *txdl_priv;
xge_hal_fifo_txd_t *txdp_last;
xge_hal_fifo_txd_t *txdp_first;
#if defined(XGE_HAL_TX_MULTI_POST_IRQ)
unsigned long flags = 0;
#endif
txdl_priv = __hal_fifo_txdl_priv(dtrh);
txdp_first = (xge_hal_fifo_txd_t *)dtrh;
txdp_first->control_1 |= XGE_HAL_TXD_GATHER_CODE_FIRST;
txdp_first->control_2 |= fifo->interrupt_type;
txdp_last = (xge_hal_fifo_txd_t *)dtrh + (txdl_priv->frags - 1);
txdp_last->control_1 |= XGE_HAL_TXD_GATHER_CODE_LAST;
#if defined(XGE_HAL_TX_MULTI_POST)
xge_os_spin_lock(fifo->post_lock_ptr);
#elif defined(XGE_HAL_TX_MULTI_POST_IRQ)
xge_os_spin_lock_irq(fifo->post_lock_ptr, flags);
#endif
__hal_fifo_dtr_post_single(channelh, dtrh,
(u64)(XGE_HAL_TX_FIFO_FIRST_LIST | XGE_HAL_TX_FIFO_LAST_LIST));
#if defined(XGE_HAL_TX_MULTI_POST)
xge_os_spin_unlock(fifo->post_lock_ptr);
#elif defined(XGE_HAL_TX_MULTI_POST_IRQ)
xge_os_spin_unlock_irq(fifo->post_lock_ptr, flags);
#endif
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO void
xge_hal_fifo_dtr_post_many(xge_hal_channel_h channelh, int num,
xge_hal_dtr_h dtrs[])
{
int i;
xge_hal_fifo_t *fifo = (xge_hal_fifo_t *)channelh;
xge_hal_fifo_txd_t *txdp_last;
xge_hal_fifo_txd_t *txdp_first;
xge_hal_fifo_txdl_priv_t *txdl_priv_last;
#if defined(XGE_HAL_TX_MULTI_POST_IRQ)
unsigned long flags = 0;
#endif
xge_assert(num > 1);
txdp_first = (xge_hal_fifo_txd_t *)dtrs[0];
txdp_first->control_1 |= XGE_HAL_TXD_GATHER_CODE_FIRST;
txdp_first->control_2 |= fifo->interrupt_type;
txdl_priv_last = __hal_fifo_txdl_priv(dtrs[num-1]);
txdp_last = (xge_hal_fifo_txd_t *)dtrs[num-1] +
(txdl_priv_last->frags - 1);
txdp_last->control_1 |= XGE_HAL_TXD_GATHER_CODE_LAST;
#if defined(XGE_HAL_TX_MULTI_POST)
xge_os_spin_lock(&((xge_hal_channel_t*)channelh)->post_lock);
#elif defined(XGE_HAL_TX_MULTI_POST_IRQ)
xge_os_spin_lock_irq(&((xge_hal_channel_t*)channelh)->post_lock,
flags);
#endif
for (i=0; i<num; i++) {
xge_hal_fifo_txdl_priv_t *txdl_priv;
u64 val64;
xge_hal_dtr_h dtrh = dtrs[i];
txdl_priv = __hal_fifo_txdl_priv(dtrh);
txdl_priv = txdl_priv;
val64 = 0;
if (i == 0) {
val64 |= XGE_HAL_TX_FIFO_FIRST_LIST;
} else if (i == num -1) {
val64 |= XGE_HAL_TX_FIFO_LAST_LIST;
}
val64 |= XGE_HAL_TX_FIFO_SPECIAL_FUNC;
__hal_fifo_dtr_post_single(channelh, dtrh, val64);
}
#if defined(XGE_HAL_TX_MULTI_POST)
xge_os_spin_unlock(&((xge_hal_channel_t*)channelh)->post_lock);
#elif defined(XGE_HAL_TX_MULTI_POST_IRQ)
xge_os_spin_unlock_irq(&((xge_hal_channel_t*)channelh)->post_lock,
flags);
#endif
fifo->channel.stats.total_posts_many++;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO xge_hal_status_e
xge_hal_fifo_dtr_next_completed(xge_hal_channel_h channelh,
xge_hal_dtr_h *dtrh, u8 *t_code)
{
xge_hal_fifo_txd_t *txdp;
xge_hal_fifo_t *fifo = (xge_hal_fifo_t *)channelh;
#if defined(XGE_OS_DMA_REQUIRES_SYNC) && defined(XGE_HAL_DMA_DTR_STREAMING)
xge_hal_fifo_txdl_priv_t *txdl_priv;
#endif
__hal_channel_dtr_try_complete(channelh, dtrh);
txdp = (xge_hal_fifo_txd_t *)*dtrh;
if (txdp == NULL) {
return XGE_HAL_INF_NO_MORE_COMPLETED_DESCRIPTORS;
}
#if defined(XGE_OS_DMA_REQUIRES_SYNC) && defined(XGE_HAL_DMA_DTR_STREAMING)
txdl_priv = __hal_fifo_txdl_priv(txdp);
xge_os_dma_sync(fifo->channel.pdev,
txdl_priv->dma_handle,
txdl_priv->dma_addr,
txdl_priv->dma_offset,
16,
XGE_OS_DMA_DIR_FROMDEVICE);
#endif
if ( !(txdp->control_1 & XGE_HAL_TXD_LIST_OWN_XENA) ) {
xge_assert(txdp->host_control!=0);
__hal_channel_dtr_complete(channelh);
*t_code = (u8)XGE_HAL_GET_TXD_T_CODE(txdp->control_1);
xge_assert(*t_code != XGE_HAL_TXD_T_CODE_UNUSED_5);
if (fifo->channel.usage_cnt > 0)
fifo->channel.usage_cnt--;
return XGE_HAL_OK;
}
*dtrh = 0;
return XGE_HAL_INF_NO_MORE_COMPLETED_DESCRIPTORS;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO void
xge_hal_fifo_dtr_free(xge_hal_channel_h channelh, xge_hal_dtr_h dtr)
{
#if defined(XGE_HAL_TX_MULTI_FREE_IRQ)
unsigned long flags = 0;
#endif
xge_hal_fifo_txdl_priv_t *txdl_priv = __hal_fifo_txdl_priv(
(xge_hal_fifo_txd_t *)dtr);
int max_frags = ((xge_hal_fifo_t *)channelh)->config->max_frags;
#if defined(XGE_HAL_TX_MULTI_FREE)
xge_os_spin_lock(&((xge_hal_channel_t*)channelh)->free_lock);
#elif defined(XGE_HAL_TX_MULTI_FREE_IRQ)
xge_os_spin_lock_irq(&((xge_hal_channel_t*)channelh)->free_lock,
flags);
#endif
if (txdl_priv->alloc_frags > max_frags) {
xge_hal_fifo_txd_t *dang_txdp = (xge_hal_fifo_txd_t *)
txdl_priv->dang_txdl;
int dang_frags = txdl_priv->dang_frags;
int alloc_frags = txdl_priv->alloc_frags;
txdl_priv->dang_txdl = NULL;
txdl_priv->dang_frags = 0;
txdl_priv->alloc_frags = 0;
xge_assert(txdl_priv->next_txdl_priv);
if (dang_txdp) {
xge_debug_fifo(XGE_TRACE,
"freeing dangled dtrh %p for %d fragments",
dang_txdp, dang_frags);
__hal_fifo_txdl_free_many(channelh, dang_txdp,
max_frags, dang_frags);
}
xge_debug_fifo(XGE_TRACE,
"freeing dtrh %p list of %d fragments", dtr,
alloc_frags);
__hal_fifo_txdl_free_many(channelh,
(xge_hal_fifo_txd_t *)dtr, max_frags,
alloc_frags);
}
else
__hal_channel_dtr_free(channelh, dtr);
((xge_hal_channel_t *)channelh)->poll_bytes += txdl_priv->bytes_sent;
#if defined(XGE_DEBUG_ASSERT) && defined(XGE_OS_MEMORY_CHECK)
__hal_fifo_txdl_priv(dtr)->allocated = 0;
#endif
#if defined(XGE_HAL_TX_MULTI_FREE)
xge_os_spin_unlock(&((xge_hal_channel_t*)channelh)->free_lock);
#elif defined(XGE_HAL_TX_MULTI_FREE_IRQ)
xge_os_spin_unlock_irq(&((xge_hal_channel_t*)channelh)->free_lock,
flags);
#endif
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO xge_hal_status_e
xge_hal_fifo_dtr_buffer_set_aligned(xge_hal_channel_h channelh,
xge_hal_dtr_h dtrh, int frag_idx, void *vaddr,
dma_addr_t dma_pointer, int size, int misaligned_size)
{
xge_hal_fifo_t *fifo = (xge_hal_fifo_t *)channelh;
xge_hal_fifo_txdl_priv_t *txdl_priv;
xge_hal_fifo_txd_t *txdp;
int remaining_size;
ptrdiff_t prev_boff;
txdl_priv = __hal_fifo_txdl_priv(dtrh);
txdp = (xge_hal_fifo_txd_t *)dtrh + txdl_priv->frags;
if (frag_idx != 0) {
txdp->control_1 = txdp->control_2 = 0;
}
xge_assert(size > 0);
xge_assert(frag_idx < txdl_priv->alloc_frags);
xge_assert(misaligned_size != 0 &&
misaligned_size <= fifo->config->alignment_size);
remaining_size = size - misaligned_size;
xge_assert(remaining_size >= 0);
xge_os_memcpy((char*)txdl_priv->align_vaddr_start,
vaddr, misaligned_size);
if (txdl_priv->align_used_frags >= fifo->config->max_aligned_frags) {
return XGE_HAL_ERR_OUT_ALIGNED_FRAGS;
}
prev_boff = txdl_priv->align_vaddr_start - txdl_priv->align_vaddr;
txdp->buffer_pointer = (u64)txdl_priv->align_dma_addr + prev_boff;
txdp->control_1 |= XGE_HAL_TXD_BUFFER0_SIZE(misaligned_size);
txdl_priv->bytes_sent += misaligned_size;
fifo->channel.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(XGE_OS_DMA_REQUIRES_SYNC)
xge_os_dma_sync(fifo->channel.pdev,
txdl_priv->align_dma_handle,
txdp->buffer_pointer,
0,
misaligned_size,
XGE_OS_DMA_DIR_TODEVICE);
#endif
if (remaining_size) {
xge_assert(frag_idx < txdl_priv->alloc_frags);
txdp++;
txdp->buffer_pointer = (u64)dma_pointer +
misaligned_size;
txdp->control_1 =
XGE_HAL_TXD_BUFFER0_SIZE(remaining_size);
txdl_priv->bytes_sent += remaining_size;
txdp->control_2 = 0;
fifo->channel.stats.total_buffers++;
txdl_priv->frags++;
}
return XGE_HAL_OK;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO xge_hal_status_e
xge_hal_fifo_dtr_buffer_append(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
void *vaddr, int size)
{
xge_hal_fifo_t *fifo = (xge_hal_fifo_t *)channelh;
xge_hal_fifo_txdl_priv_t *txdl_priv;
ptrdiff_t used;
xge_assert(size > 0);
txdl_priv = __hal_fifo_txdl_priv(dtrh);
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 XGE_HAL_ERR_OUT_ALIGNED_FRAGS;
xge_os_memcpy((char*)txdl_priv->align_vaddr_start +
txdl_priv->align_dma_offset, vaddr, size);
fifo->channel.stats.copied_frags++;
txdl_priv->align_dma_offset += size;
return XGE_HAL_OK;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO void
xge_hal_fifo_dtr_buffer_finalize(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
int frag_idx)
{
xge_hal_fifo_t *fifo = (xge_hal_fifo_t *)channelh;
xge_hal_fifo_txdl_priv_t *txdl_priv;
xge_hal_fifo_txd_t *txdp;
ptrdiff_t prev_boff;
xge_assert(frag_idx < fifo->config->max_frags);
txdl_priv = __hal_fifo_txdl_priv(dtrh);
txdp = (xge_hal_fifo_txd_t *)dtrh + txdl_priv->frags;
if (frag_idx != 0) {
txdp->control_1 = txdp->control_2 = 0;
}
prev_boff = txdl_priv->align_vaddr_start - txdl_priv->align_vaddr;
txdp->buffer_pointer = (u64)txdl_priv->align_dma_addr + prev_boff;
txdp->control_1 |=
XGE_HAL_TXD_BUFFER0_SIZE(txdl_priv->align_dma_offset);
txdl_priv->bytes_sent += (unsigned int)txdl_priv->align_dma_offset;
fifo->channel.stats.total_buffers++;
fifo->channel.stats.copied_buffers++;
txdl_priv->frags++;
txdl_priv->align_used_frags++;
#if defined(XGE_OS_DMA_REQUIRES_SYNC)
xge_os_dma_sync(fifo->channel.pdev,
txdl_priv->align_dma_handle,
txdp->buffer_pointer,
0,
txdl_priv->align_dma_offset,
XGE_OS_DMA_DIR_TODEVICE);
#endif
txdl_priv->align_vaddr_start += txdl_priv->align_dma_offset;
txdl_priv->align_dma_offset = 0;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO void
xge_hal_fifo_dtr_buffer_set(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
int frag_idx, dma_addr_t dma_pointer, int size)
{
xge_hal_fifo_t *fifo = (xge_hal_fifo_t *)channelh;
xge_hal_fifo_txdl_priv_t *txdl_priv;
xge_hal_fifo_txd_t *txdp;
txdl_priv = __hal_fifo_txdl_priv(dtrh);
txdp = (xge_hal_fifo_txd_t *)dtrh + txdl_priv->frags;
if (frag_idx != 0) {
txdp->control_1 = txdp->control_2 = 0;
}
xge_assert(size > 0);
xge_assert(frag_idx < txdl_priv->alloc_frags);
txdp->buffer_pointer = (u64)dma_pointer;
txdp->control_1 |= XGE_HAL_TXD_BUFFER0_SIZE(size);
txdl_priv->bytes_sent += size;
fifo->channel.stats.total_buffers++;
txdl_priv->frags++;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO void
xge_hal_fifo_dtr_mss_set(xge_hal_dtr_h dtrh, int mss)
{
xge_hal_fifo_txd_t *txdp = (xge_hal_fifo_txd_t *)dtrh;
txdp->control_1 |= XGE_HAL_TXD_LSO_COF_CTRL(XGE_HAL_TXD_TCP_LSO);
txdp->control_1 |= XGE_HAL_TXD_TCP_LSO_MSS(mss);
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO void
xge_hal_fifo_dtr_cksum_set_bits(xge_hal_dtr_h dtrh, u64 cksum_bits)
{
xge_hal_fifo_txd_t *txdp = (xge_hal_fifo_txd_t *)dtrh;
txdp->control_2 |= cksum_bits;
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO void
xge_hal_fifo_dtr_vlan_set(xge_hal_dtr_h dtrh, u16 vlan_tag)
{
xge_hal_fifo_txd_t *txdp = (xge_hal_fifo_txd_t *)dtrh;
txdp->control_2 |= XGE_HAL_TXD_VLAN_ENABLE;
txdp->control_2 |= XGE_HAL_TXD_VLAN_TAG(vlan_tag);
}
__HAL_STATIC_FIFO __HAL_INLINE_FIFO xge_hal_status_e
xge_hal_fifo_is_next_dtr_completed(xge_hal_channel_h channelh)
{
xge_hal_fifo_txd_t *txdp;
xge_hal_dtr_h dtrh;
__hal_channel_dtr_try_complete(channelh, &dtrh);
txdp = (xge_hal_fifo_txd_t *)dtrh;
if (txdp == NULL) {
return XGE_HAL_INF_NO_MORE_COMPLETED_DESCRIPTORS;
}
if ( !(txdp->control_1 & XGE_HAL_TXD_LIST_OWN_XENA) ) {
xge_assert(txdp->host_control!=0);
return XGE_HAL_OK;
}
return XGE_HAL_INF_NO_MORE_COMPLETED_DESCRIPTORS;
}