📄 xdma_channel_sg.c
字号:
* scatter gather list which was to be started had already been used by the* hardware for a DMA transfer that has been completed.** NOTES:** 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.*******************************************************************************/XStatusXDmaChannel_SgStart(XDmaChannel * InstancePtr){ u32 Register; XBufDescriptor *LastDescriptorPtr; /* assert to verify input arguments */ XASSERT_NONVOID(InstancePtr != NULL); 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 == NULL) { XIo_Out32(InstancePtr->RegBaseAddress + XDC_BDA_REG_OFFSET, (u32) InstancePtr->GetPtr); } else { XBufDescriptor *NextDescriptorPtr; /* get the next descriptor to be started, if the status indicates it * hasn't already been used by the h/w, then it's OK to start it, * s/w sets the status of each descriptor to busy and then h/w 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 h/w is to be committed by the s/w, 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 s/w 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;}/******************************************************************************** FUNCTION:** XDmaChannel_SgStop** DESCRIPTION:** 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.** ARGUMENTS:** 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.** 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 VALUE:** A status containing XST_SUCCESS if scatter gather was stopped successfully* for the DMA channel.** A value of XST_DMA_SG_IS_STOPPED indicates scatter gather was not stoppped* because the scatter gather is not started, but was already stopped.** BufDescriptorPtr contains a pointer to the buffer descriptor which was* completed when the operation was stopped.** NOTES:** 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.*******************************************************************************/XStatusXDmaChannel_SgStop(XDmaChannel * InstancePtr, XBufDescriptor ** BufDescriptorPtr){ u32 Register; /* assert to verify input arguments */ XASSERT_NONVOID(InstancePtr != NULL); XASSERT_NONVOID(BufDescriptorPtr != NULL); 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; } /* Ensure the interrupt status for the scatter gather is cleared such * that this function will wait til the disable has occurred, writing * a 1 to only that bit in the register will clear only it */ XIo_Out32(InstancePtr->RegBaseAddress + XDC_IS_REG_OFFSET, XDC_IXR_SG_DISABLE_ACK_MASK); /* 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_IS_REG_OFFSET); } while ((Register & XDC_IXR_SG_DISABLE_ACK_MASK) == 0); /* Ensure the interrupt status for the scatter gather disable is cleared, * writing a 1 to only that bit in the register will clear only it */ XIo_Out32(InstancePtr->RegBaseAddress + XDC_IS_REG_OFFSET, XDC_IXR_SG_DISABLE_ACK_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;}/******************************************************************************** FUNCTION:** XDmaChannel_CreateSgList** DESCRIPTION:** 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.** ARGUMENTS:** 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.** MemoryPtr contains a pointer to the memory which is to be used for buffer* descriptors and must not be cached.** ByteCount contains the number of bytes for the specified memory to be used* for buffer descriptors.** RETURN VALUE:** A status contains XST_SUCCESS if the scatter gather list was successfully* created.** A value of XST_DMA_SG_LIST_EXISTS indicates that the scatter gather list* was not created because the list has already been created.** NOTES:** None.*******************************************************************************/XStatusXDmaChannel_CreateSgList(XDmaChannel * InstancePtr, u32 * MemoryPtr, u32 ByteCount){ XBufDescriptor *BufferDescriptorPtr = (XBufDescriptor *) MemoryPtr; XBufDescriptor *PreviousDescriptorPtr = NULL; XBufDescriptor *StartOfListPtr = BufferDescriptorPtr; u32 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 != NULL); XASSERT_NONVOID(MemoryPtr != NULL); XASSERT_NONVOID(((u32) 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 *) ((u32) 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 != NULL) { 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 */ InstancePtr->TotalDescriptorCount++; UsedByteCount += sizeof (XBufDescriptor); } /* connect the last buffer descriptor created and inserted in the list * to the first such that a ring buffer is created */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -