xemac_intr_dma.c

来自「适合KS8695X」· C语言 代码 · 共 1,345 行 · 第 1/4 页

C
1,345
字号
	case XEM_RECV:
		*WaitPtr =
		    XDmaChannel_GetPktWaitBound(&InstancePtr->RecvChannel);
		break;

	default:
		return XST_INVALID_PARAM;
	}

	return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* Give the driver the memory space to be used for the scatter-gather DMA
* receive descriptor list. This function should only be called once, during
* initialization of the Ethernet driver. The memory space must be big enough
* to hold some number of descriptors, depending on the needs of the system.
* The xemac.h file defines minimum and default numbers of descriptors
* which can be used to allocate this memory space.
*
* The memory space must be word-aligned. An assert will occur if asserts are
* turned on and the memory is not word-aligned.
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
* @param MemoryPtr is a pointer to the word-aligned memory.
* @param ByteCount is the length, in bytes, of the memory space.
*
* @return
*
* - XST_SUCCESS if the space was initialized successfully
* - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
* - XST_DMA_SG_LIST_EXISTS if this list space has already been created
*
* @note
*
* If the device is configured for scatter-gather DMA, this function must be
* called AFTER the XEmac_Initialize() function because the DMA channel
* components must be initialized before the memory space is set.
*
******************************************************************************/
XStatus
XEmac_SetSgRecvSpace(XEmac * InstancePtr, u32 * MemoryPtr, u32 ByteCount)
{
	XASSERT_NONVOID(InstancePtr != NULL);
	XASSERT_NONVOID(MemoryPtr != NULL);
	XASSERT_NONVOID(ByteCount != 0);
	XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

	if (!XEmac_mIsSgDma(InstancePtr)) {
		return XST_NOT_SGDMA;
	}

	return XDmaChannel_CreateSgList(&InstancePtr->RecvChannel, MemoryPtr,
					ByteCount);
}

/*****************************************************************************/
/**
*
* Give the driver the memory space to be used for the scatter-gather DMA
* transmit descriptor list. This function should only be called once, during
* initialization of the Ethernet driver. The memory space must be big enough
* to hold some number of descriptors, depending on the needs of the system.
* The xemac.h file defines minimum and default numbers of descriptors
* which can be used to allocate this memory space.
*
* The memory space must be word-aligned. An assert will occur if asserts are
* turned on and the memory is not word-aligned.
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
* @param MemoryPtr is a pointer to the word-aligned memory.
* @param ByteCount is the length, in bytes, of the memory space.
*
* @return
*
* - XST_SUCCESS if the space was initialized successfully
* - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
* - XST_DMA_SG_LIST_EXISTS if this list space has already been created
*
* @note
*
* If the device is configured for scatter-gather DMA, this function must be
* called AFTER the XEmac_Initialize() function because the DMA channel
* components must be initialized before the memory space is set.
*
******************************************************************************/
XStatus
XEmac_SetSgSendSpace(XEmac * InstancePtr, u32 * MemoryPtr, u32 ByteCount)
{
	XASSERT_NONVOID(InstancePtr != NULL);
	XASSERT_NONVOID(MemoryPtr != NULL);
	XASSERT_NONVOID(ByteCount != 0);
	XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

	if (!XEmac_mIsSgDma(InstancePtr)) {
		return XST_NOT_SGDMA;
	}

	return XDmaChannel_CreateSgList(&InstancePtr->SendChannel, MemoryPtr,
					ByteCount);
}

/*****************************************************************************/
/**
*
* Set the callback function for handling received frames in scatter-gather DMA
* mode.  The upper layer software should call this function during
* initialization.  The callback is called once per frame received. The head of
* a descriptor list is passed in along with the number of descriptors in the
* list. Before leaving the callback, the upper layer software should attach a
* new buffer to each descriptor in the list.
*
* The callback is invoked by the driver within interrupt context, so it needs
* to do its job quickly. Sending the received frame up the protocol stack
* should be done at task-level. If there are other potentially slow operations
* within the callback, these too should be done at task-level.
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
* @param CallBackRef is a reference pointer to be passed back to the adapter in
*        the callback. This helps the adapter correlate the callback to a
*        particular driver.
* @param FuncPtr is the pointer to the callback function.
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
void
XEmac_SetSgRecvHandler(XEmac * InstancePtr, void *CallBackRef,
		       XEmac_SgHandler FuncPtr)
{
	/*
	 * Asserted IsDmaSg here instead of run-time check because there is really
	 * no ill-effects of setting these when not configured for scatter-gather.
	 */
	XASSERT_VOID(InstancePtr != NULL);
	XASSERT_VOID(FuncPtr != NULL);
	XASSERT_VOID(XEmac_mIsSgDma(InstancePtr));
	XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

	InstancePtr->SgRecvHandler = FuncPtr;
	InstancePtr->SgRecvRef = CallBackRef;
}

/*****************************************************************************/
/**
*
* Set the callback function for handling confirmation of transmitted frames in
* scatter-gather DMA mode.  The upper layer software should call this function
* during initialization.  The callback is called once per frame sent. The head
* of a descriptor list is passed in along with the number of descriptors in
* the list. The callback is responsible for freeing buffers attached to these
* descriptors.
*
* The callback is invoked by the driver within interrupt context, so it needs
* to do its job quickly. If there are potentially slow operations within the
* callback, these should be done at task-level.
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
* @param CallBackRef is a reference pointer to be passed back to the adapter in
*        the callback. This helps the adapter correlate the callback to a
*        particular driver.
* @param FuncPtr is the pointer to the callback function.
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
void
XEmac_SetSgSendHandler(XEmac * InstancePtr, void *CallBackRef,
		       XEmac_SgHandler FuncPtr)
{
	/*
	 * Asserted IsDmaSg here instead of run-time check because there is really
	 * no ill-effects of setting these when not configured for scatter-gather.
	 */
	XASSERT_VOID(InstancePtr != NULL);
	XASSERT_VOID(FuncPtr != NULL);
	XASSERT_VOID(XEmac_mIsSgDma(InstancePtr));
	XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

	InstancePtr->SgSendHandler = FuncPtr;
	InstancePtr->SgSendRef = CallBackRef;
}

/*****************************************************************************/
/*
*
* Handle an interrupt from the DMA receive channel. DMA interrupts are:
*
* - DMA error. DMA encountered a bus error or timeout. This is a fatal error
*   that requires reset of the channel.  The driver calls the error handler
*   of the upper layer software with an error code indicating the device should
*   be reset.
* - Packet count threshold reached.  For scatter-gather operations, indicates
*   the threshold for the number of packets not serviced by software has been
*   reached. The driver behaves as follows:
*       - Get the value of the packet counter, which tells us how many packets
*         are ready to be serviced
*       - For each packet
*           - For each descriptor, remove it from the scatter-gather list
*           - Check for the last descriptor in the frame, and if set
*               - Bump frame statistics
*               - Call the scatter-gather receive callback function
*               - Decrement the packet counter by one
*       Note that there are no receive errors reported in the status word of
*       the buffer descriptor.  If receive errors occur, the MAC drops the
*       packet, and we only find out about the errors through various error
*       count registers.
* - Packet wait bound reached.  For scatter-gather, indicates the time to wait
*   for the next packet has expired.  The driver follows the same logic as when
*   the packet count threshold interrupt is received.
* - Scatter-gather end acknowledge.  Hardware has reached the end of the
*   descriptor list.  The driver follows the same logic as when the packet count
*   threshold interrupt is received. In addition, the driver restarts the DMA
*   scatter-gather channel in case there are newly inserted descriptors.
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
*
* @return
*
* Although the function returns void, there are asynchronous errors that can
* be generated (by calling the ErrorHandler) from this function.  These are:
* - XST_DMA_SG_LIST_EMPTY indicates we tried to get a buffer descriptor from the
*   DMA channel, but there was not one ready for software.
* - XST_DMA_ERROR indicates a DMA bus error or timeout occurred. This is a fatal
*   error that requires reset.
*
* @note
*
* None.
*
******************************************************************************/
static void
HandleDmaRecvIntr(XEmac * InstancePtr)
{
	u32 IntrStatus;

	/*
	 * Read the interrupt status
	 */
	IntrStatus = XDmaChannel_GetIntrStatus(&InstancePtr->RecvChannel);

	/*
	 * For packet threshold or wait bound interrupts, process desciptors. Also
	 * process descriptors on a SG end acknowledgement, which means the end of
	 * the descriptor list has been reached by the hardware. For receive, this
	 * is potentially trouble since it means the descriptor list is full,
	 * unless software can process enough packets quickly enough so the
	 * hardware has room to put new packets.
	 */
	if (IntrStatus & (XDC_IXR_PKT_THRESHOLD_MASK |
			  XDC_IXR_PKT_WAIT_BOUND_MASK | XDC_IXR_SG_END_MASK)) {
		XStatus Result = XST_SUCCESS;
		u32 NumFrames;
		u32 NumProcessed;
		u32 NumBuffers;
		u32 NumBytes;
		u32 IsLast;
		XBufDescriptor *FirstBdPtr;
		XBufDescriptor *BdPtr;

		/*
		 * Get the number of unserviced packets
		 */
		NumFrames = XDmaChannel_GetPktCount(&InstancePtr->RecvChannel);

		for (NumProcessed = 0; NumProcessed < NumFrames; NumProcessed++) {
			IsLast = FALSE;
			FirstBdPtr = NULL;
			NumBuffers = 0;
			NumBytes = 0;

			/*
			 * For each packet, get the descriptor from the list. On the
			 * last one in the frame, make the callback to the upper layer.
			 */
			while (!IsLast) {
				Result =
				    XDmaChannel_GetDescriptor(&InstancePtr->
							      RecvChannel,
							      &BdPtr);
				if (Result != XST_SUCCESS) {
					/*
					 * An error getting a buffer descriptor from the list.
					 * This should not happen, but if it does, report it to
					 * the error callback and break out of the loops to service
					 * other interrupts.
					 */
					InstancePtr->ErrorHandler(InstancePtr->
								  ErrorRef,
								  Result);
					break;
				}

				/*
				 * Keep a pointer to the first descriptor in the list, as it
				 * will be passed to the upper layers in a bit. By the fact
				 * that we received this packet means no errors occurred, so
				 * no need to check the device status word for errors.
				 */
				if (FirstBdPtr == NULL) {
					FirstBdPtr = BdPtr;
				}

				NumBytes += XBufDescriptor_GetLength(BdPtr);

				/*
				 * Check to see if this is the last descriptor in the frame,
				 * and if so, set the IsLast flag to get out of the loop.
				 */
				if (XBufDescriptor_IsLastStatus(BdPtr)) {
					IsLast = TRUE;
				}

				/*
				 * Bump the number of buffers in this packet
				 */
				NumBuffers++;

			}	/* end while loop */

			/*
			 * Check for error that occurred inside the while loop, and break
			 * out of the for loop if there was one so other interrupts can

⌨️ 快捷键说明

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