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 + -
显示快捷键?