in hw/mcu/nxp/src/ext/nxp-kinetis-sdk/drivers/fsl_enet.c [1707:1901]
status_t ENET_SendFrame(ENET_Type *base,
enet_handle_t *handle,
const uint8_t *data,
uint32_t length,
uint8_t ringId,
bool tsFlag,
void *context)
{
assert(handle != NULL);
assert(data != NULL);
assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1);
assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base));
volatile enet_tx_bd_struct_t *curBuffDescrip;
enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId];
enet_frame_info_t *txDirty = NULL;
uint32_t len = 0;
uint32_t sizeleft = 0;
uint32_t address;
status_t result = kStatus_Success;
uint32_t src;
uint32_t configVal;
bool isReturn = false;
/* Check the frame length. */
if (length > ENET_FRAME_MAX_FRAMELEN)
{
result = kStatus_ENET_TxFrameOverLen;
}
else
{
/* Check if the transmit buffer is ready. */
curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))
{
result = kStatus_ENET_TxFrameBusy;
}
/* Check txDirtyRing if need frameinfo in tx interrupt callback. */
else if ((handle->TxReclaimEnable[ringId]) && !ENET_TxDirtyRingAvailable(txDirtyRing))
{
result = kStatus_ENET_TxFrameBusy;
}
else
{
/* One transmit buffer is enough for one frame. */
if (handle->txBuffSizeAlign[ringId] >= length)
{
/* Copy data to the buffer for uDMA transfer. */
#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local);
#else
address = (uint32_t)curBuffDescrip->buffer;
#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
(void)memcpy((void *)(uint32_t *)address, (const void *)(uint32_t *)(uint32_t)data, length);
#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
if (handle->txMaintainEnable[ringId])
{
DCACHE_CleanByRange(address, length);
}
#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
/* Set data length. */
curBuffDescrip->length = (uint16_t)length;
#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
/* For enable the timestamp. */
if (tsFlag)
{
curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
}
else
{
curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
}
#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK);
/* Increase the buffer descriptor address. */
txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
/* Add context to frame info ring */
if (handle->TxReclaimEnable[ringId])
{
txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
txDirty->context = context;
txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
{
txDirtyRing->isFull = true;
}
txBdRing->txDescUsed++;
}
/* Active the transmit buffer descriptor. */
ENET_ActiveSend(base, ringId);
}
else
{
/* One frame requires more than one transmit buffers. */
do
{
#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
/* For enable the timestamp. */
if (tsFlag)
{
curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
}
else
{
curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
}
#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
/* Update the size left to be transmit. */
sizeleft = length - len;
#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local);
#else
address = (uint32_t)curBuffDescrip->buffer;
#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
src = (uint32_t)data + len;
if (sizeleft > handle->txBuffSizeAlign[ringId])
{
/* Data copy. */
(void)memcpy((void *)(uint32_t *)address, (void *)(uint32_t *)src,
handle->txBuffSizeAlign[ringId]);
#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
if (handle->txMaintainEnable[ringId])
{
/* Add the cache clean maintain. */
DCACHE_CleanByRange(address, handle->txBuffSizeAlign[ringId]);
}
#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
/* Data length update. */
curBuffDescrip->length = handle->txBuffSizeAlign[ringId];
len += handle->txBuffSizeAlign[ringId];
/* Sets the control flag. */
configVal = (uint32_t)curBuffDescrip->control;
configVal &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
configVal |= ENET_BUFFDESCRIPTOR_TX_READY_MASK;
curBuffDescrip->control = (uint16_t)configVal;
if (handle->TxReclaimEnable[ringId])
{
txBdRing->txDescUsed++;
}
/* Active the transmit buffer descriptor*/
ENET_ActiveSend(base, ringId);
}
else
{
(void)memcpy((void *)(uint32_t *)address, (void *)(uint32_t *)src, sizeleft);
#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
if (handle->txMaintainEnable[ringId])
{
/* Add the cache clean maintain. */
DCACHE_CleanByRange(address, sizeleft);
}
#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
curBuffDescrip->length = (uint16_t)sizeleft;
/* Set Last buffer wrap flag. */
curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
if (handle->TxReclaimEnable[ringId])
{
/* Add context to frame info ring */
txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
txDirty->context = context;
txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
{
txDirtyRing->isFull = true;
}
txBdRing->txDescUsed++;
}
/* Active the transmit buffer descriptor. */
ENET_ActiveSend(base, ringId);
isReturn = true;
break;
}
/* Increase and get the current buffer descriptor address. */
txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
} while (0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK));
if (isReturn == false)
{
result = kStatus_ENET_TxFrameBusy;
}
}
}
}
return result;
}