📄 xdma_multi_sg.c
字号:
/* $Id: xdma_multi_sg.c,v 1.1 2005/11/28 19:08:13 meinelte Exp $ *//******************************************************************************** XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND* SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,* OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,* APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION* THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS* FOR A PARTICULAR PURPOSE.** (c) Copyright 2003-2004 Xilinx Inc.* All rights reserved.*******************************************************************************//*****************************************************************************//**** @file xdma_multi_sg.c** <b>Description</b>** This file contains the implementation of the XDmaMulti component which is* related to scatter gather operations.** <b>Scatter Gather Operations</b>** The multichannel DMA may support scatter gather operations. A scatter* gather operation automates the DMA transfer such that multiple buffers can* be sent or received with minimal software interaction with the hardware.* Buffer descriptors, contained in the XBufDescriptor component, are used by* the scatter gather operations of the DMA to describe the buffers to* be processed.** <b>Scatter Gather List Operations</b>** A scatter gather list may be supported by each DMA channel. The scatter* gather list allows buffer descriptors to be put into the list by a device* driver which requires scatter gather. The hardware processes the buffer* descriptors which are contained in the list and modifies the buffer* descriptors to reflect the status of the DMA operations. The device driver* is notified by interrupt that specific DMA events occur including scatter* gather events. The device driver removes the completed buffer descriptors* from the scatter gather list to evaluate the status of each DMA operation.** The scatter gather list is created and buffer descriptors are inserted into* the list. Buffer descriptors are never removed from the list after it's* creation such that a put operation copies from a temporary buffer descriptor* to a buffer descriptor in the list. Get operations don't copy from the list* to a temporary, but return a pointer to the buffer descriptor in the list.* A buffer descriptor in the list may be locked to prevent it from being* overwritten by a put operation. This allows the device driver to get a* descriptor from a scatter gather list and prevent it from being overwritten* until the buffer associated with the buffer descriptor has been processed.** The get and put functions only operate on the list and are asynchronous from* the hardware which may be using the list of descriptors. This is important* because there are no checks in the get and put functions to ensure that the* hardware has processed the descriptors. This must be handled by the driver* using the DMA scatter gather channel through the use of the other functions.* When a scatter gather operation is started, the start function does ensure* that the descriptor to start has not already been processed by the hardware* and is not the first of a series of descriptors that have not been committed* yet.** Descriptors are put into the list but not marked as ready to use by the* hardware until a commit operation is done. This allows multiple descriptors* which may contain a single packet of information for a protocol to be* guaranteed not to cause any underflow conditions during transmission. The* hardware design only allows descriptors to cause it to stop after a descriptor* has been processed rather than before it is processed. A series of* descriptors are put into the list followed by a commit operation, or each* descriptor may be committed. A commit operation is performed by changing a* single descriptor, the first of the series of puts, to indicate that the* hardware may now use all descriptors after it. The last descriptor in the* list is always set to cause the hardware to stop after it is processed.** <b>Typical Scatter Gather Processing</b>** The following steps illustrate the typical processing to use the* scatter gather features of the multichannel DMA.** 1. Create a scatter gather list for the each channel of DMA which puts empty* buffer descriptors into the list.<br>* 2. Create buffer descriptors which describe the buffers to be filled with* receive data or the buffers which contain data to be sent.<br>* 3. Put buffer descriptors into the scatter list such that scatter* gather operations are requested.<br>* 4. Commit the buffer descriptors in the list such that they are ready to be* used by the DMA hardware.<br>* 5. Start the scatter gather operations of the DMA channel.<br>* 6. Process any interrupts which occur as a result of the scatter gather* operations or poll the DMA channel to determine the status. This may* be accomplished by getting the packet count for the channel and then* getting the appropriate number of descriptors from the list for that* number of packets.** <b>Minimizing Interrupts</b>** The Scatter Gather operating mode is designed to reduce the amount of CPU* throughput necessary to manage the hardware for devices. A key to the CPU* throughput is the number and rate of interrupts that the CPU must service.* Devices with higher data rates can cause larger numbers of interrupts and* higher frequency interrupts. Ideally the number of interrupts can be reduced* by only generating an interrupt when a specific amount of data has been* received from the interface. This design suffers from a lack of interrupts* when the amount of data received is less than the specified amount of data* to generate an interrupt. In order to help minimize the number of interrupts* which the CPU must service, an algorithm referred to as "interrupt coalescing"* is utilized. In the case of the multichannel DMA, each channel of DMA is* independent and the interrupts from each channel can have independent* Packet Wait and Packet Count values allowing for traffic specific values* for each channel.** <b>Interrupt Coalescing</b>** The principle of interrupt coalescing is to wait before generating an* interrupt until a certain number of packets have been received or sent. An* interrupt is also generated if a smaller number of packets have been received* followed by a certain period of time with no packet reception. This is a* trade-off of latency for bandwidth and is accomplished using several* mechanisms of the hardware including a counter for packets received or* transmitted and a packet timer. These two hardware mechanisms work in* combination to allow a reduction in the number of interrupts processed by the* CPU for packet reception.** <b>Unserviced Packet Count</b>** The purpose of the packet counter is to count the number of packets received* or transmitted and provide an interrupt when a specific number of packets* have been processed by the hardware. An interrupt is generated whenever the* counter is greater than or equal to the Packet Count Threshold. This counter* contains an accurate count of the number of packets that the hardware has* processed, either received or transmitted, and the software has not serviced.** The packet counter allows the number of interrupts to be reduced by waiting* to generate an interrupt until enough packets are received. For packet* reception, packet counts of less than the number to generate an interrupt* would not be serviced without the addition of a packet timer. This counter is* continuously updated by the hardware, not latched to the value at the time* the interrupt occurred.** The packet counter can be used within the interrupt service routine for the* device to reduce the number of interrupts. The interrupt service routine* loops while performing processing for each packet which has been received or* transmitted and decrements the counter by a specified value. At the same time,* the hardware is possibly continuing to receive or transmit more packets such* that the software may choose, based upon the value in the packet counter, to* remain in the interrupt service routine rather than exiting and immediately* returning. This feature should be used with caution as reducing the number of* interrupts is beneficial, but unbounded interrupt processing is not desirable.** Since the hardware may be incrementing the packet counter simultaneously* with the software decrementing the counter, there is a need for atomic* operations. The hardware ensures that the operation is atomic such that* simultaneous accesses are properly handled.** <b>Packet Wait Bound</b>** The purpose of the packet wait bound is to augment the unserviced packet* count. Whenever there is no pending interrupt for the channel and the* unserviced packet count is non-zero, a timer starts counting timeout at the* value contained the packet wait bound register. If the timeout is* reached, an interrupt is generated such that the software may service the* data which was buffered.** <b>Asserts</b>** Asserts are used within all Xilinx drivers to enforce constraints on argument* values. Asserts can be turned off on a system-wide basis by defining, at compile* time, the NDEBUG identifier. By default, asserts are turned on and it is* recommended that application developers leave asserts on during development.** <b>Special Test Conditions</b>** The Put Pointer points to the next location in the descriptor list to copy* in a new descriptor. The Get Pointer points to the next location in the* list to get a descriptor from. The Get Pointer only allows software to* have a traverse the list after the hardware has finished processing some* number of descriptors. The Commit Pointer points to the descriptor in the* list which is to be committed. It is also used to determine that no* descriptor is waiting to be committed (NULL). The Last Pointer points to* the last descriptor that was put into the list. It typically points* to the previous descriptor to the one pointed to by the Put Pointer.* Comparisons are done between these pointers to determine when the following* special conditions exist.** <b>Single Put And Commit</b>** The buffer descriptor is ready to be used by the hardware so it is important* for the descriptor to not appear to be waiting to be committed. The commit* pointer is reset when a commit is done indicating there are no descriptors* waiting to be committed. In all cases but this one, the descriptor is* changed to cause the hardware to go to the next descriptor after processing* this one. But in this case, this is the last descriptor in the list such* that it must not be changed.** <b>3 Or More Puts And Commit</b>** A series of 3 or more puts followed by a single commit is different in that* only the 1st descriptor put into the list is changed when the commit is done.* This requires each put starting on the 3rd to change the previous descriptor* so that it allows the hardware to continue to the next descriptor in the list.** <b>The 1st Put Following A Commit</b>** The commit caused the commit pointer to be NULL indicating that there are no* descriptors waiting to be committed. It is necessary for the next put to set* the commit pointer so that a commit must follow the put for the hardware to* use the descriptor.** <pre>* MODIFICATION HISTORY:** Ver Who Date Changes* ----- ---- -------- -----------------------------------------------* 1.00a ecm 09/16/03 First release* 1.00a xd 10/27/04 Doxygenated for inclusion in API documentation* 1.00b ecm 10/31/05 Updated for the check sum offload changes.* </pre>*******************************************************************************//***************************** Include Files *********************************/#include "xdma_multi.h"#include "xbasic_types.h"#include "xio.h"#include "xbuf_descriptor.h"#include "xstatus.h"/************************** Constant Definitions *****************************//**************************** Type Definitions *******************************//***************** Macros (Inline Functions) Definitions *********************//** * The following macro copies selected fields of a buffer descriptor to another * buffer descriptor, this was provided by the buffer descriptor component but * was moved here since it is only used internally to this component and since * it does not copy all fields. */#define CopyBufferDescriptor(InstancePtr, DestinationPtr) \{ \ *((Xuint32 *)DestinationPtr + XBD_CONTROL_OFFSET) = \ *((Xuint32 *)InstancePtr + XBD_CONTROL_OFFSET); \ *((Xuint32 *)DestinationPtr + XBD_SOURCE_OFFSET) = \ *((Xuint32 *)InstancePtr + XBD_SOURCE_OFFSET); \ *((Xuint32 *)DestinationPtr + XBD_DESTINATION_OFFSET) = \ *((Xuint32 *)InstancePtr + XBD_DESTINATION_OFFSET); \ *((Xuint32 *)DestinationPtr + XBD_LENGTH_OFFSET) = \ *((Xuint32 *)InstancePtr + XBD_LENGTH_OFFSET); \ *((Xuint32 *)DestinationPtr + XBD_STATUS_OFFSET) = \ *((Xuint32 *)InstancePtr + XBD_STATUS_OFFSET); \ *((Xuint32 *)DestinationPtr + XBD_DEVICE_STATUS_OFFSET) = \ *((Xuint32 *)InstancePtr + XBD_DEVICE_STATUS_OFFSET); \ *((Xuint32 *)DestinationPtr + XBD_ID_OFFSET) = \ *((Xuint32 *)InstancePtr + XBD_ID_OFFSET); \ *((Xuint32 *)DestinationPtr + XBD_FLAGS_OFFSET) = \ *((Xuint32 *)InstancePtr + XBD_FLAGS_OFFSET); \ *((Xuint32 *)DestinationPtr + XBD_RQSTED_LENGTH_OFFSET) = \ *((Xuint32 *)InstancePtr + XBD_RQSTED_LENGTH_OFFSET); \}/************************** Variable Definitions *****************************//************************** Function Prototypes ******************************//*****************************************************************************//**** This function starts a scatter gather operation for a scatter gather* DMA channel. The first buffer descriptor in the buffer descriptor list* will be started with the scatter gather operation. A scatter gather list* should have previously been created for the channel of DMA and buffer* descriptors put into the scatter gather list such that there are scatter* operations ready to be performed.** @param InstancePtr contains a pointer to the multichannel DMA to operate on.* The DMA channel should be configured to use scatter gather in order* for this function to be called.** @param Channel is the particular channel of interest.** @return* - XST_SUCCESS if scatter gather was started successfully* <br><br>* - XST_DMA_SG_NO_LIST indicates the scatter gather list has not* been created.* <br><br>* - XST_DMA_SG_LIST_EMPTY indicates scatter gather was not started* because the scatter gather list of the DMA channel does not contain any* buffer descriptors that are ready to be processed by the hardware.* <br><br>* - XST_DMA_SG_IS_STARTED indicates scatter gather was not started* because the scatter gather was not stopped, but was already started.* <br><br>* - XST_DMA_SG_BD_NOT_COMMITTED indicates the buffer descriptor of* scatter gather list which was to be started is not committed to the list.* This status is more likely if this function is being called from an ISR* and non-ISR processing is putting descriptors into the list.* <br><br>* - 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 XDmaMulti_SgStart(XDmaMulti *InstancePtr, unsigned Channel){ Xuint32 Register; Xuint32 DMACRegister; XBufDescriptor *LastDescriptorPtr; /* Assert to verify input arguments. */ XASSERT_NONVOID(InstancePtr != XNULL); XASSERT_NONVOID(InstancePtr->ChannelCount > Channel); XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); /* If a scatter gather list has not been created yet, return a status. */ if (CHANNEL_DATA.TotalDescriptorCount == 0) { return XST_DMA_SG_NO_LIST; } /* If the scatter gather list exists but is empty then return a status. */ if (XDmaMulti_IsSgListEmpty(InstancePtr, Channel) == XTRUE) { return XST_DMA_SG_LIST_EMPTY; } /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -