Ejemplo n.º 1
0
/**
 * \brief Send a packet with GMAC. If the packet size is larger than transfer buffer size 
 * error returned. If packet transfer status is monitored, specify callback for each packet.
 *  \param pGmacd Pointer to GMAC Driver instance. 
 *  \param buffer   The buffer to be send
 *  \param size     The size of buffer to be send
 *  \param fGMAC_TxCallback Threshold Wakeup callback
 *  \param fWakeUpCb   TX Wakeup
 *  \return         OK, Busy or invalid packet
 */
uint8_t GMACD_Send(sGmacd *pGmacd,
                  void *pBuffer,
                  uint32_t size,
                  fGmacdTransferCallback fTxCb )
{
    Gmac *pHw = pGmacd->pHw;
    sGmacTxDescriptor      *pTxTd;
    volatile fGmacdTransferCallback *pfTxCb;
    
    TRACE_DEBUG("GMAC_Send\n\r");
    /* Check parameter */
    if (size > GMAC_TX_UNITSIZE) {

        TRACE_ERROR("GMAC driver does not split send packets.");
        return GMACD_PARAM;
    }

    /* Pointers to the current TxTd */
    pTxTd = &pGmacd->pTxD[pGmacd->wTxHead];
    /* If no free TxTd, buffer can't be sent */
    if( GCIRC_SPACE(pGmacd->wTxHead, pGmacd->wTxTail, pGmacd->wTxListSize) == 0)
        return GMACD_TX_BUSY;
    /* Pointers to the current Tx Callback */
    pfTxCb = &pGmacd->fTxCbList[pGmacd->wTxHead];
    /* Sanity check */

    /* Setup/Copy data to transmition buffer */
    if (pBuffer && size) {
        // Driver manage the ring buffer
        memcpy((void *)pTxTd->addr, pBuffer, size);
    }
    /* Tx Callback */
    *pfTxCb = fTxCb;

    /* Update TD status. The buffer size defined is length of ethernet frame
      so it's always the last buffer of the frame. */
    if (pGmacd->wTxHead == pGmacd->wTxListSize-1) {
        pTxTd->status.val = 
            (size & GMAC_LENGTH_FRAME) | GMAC_TX_LAST_BUFFER_BIT | GMAC_TX_WRAP_BIT;
    }
    else {
        pTxTd->status.val = (size & GMAC_LENGTH_FRAME) | GMAC_TX_LAST_BUFFER_BIT;
    }
    
    GCIRC_INC(pGmacd->wTxHead, pGmacd->wTxListSize);
    
    //CP15_flush_dcache_for_dma ((uint32_t)(pTxTd), ((uint32_t)(pTxTd) + sizeof(pTxTd)));
    /* Tx packets count */

    /* Now start to transmit if it is not already done */
    GMAC_TransmissionStart(pHw);

    return GMACD_OK;
}
Ejemplo n.º 2
0
/**
 * \brief Send a frame splitted into buffers. If the frame size is larger than transfer buffer size
 * error returned. If frame transfer status is monitored, specify callback for each frame.
 *  \param pGmacd Pointer to GMAC Driver instance. 
 *  \param sgl Pointer to a scatter-gather list describing the buffers of the ethernet frame.
 */
uint8_t GMACD_SendSG(sGmacd *pGmacd,
                     const sGmacSGList *sgl,
                     fGmacdTransferCallback fTxCb,
                     gmacQueList_t queIdx)
{
    Gmac *pHw = pGmacd->pHw;
    sGmacTxDescriptor *pTd = pGmacd->queueList[queIdx].pTxD;
    sGmacTxDescriptor *pTxTd;
    uint16_t wTxPos, wTxHead;
    int i;

    TRACE_DEBUG("%s\n\r", __FUNCTION__);

    /* Check parameter */
    if (!sgl->len) {
        TRACE_ERROR("%s:: ethernet frame is empty.\r\n", __FUNCTION__);
        return GMACD_PARAM;
    }
    if (sgl->len >= pGmacd->queueList[queIdx].wTxListSize) {
        TRACE_ERROR("%s: ethernet frame has too many buffers.\r\n", __FUNCTION__);
        return GMACD_PARAM;
    }

    /* Check available space */
    if (GCIRC_SPACE(pGmacd->queueList[queIdx].wTxHead, pGmacd->queueList[queIdx].wTxTail, pGmacd->queueList[queIdx].wTxListSize) < (int)sgl->len)
        return GMACD_TX_BUSY;

    /* Tag end of TX queue */
    wTxHead = fixed_mod(pGmacd->queueList[queIdx].wTxHead + sgl->len, pGmacd->queueList[queIdx].wTxListSize);
    wTxPos = wTxHead;
    pGmacd->queueList[queIdx].fTxCbList[wTxPos] = NULL;
    pTxTd = &pTd[wTxPos];
    pTxTd->status.val = GMAC_TX_USED_BIT;    

    /* Update buffer descriptors in reverse order to avoid a race 
     * condition with hardware.
     */
    for (i = (int)(sgl->len-1); i >= 0; --i) {
        const sGmacSG *sg = &sgl->sg[i];
        uint32_t status;

        if (sg->size > GMAC_TX_UNITSIZE) {
            TRACE_ERROR("%s: buffer size is too big.\r\n", __FUNCTION__);
            return GMACD_PARAM;
        }

        if (wTxPos == 0)
            wTxPos = pGmacd->queueList[queIdx].wTxListSize-1;
        else
            wTxPos--;

        /* Reset TX callback */
        pGmacd->queueList[queIdx].fTxCbList[wTxPos] = NULL;

        pTxTd = &pTd[wTxPos];
#ifdef GMAC_ZERO_COPY
        /** Update buffer descriptor address word:
         *  MUST be done before status word to avoid a race condition.
         */
        pTxTd->addr = (uint32_t)sg->pBuffer;        
#else
        /* Copy data into transmittion buffer */
        if (sg->pBuffer && sg->size)
            memcpy((void *)pTxTd->addr, sg->pBuffer, sg->size);        
#endif

        /* Compute buffer descriptor status word */
        status = sg->size & GMAC_LENGTH_FRAME;
        if (i == (int)(sgl->len-1)) {
            status |= GMAC_TX_LAST_BUFFER_BIT;
            pGmacd->queueList[queIdx].fTxCbList[wTxPos] = fTxCb;
        }
        if (wTxPos == pGmacd->queueList[queIdx].wTxListSize-1)
            status |= GMAC_TX_WRAP_BIT;

        /* Update buffer descriptor status word: clear USED bit */
        pTxTd->status.val = status;

        /* Make newly initialized descriptor visible to hardware */
        memory_barrier();
    }

    /* Update TX ring buffer pointers */
    pGmacd->queueList[queIdx].wTxHead = wTxHead;

    memory_barrier();
    /* Now start to transmit if it is not already done */
    GMAC_TransmissionStart(pHw);

    return GMACD_OK;
}