status_t ENET_SendFrame()

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;
}