xdma_channel_sg.c

来自「linux嵌入式系统的dma方式的实现代码」· C语言 代码 · 共 1,247 行 · 第 1/4 页

C
1,247
字号
* - A value of XST_DMA_SG_NO_DATA indicates that the buffer descriptor of the*   scatter gather list which was to be started had already been used by the*   hardware for a DMA transfer that has been completed.** @note** It is the responsibility of the caller to get all the buffer descriptors* after performing a stop operation and before performing a start operation.* If buffer descriptors are not retrieved between stop and start operations,* buffer descriptors may be processed by the hardware more than once.*******************************************************************************/XStatus XDmaChannel_SgStart(XDmaChannel *InstancePtr){    Xuint32 Register;    XBufDescriptor *LastDescriptorPtr;    /* assert to verify input arguments */    XASSERT_NONVOID(InstancePtr != XNULL);    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);    /* if a scatter gather list has not been created yet, return a status */    if (InstancePtr->TotalDescriptorCount == 0)    {        return XST_DMA_SG_NO_LIST;    }    /* if the scatter gather list exists but is empty then return a status */    if (XDmaChannel_IsSgListEmpty(InstancePtr))    {        return XST_DMA_SG_LIST_EMPTY;    }    /* if scatter gather is busy for the DMA channel, return a status because     * restarting it could lose data     */    Register = XIo_In32(InstancePtr->RegBaseAddress + XDC_DMAS_REG_OFFSET);    if (Register & XDC_DMASR_SG_BUSY_MASK)    {        return XST_DMA_SG_IS_STARTED;    }    /* get the address of the last buffer descriptor which the DMA hardware     * finished processing     */    LastDescriptorPtr = (XBufDescriptor *)XIo_In32(InstancePtr->RegBaseAddress                                                   + XDC_BDA_REG_OFFSET);    /* setup the first buffer descriptor that will be sent when the scatter     * gather channel is enabled, this is only necessary one time since     * the BDA register of the channel maintains the last buffer descriptor     * processed     */    if (LastDescriptorPtr == XNULL)    {        XIo_Out32(InstancePtr->RegBaseAddress + XDC_BDA_REG_OFFSET,                  (Xuint32)InstancePtr->GetPtr);    }    else    {        XBufDescriptor *NextDescriptorPtr;        /* get the next descriptor to be started, if the status indicates it         * hasn't already been used by the hw, then it's OK to start it,         * sw sets the status of each descriptor to busy and then hw clears         * the busy when it is complete         */        NextDescriptorPtr = XBufDescriptor_GetNextPtr(LastDescriptorPtr);        if ((XBufDescriptor_GetStatus(NextDescriptorPtr) &             XDC_DMASR_BUSY_MASK) == 0)        {            return XST_DMA_SG_NO_DATA;        }        /* don't start the DMA SG channel if the descriptor to be processed         * by hw is to be committed by the sw, this function can be called         * such that it interrupts a thread that was putting into the list         */        if (NextDescriptorPtr == InstancePtr->CommitPtr)        {            return XST_DMA_SG_BD_NOT_COMMITTED;        }    }    /* start the scatter gather operation by clearing the stop bit in the     * control register and setting the enable bit in the sw control register,     * both of these are necessary to cause it to start, right now the order of     * these statements is important, the software control register should be     * set 1st.  The other order can cause the CPU to have a loss of sync     * because it cannot read/write the register while the DMA operation is     * running     */    Register = XIo_In32(InstancePtr->RegBaseAddress + XDC_SWCR_REG_OFFSET);    XIo_Out32(InstancePtr->RegBaseAddress + XDC_SWCR_REG_OFFSET,              Register | XDC_SWCR_SG_ENABLE_MASK);    Register = XIo_In32(InstancePtr->RegBaseAddress + XDC_DMAC_REG_OFFSET);    XIo_Out32(InstancePtr->RegBaseAddress + XDC_DMAC_REG_OFFSET,              Register & ~XDC_DMACR_SG_DISABLE_MASK);    /* indicate the DMA channel scatter gather operation was started     * successfully     */    return XST_SUCCESS;}/*****************************************************************************//**** This function stops a scatter gather operation for a scatter gather* DMA channel. This function starts the process of stopping a scatter* gather operation that is in progress and waits for the stop to be completed.* Since it waits for the operation to stopped before returning, this function* could take an amount of time relative to the size of the DMA scatter gather* operation which is in progress.  The scatter gather list of the DMA channel* is not modified by this function such that starting the scatter gather* channel after stopping it will cause it to resume.  This operation is* considered to be a graceful stop in that the scatter gather operation* completes the current buffer descriptor before stopping.** If the interrupt is enabled, an interrupt will be generated when the* operation is stopped and the caller is responsible for handling the* interrupt.** @param** InstancePtr contains a pointer to the DMA channel to operate on.  The DMA* channel should be configured to use scatter gather in order for this function* to be called.** @param** BufDescriptorPtr is also a return value which contains a pointer to the* buffer descriptor which the scatter gather operation completed when it* was stopped.** @return* - A status containing XST_SUCCESS if scatter gather was stopped successfully*   for the DMA channel.*   <br><br>* - A value of XST_DMA_SG_IS_STOPPED indicates scatter gather was not stopped*   because the scatter gather is not started, but was already stopped.*   <br><br>* - BufDescriptorPtr contains a pointer to the buffer descriptor which was*   completed when the operation was stopped.** @note** This function implements a loop which polls the hardware for an infinite* amount of time. If the hardware is not operating correctly, this function* may never return.*******************************************************************************/XStatus XDmaChannel_SgStop(XDmaChannel *InstancePtr,                           XBufDescriptor **BufDescriptorPtr){    Xuint32 Register;    /* assert to verify input arguments */    XASSERT_NONVOID(InstancePtr != XNULL);    XASSERT_NONVOID(BufDescriptorPtr != XNULL);    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);    /* get the contents of the software control register, if scatter gather is not     * enabled (started), then return a status because the disable acknowledge     * would not be generated     */    Register = XIo_In32(InstancePtr->RegBaseAddress + XDC_SWCR_REG_OFFSET);    if ((Register & XDC_SWCR_SG_ENABLE_MASK) == 0)    {        return XST_DMA_SG_IS_STOPPED;    }    /* disable scatter gather by writing to the software control register     * without modifying any other bits of the register     */    XIo_Out32(InstancePtr->RegBaseAddress + XDC_SWCR_REG_OFFSET,              Register & ~XDC_SWCR_SG_ENABLE_MASK);    /* scatter gather does not disable immediately, but after the current     * buffer descriptor is complete, so wait for the DMA channel to indicate     * the disable is complete     */    do    {        Register = XIo_In32(InstancePtr->RegBaseAddress + XDC_DMAS_REG_OFFSET);    }    while (Register & XDC_DMASR_SG_BUSY_MASK);    /* set the specified buffer descriptor pointer to point to the buffer     * descriptor that the scatter gather DMA channel was processing     */    *BufDescriptorPtr = (XBufDescriptor *)XIo_In32(InstancePtr->RegBaseAddress                                                   + XDC_BDA_REG_OFFSET);    return XST_SUCCESS;}/*****************************************************************************//**** This function creates a scatter gather list in the DMA channel.  A scatter* gather list consists of a list of buffer descriptors that are available to* be used for scatter gather operations.  Buffer descriptors are put into the* list to request a scatter gather operation to be performed.** A number of buffer descriptors are created from the specified memory and put* into a buffer descriptor list as empty buffer descriptors. This function must* be called before non-empty buffer descriptors may be put into the DMA channel* to request scatter gather operations.** @param** InstancePtr contains a pointer to the DMA channel to operate on.  The DMA* channel should be configured to use scatter gather in order for this function* to be called.** @param** MemoryPtr contains a pointer to the memory which is to be used for buffer* descriptors and must not be cached.** @param** ByteCount contains the number of bytes for the specified memory to be used* for buffer descriptors.** @return* - A status contains XST_SUCCESS if the scatter gather list was successfully*   created.*   <br><br>* - A value of XST_DMA_SG_LIST_EXISTS indicates that the scatter gather list*   was not created because the list has already been created.** @note** None.*******************************************************************************/XStatus XDmaChannel_CreateSgList(XDmaChannel *InstancePtr,                                 Xuint32 *MemoryPtr,                                 Xuint32 ByteCount){    XBufDescriptor *BufferDescriptorPtr = (XBufDescriptor *)MemoryPtr;    XBufDescriptor *PreviousDescriptorPtr = XNULL;    XBufDescriptor *StartOfListPtr = BufferDescriptorPtr;    Xuint32 UsedByteCount;    /* assert to verify valid input arguments, alignment for those     * arguments that have alignment restrictions, and at least enough     * memory for one buffer descriptor     */    XASSERT_NONVOID(InstancePtr != XNULL);    XASSERT_NONVOID(MemoryPtr != XNULL);    XASSERT_NONVOID(((Xuint32)MemoryPtr & 3) == 0);    XASSERT_NONVOID(ByteCount != 0);    XASSERT_NONVOID(ByteCount >= sizeof(XBufDescriptor));    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);    /* if the scatter gather list has already been created, then return     * with a status     */    if (InstancePtr->TotalDescriptorCount != 0)    {        return XST_DMA_SG_LIST_EXISTS;    }    /* loop thru the specified memory block and create as many buffer     * descriptors as possible putting each into the list which is     * implemented as a ring buffer, make sure not to use any memory which     * is not large enough for a complete buffer descriptor     */    UsedByteCount = 0;    while ((UsedByteCount + sizeof(XBufDescriptor)) <= ByteCount)    {        /* setup a pointer to the next buffer descriptor in the memory and         * update # of used bytes to know when all of memory is used         */        BufferDescriptorPtr = (XBufDescriptor *)((Xuint32)MemoryPtr +                                                 UsedByteCount);        /* initialize the new buffer descriptor such that it doesn't contain         * garbage which could be used by the DMA hardware         */        XBufDescriptor_Initialize(BufferDescriptorPtr);        /* if this is not the first buffer descriptor to be created,         * then link it to the last created buffer descriptor         */        if (PreviousDescriptorPtr != XNULL)        {            XBufDescriptor_SetNextPtr(PreviousDescriptorPtr,                                      BufferDescriptorPtr);        }        /* always keep a pointer to the last created buffer descriptor such         * that they can be linked together in the ring buffer         */        PreviousDescriptorPtr = BufferDescriptorPtr;        /* keep a count of the number of descriptors in the list to allow         * error processing to be performed         */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?