Esempio n. 1
0
/**
*
* Add a descriptor, with an attached empty buffer, into the receive descriptor
* list. The buffer attached to the descriptor must be 32-bit aligned if using
* the OPB Ethernet core and 64-bit aligned if using the PLB Ethernet core.
* This function is used by the upper layer software during initialization when
* first setting up the receive descriptors, and also during reception of frames
* to replace filled buffers with empty buffers. This function can be called
* when the device is started or stopped. Note that it does start the scatter-
* gather DMA engine.  Although this is not necessary during initialization, it
* is not a problem during initialization because the MAC receiver is not yet
* started.
*
* The buffer attached to the descriptor must be aligned on both the front end
* and the back end.
*
* Notification of received frames are done asynchronously through the receive
* callback function.
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
* @param BdPtr is a pointer to the buffer descriptor that will be added to the
*        descriptor list.
*
* @return
*
* - XST_SUCCESS if a descriptor was successfully returned to the driver
* - XST_NOT_SGDMA if the device is not in scatter-gather DMA mode
* - XST_DMA_SG_LIST_FULL if the receive descriptor list is full
* - XST_DMA_SG_BD_LOCKED if the DMA channel cannot insert the descriptor into
*   the list because a locked descriptor exists at the insert point.
* - XST_DMA_SG_NOTHING_TO_COMMIT if even after inserting a descriptor into the
*   list, the DMA channel believes there are no new descriptors to commit.
*
* @internal
*
* A status that should never be returned from this function, although
* the code is set up to handle it, is XST_DMA_SG_NO_LIST. Starting the device
* requires a list to be created, and this function requires the device to be
* started.
*
******************************************************************************/
XStatus XEmac_SgRecv(XEmac * InstancePtr, XBufDescriptor * BdPtr)
{
	XStatus Result;
	u32 BdControl;

	XASSERT_NONVOID(InstancePtr != NULL);
	XASSERT_NONVOID(BdPtr != NULL);
	XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

	/*
	 * Be sure the device is configured for scatter-gather DMA
	 */
	if (!XEmac_mIsSgDma(InstancePtr)) {
		return XST_NOT_SGDMA;
	}

	/*
	 * Set some descriptor control word defaults (destination address increment
	 * and local source address) and the source address (the FIFO). These are
	 * the same for every receive descriptor.
	 */
	BdControl = XBufDescriptor_GetControl(BdPtr);
	XBufDescriptor_SetControl(BdPtr, BdControl | XEM_DFT_RECV_BD_MASK);
	XBufDescriptor_SetSrcAddress(BdPtr,
				     InstancePtr->PhysAddress +
				     XEM_PFIFO_RXDATA_OFFSET);

	/*
	 * Put the descriptor into the channel's descriptor list and commit.
	 * Although this function is likely called within interrupt context, there
	 * is the possibility that the upper layer software queues it to a task.
	 * In this case, a critical section is needed here to protect shared data
	 * in the DMA component.
	 */
	XIIF_V123B_GINTR_DISABLE(InstancePtr->BaseAddress);

	Result = XDmaChannel_PutDescriptor(&InstancePtr->RecvChannel, BdPtr);
	if (Result != XST_SUCCESS) {
		XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
		return Result;
	}

	Result = XDmaChannel_CommitPuts(&InstancePtr->RecvChannel);
	if (Result != XST_SUCCESS) {
		XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
		return Result;
	}

	/*
	 * Start the DMA channel. Ignore the return status since we know the list
	 * exists and has at least one entry and we don't care if the channel is
	 * already started. The DMA component accesses data here that can be
	 * modified at interrupt or task levels, so a critical section is required.
	 */
	(void)XDmaChannel_SgStart(&InstancePtr->RecvChannel);

	XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);

	return XST_SUCCESS;
}
/******************************************************************************
*
* FUNCTION:
*
* XDmaChannel_CommitPuts
*
* DESCRIPTION:
*
* This function commits the buffer descriptors which have been put into the
* scatter list for the DMA channel since the last commit operation was
* performed.  This enables the calling functions to put several buffer
* descriptors into the list (e.g.,a packet's worth) before allowing the scatter
* gather operations to start.  This prevents the DMA channel hardware from
* starting to use the buffer descriptors in the list before they are ready
* to be used (multiple buffer descriptors for a single packet).
*
* 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.
*
* RETURN VALUE:
*
* A status indicating XST_SUCCESS if the buffer descriptors of the list were
* successfully committed.
*
* A value of XST_DMA_SG_NOTHING_TO_COMMIT indicates that the buffer descriptors
* were not committed because there was nothing to commit in the list.  All the
* buffer descriptors which are in the list are commited.
*
* NOTES:
*
* None.
*
******************************************************************************/
XStatus
XDmaChannel_CommitPuts(XDmaChannel * InstancePtr)
{
	/* assert to verify input arguments */

	XASSERT_NONVOID(InstancePtr != NULL);
	XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

	/* if the buffer descriptor to be committed is already committed or
	 * the list is empty (none have been put in), then indicate an error
	 */
	if ((InstancePtr->CommitPtr == NULL) ||
	    XDmaChannel_IsSgListEmpty(InstancePtr)) {
		return XST_DMA_SG_NOTHING_TO_COMMIT;
	}

	/* last descriptor in the list must have scatter gather disabled so the end
	 * of the list is hit by h/w, if descriptor to commit is not last in list,
	 * commit descriptors by enabling scatter gather in the descriptor
	 */
	if (InstancePtr->CommitPtr != InstancePtr->LastPtr) {
		u32 Control;

		Control = XBufDescriptor_GetControl(InstancePtr->CommitPtr);
		XBufDescriptor_SetControl(InstancePtr->CommitPtr, Control &
					  ~XDC_DMACR_SG_DISABLE_MASK);
	}
	/* Update the commit pointer to indicate that there is nothing to be
	 * committed, this state is used by start processing to know that the
	 * buffer descriptor to start is not waiting to be committed
	 */
	InstancePtr->CommitPtr = NULL;

	return XST_SUCCESS;
}
/******************************************************************************
*
* FUNCTION:
*
* XDmaChannel_GetDescriptor
*
* DESCRIPTION:
*
* This function gets a buffer descriptor from the scatter gather list of the
* DMA channel. The buffer descriptor is retrieved from the scatter gather list
* and the scatter gather list is updated to not include the retrieved buffer
* descriptor.  This is typically done after a scatter gather operation
* completes indicating that a data buffer has been successfully sent or data
* has been received into the data buffer. The purpose of this function is to
* allow the device using the scatter gather operation to get the results of the
* operation.
*
* 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 a pointer to a pointer to the buffer descriptor which
* was retrieved from the list.	The buffer descriptor is not really removed
* from the list, but it is changed to a state such that the hardware will not
* use it again until it is put into the scatter gather list of the DMA channel.
*
* RETURN VALUE:
*
* A status indicating XST_SUCCESS if a buffer descriptor was retrieved from
* the scatter gather list of the DMA channel.
*
* A value of XST_DMA_SG_NO_LIST indicates the scatter gather list has not
* been created.
*
* A value of XST_DMA_SG_LIST_EMPTY indicates no buffer descriptor was
* retrieved from the list because there are no buffer descriptors to be
* processed in the list.
*
* BufDescriptorPtr is updated to point to the buffer descriptor which was
* retrieved from the list if the status indicates success.
*
* NOTES:
*
* None.
*
******************************************************************************/
XStatus
XDmaChannel_GetDescriptor(XDmaChannel * InstancePtr,
			  XBufDescriptor ** BufDescriptorPtr)
{
	u32 Control;

	/* assert to verify input arguments */

	XASSERT_NONVOID(InstancePtr != NULL);
	XASSERT_NONVOID(BufDescriptorPtr != 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 buffer descriptor list is empty, then indicate an error */

	if (XDmaChannel_IsSgListEmpty(InstancePtr)) {
		return XST_DMA_SG_LIST_EMPTY;
	}

	/* retrieve the next buffer descriptor which is ready to be processed from
	 * the buffer descriptor list for the DMA channel, set the control word
	 * such that hardware will stop after the descriptor has been processed
	 */
	Control = XBufDescriptor_GetControl(InstancePtr->GetPtr);
	XBufDescriptor_SetControl(InstancePtr->GetPtr,
				  Control | XDC_DMACR_SG_DISABLE_MASK);

	/* set the input argument, which is also an output, to point to the
	 * buffer descriptor which is to be retrieved from the list
	 */
	*BufDescriptorPtr = InstancePtr->GetPtr;

	/* update the pointer of the DMA channel to reflect the buffer descriptor
	 * was retrieved from the list by setting it to the next buffer descriptor
	 * in the list and indicate one less descriptor in the list now
	 */
	InstancePtr->GetPtr = XBufDescriptor_GetNextPtr(InstancePtr->GetPtr);
	InstancePtr->ActiveDescriptorCount--;

	return XST_SUCCESS;
}
Esempio n. 4
0
/**
*
* Send an Ethernet frame using scatter-gather DMA. The caller attaches the
* frame to one or more buffer descriptors, then calls this function once for
* each descriptor. The caller is responsible for allocating and setting up the
* descriptor. An entire Ethernet frame may or may not be contained within one
* descriptor.  This function simply inserts the descriptor into the scatter-
* gather engine's transmit list. The caller is responsible for providing mutual
* exclusion to guarantee that a frame is contiguous in the transmit list. The
* buffer attached to the descriptor must be 32-bit aligned if using the OPB
* Ethernet core and 64-bit aligned if using the PLB Ethernet core.
*
* The driver updates the descriptor with the device control register before
* being inserted into the transmit list.  If this is the last descriptor in
* the frame, the inserts are committed, which means the descriptors for this
* frame are now available for transmission.
*
* It is assumed that the upper layer software supplies a correctly formatted
* Ethernet frame, including the destination and source addresses, the
* type/length field, and the data field.  It is also assumed that upper layer
* software does not append FCS at the end of the frame.
*
* This call is non-blocking.  Notification of error or successful transmission
* is done asynchronously through the send or error callback function.
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
* @param BdPtr is the address of a descriptor to be inserted into the transmit
*        ring.
* @param Delay indicates whether to start the scatter-gather DMA channel
*        immediately, or whether to wait. This allows the user to build up a
*        list of more than one descriptor before starting the transmission of
*        the packets, which allows the application to keep up with DMA and have
*        a constant stream of frames being transmitted. Use XEM_SGDMA_NODELAY or
*        XEM_SGDMA_DELAY, defined in xemac.h, as the value of this argument. If
*        the user chooses to delay and build a list, the user must call this
*        function with the XEM_SGDMA_NODELAY option or call XEmac_Start() to
*        kick off the tranmissions.
*
* @return
*
* - XST_SUCCESS if the buffer was successfull sent
* - XST_DEVICE_IS_STOPPED if the Ethernet MAC has not been started yet
* - XST_NOT_SGDMA if the device is not in scatter-gather DMA mode
* - XST_DMA_SG_LIST_FULL if the descriptor list for the DMA channel is full
* - XST_DMA_SG_BD_LOCKED if the DMA channel cannot insert the descriptor into
*   the list because a locked descriptor exists at the insert point
* - XST_DMA_SG_NOTHING_TO_COMMIT if even after inserting a descriptor into the
*   list, the DMA channel believes there are no new descriptors to commit. If
*   this is ever encountered, there is likely a thread mutual exclusion problem
*   on transmit.
*
* @note
*
* This function is not thread-safe. The user must provide mutually exclusive
* access to this function if there are to be multiple threads that can call it.
*
* @internal
*
* A status that should never be returned from this function, although
* the code is set up to handle it, is XST_DMA_SG_NO_LIST. Starting the device
* requires a list to be created, and this function requires the device to be
* started.
*
******************************************************************************/
XStatus XEmac_SgSend(XEmac * InstancePtr, XBufDescriptor * BdPtr, int Delay)
{
	XStatus Result;
	u32 BdControl;

	XASSERT_NONVOID(InstancePtr != NULL);
	XASSERT_NONVOID(BdPtr != NULL);
	XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

	/*
	 * Be sure the device is configured for scatter-gather DMA, then be sure
	 * it is started.
	 */
	if (!XEmac_mIsSgDma(InstancePtr)) {
		return XST_NOT_SGDMA;
	}

	/*
	 * Set some descriptor control word defaults (source address increment
	 * and local destination address) and the destination address
	 * (the FIFO).  These are the same for every transmit descriptor.
	 */
	BdControl = XBufDescriptor_GetControl(BdPtr);
	XBufDescriptor_SetControl(BdPtr, BdControl | XEM_DFT_SEND_BD_MASK);

	XBufDescriptor_SetDestAddress(BdPtr,
				      InstancePtr->PhysAddress +
				      XEM_PFIFO_TXDATA_OFFSET);

	/*
	 * Put the descriptor in the send list. The DMA component accesses data
	 * here that can also be modified in interrupt context, so a critical
	 * section is required.
	 */
	XIIF_V123B_GINTR_DISABLE(InstancePtr->BaseAddress);

	Result = XDmaChannel_PutDescriptor(&InstancePtr->SendChannel, BdPtr);
	if (Result != XST_SUCCESS) {
		XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
		return Result;
	}

	/*
	 * If this is the last buffer in the frame, commit the inserts and start
	 * the DMA engine if necessary
	 */
	if (XBufDescriptor_IsLastControl(BdPtr)) {
		Result = XDmaChannel_CommitPuts(&InstancePtr->SendChannel);
		if (Result != XST_SUCCESS) {
			XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
			return Result;
		}

		if (Delay == XEM_SGDMA_NODELAY) {
			/*
			 * Start the DMA channel. Ignore the return status since we know the
			 * list exists and has at least one entry and we don't care if the
			 * channel is already started.  The DMA component accesses data here
			 * that can be modified at interrupt or task levels, so a critical
			 * section is required.
			 */
			(void)XDmaChannel_SgStart(&InstancePtr->SendChannel);
		}
	}

	XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);

	return XST_SUCCESS;
}
/******************************************************************************
*
* FUNCTION:
*
* XDmaChannel_PutDescriptor
*
* DESCRIPTION:
*
* This function puts a buffer descriptor into the DMA channel scatter
* gather list. A DMA channel maintains a list of buffer descriptors which are
* to be processed.  This function puts the specified buffer descriptor
* at the next location in the list.  Note that since the list is already intact,
* the information in the parameter is copied into the list (rather than modify
* list pointers on the fly).
*
* After buffer descriptors are put into the list, they must also be committed
* by calling another function.	This allows multiple buffer descriptors which
* span a single packet to be put into the list while preventing the hardware
* from starting the first buffer descriptor of the packet.
*
* 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.
*
* BufferDescriptorPtr is a pointer to the buffer descriptor to be put into
* the next available location of the scatter gather list.
*
* RETURN VALUE:
*
* A status which indicates XST_SUCCESS if the buffer descriptor was
* successfully put into the scatter gather list.
*
* A value of XST_DMA_SG_NO_LIST indicates the scatter gather list has not
* been created.
*
* A value of XST_DMA_SG_LIST_FULL indicates the buffer descriptor was not
* put into the list because the list was full.
*
* A value of XST_DMA_SG_BD_LOCKED indicates the buffer descriptor was not
* put into the list because the buffer descriptor in the list which is to
* be overwritten was locked.  A locked buffer descriptor indicates the higher
* layered software is still using the buffer descriptor.
*
* NOTES:
*
* It is necessary to create a scatter gather list for a DMA channel before
* putting buffer descriptors into it.
*
******************************************************************************/
XStatus
XDmaChannel_PutDescriptor(XDmaChannel * InstancePtr,
			  XBufDescriptor * BufferDescriptorPtr)
{
	u32 Control;

	/* assert to verify valid input arguments and alignment for those
	 * arguments that have alignment restrictions
	 */
	XASSERT_NONVOID(InstancePtr != NULL);
	XASSERT_NONVOID(BufferDescriptorPtr != NULL);
	XASSERT_NONVOID(((u32) BufferDescriptorPtr & 3) == 0);
	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 list is full because all descriptors are pointing to valid
	 * buffers, then indicate an error, this code assumes no list or an
	 * empty list is detected above
	 */
	if (InstancePtr->ActiveDescriptorCount ==
	    InstancePtr->TotalDescriptorCount) {
		return XST_DMA_SG_LIST_FULL;
	}

	/* if the buffer descriptor in the list which is to be overwritten is
	 * locked, then don't overwrite it and return a status
	 */
	if (XBufDescriptor_IsLocked(InstancePtr->PutPtr)) {
		return XST_DMA_SG_BD_LOCKED;
	}

	/* set the scatter gather stop bit in the control word of the descriptor
	 * to cause the h/w to stop after it processes this descriptor since it
	 * will be the last in the list
	 */
	Control = XBufDescriptor_GetControl(BufferDescriptorPtr);
	XBufDescriptor_SetControl(BufferDescriptorPtr,
				  Control | XDC_DMACR_SG_DISABLE_MASK);

	/* set both statuses in the descriptor so we tell if they are updated with
	 * the status of the transfer, the hardware should change the busy in the
	 * DMA status to be false when it completes
	 */
	XBufDescriptor_SetStatus(BufferDescriptorPtr, XDC_DMASR_BUSY_MASK);
	XBufDescriptor_SetDeviceStatus(BufferDescriptorPtr, 0);

	/* copy the descriptor into the next position in the list so it's ready to
	 * be used by the h/w, this assumes the descriptor in the list prior to this
	 * one still has the stop bit in the control word set such that the h/w
	 * use this one yet
	 */
	CopyBufferDescriptor(BufferDescriptorPtr, InstancePtr->PutPtr);

	/* only the last in the list and the one to be committed have scatter gather
	 * disabled in the control word, a commit requires only one descriptor
	 * to be changed, when # of descriptors to commit > 2 all others except the
	 * 1st and last have scatter gather enabled
	 */
	if ((InstancePtr->CommitPtr != InstancePtr->LastPtr) &&
	    (InstancePtr->CommitPtr != NULL)) {
		Control = XBufDescriptor_GetControl(InstancePtr->LastPtr);
		XBufDescriptor_SetControl(InstancePtr->LastPtr,
					  Control & ~XDC_DMACR_SG_DISABLE_MASK);
	}

	/* update the list data based upon putting a descriptor into the list,
	 * these operations must be last
	 */
	InstancePtr->ActiveDescriptorCount++;

	/* only update the commit pointer if it is not already active, this allows
	 * it to be deactivated after every commit such that a single descriptor
	 * which is committed does not appear to be waiting to be committed
	 */
	if (InstancePtr->CommitPtr == NULL) {
		InstancePtr->CommitPtr = InstancePtr->LastPtr;
	}

	/* these updates MUST BE LAST after the commit pointer update in order for
	 * the commit pointer to track the correct descriptor to be committed
	 */
	InstancePtr->LastPtr = InstancePtr->PutPtr;
	InstancePtr->PutPtr = XBufDescriptor_GetNextPtr(InstancePtr->PutPtr);

	return XST_SUCCESS;
}