📄 xemac_intr_fifo.c
字号:
/* $Id: xemac_intr_fifo.c,v 1.1 2005/10/26 15:44:52 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 Xilinx Inc.* All rights reserved.*******************************************************************************//*****************************************************************************//**** @file xemac_intr_fifo.c** Contains functions related to interrupt mode using direct FIFO I/O or simple* DMA. The driver uses simple DMA if the device is configured with DMA,* otherwise it uses direct FIFO access.** The interrupt handler, XEmac_IntrHandlerFifo(), must be connected by the user* to the interrupt controller.** <pre>* MODIFICATION HISTORY:** Ver Who Date Changes* ----- ---- -------- -----------------------------------------------* 1.00a rpm 07/31/01 First release* 1.00b rpm 02/20/02 Repartitioned files and functions* 1.00c rpm 12/05/02 New version includes support for simple DMA* 1.00c rpm 04/01/03 Added check in FifoSend for room in the data FIFO* before starting a simple DMA transfer.* 1.00d rpm 09/26/03 New version includes support PLB Ethernet and v2.00a of* the packet fifo driver.* </pre>*******************************************************************************//***************************** Include Files *********************************/#include "xbasic_types.h"#include "xemac_i.h"#include "xio.h"#include "xipif_v1_23_b.h" /* Uses v1.23b of the IPIF *//************************** Constant Definitions *****************************//**************************** Type Definitions *******************************//***************** Macros (Inline Functions) Definitions *********************//************************** Variable Definitions *****************************//************************** Function Prototypes ******************************/static void HandleEmacFifoIntr(XEmac *InstancePtr);/*****************************************************************************//**** Send an Ethernet frame using direct FIFO I/O or simple DMA with interrupts.* The caller provides a contiguous-memory buffer and its length. The buffer* must be 32-bit aligned. If using simple DMA and the PLB 10/100 Ethernet core,* the buffer must be 64-bit aligned. The callback function set by using* SetFifoSendHandler is invoked when the transmission is complete.** 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.** If the device is configured with DMA, simple DMA will be used to transfer* the buffer from memory to the Emac. This means that this buffer should not* be cached. See the comment section "Simple DMA" in xemac.h for more* information.** @param InstancePtr is a pointer to the XEmac instance to be worked on.* @param BufPtr is a pointer to a aligned buffer containing the Ethernet* frame to be sent.* @param ByteCount is the size of the Ethernet frame.** @return** - XST_SUCCESS if the frame was successfully sent. An interrupt is generated* when the EMAC transmits the frame and the driver calls the callback set* with XEmac_SetFifoSendHandler()* - XST_DEVICE_IS_STOPPED if the device has not yet been started* - XST_NOT_INTERRUPT if the device is not in interrupt mode* - XST_FIFO_NO_ROOM if there is no room in the FIFO for this frame* - XST_DEVICE_BUSY if configured for simple DMA and the DMA engine is busy* - XST_DMA_ERROR if an error occurred during the DMA transfer (simple DMA).* The user should treat this as a fatal error that requires a reset of the* EMAC device.** @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** The Ethernet MAC uses FIFOs behind its length and status registers. For this* reason, it is important to keep the length, status, and data FIFOs in sync* when reading or writing to them.*******************************************************************************/XStatus XEmac_FifoSend(XEmac *InstancePtr, Xuint8 *BufPtr, Xuint32 ByteCount){ XStatus Result; volatile Xuint32 StatusReg; XASSERT_NONVOID(InstancePtr != XNULL); XASSERT_NONVOID(BufPtr != XNULL); XASSERT_NONVOID(ByteCount > XEM_HDR_SIZE); /* send at least 1 byte */ XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); /* * Be sure the device is configured for interrupt mode and it is started */ if (InstancePtr->IsPolled) { return XST_NOT_INTERRUPT; } if (InstancePtr->IsStarted != XCOMPONENT_IS_STARTED) { return XST_DEVICE_IS_STOPPED; } /* * Before writing to the data FIFO, make sure the length FIFO is not * full. The data FIFO might not be full yet even though the length FIFO * is. This avoids an overrun condition on the length FIFO and keeps the * FIFOs in sync. */ StatusReg = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress); if (StatusReg & XEM_EIR_XMIT_LFIFO_FULL_MASK) { return XST_FIFO_NO_ROOM; } /* * Send either by directly writing to the FIFOs or using the DMA engine */ if (!XEmac_mIsDma(InstancePtr)) { /* * This is a non-blocking write. The packet FIFO returns an error if there * is not enough room in the FIFO for this frame. */ Result = XPacketFifoV200a_Write(&InstancePtr->SendFifo, BufPtr, ByteCount); if (Result != XST_SUCCESS) { return Result; } } else { Xuint32 Vacancy; /* * Need to make sure there is room in the data FIFO for the packet * before trying to DMA into it. Get the vacancy count (in words) * and make sure the packet will fit. */ Vacancy = XPF_V200A_GET_COUNT(&InstancePtr->SendFifo); if ((Vacancy * sizeof(Xuint32)) < ByteCount) { return XST_FIFO_NO_ROOM; } /* * Check the DMA engine to make sure it is not already busy */ if (XDmaChannel_GetStatus(&InstancePtr->SendChannel) & XDC_DMASR_BUSY_MASK) { return XST_DEVICE_BUSY; } /* * Set the DMA control register up properly */ XDmaChannel_SetControl(&InstancePtr->SendChannel, XDC_DMACR_SOURCE_INCR_MASK | XDC_DMACR_DEST_LOCAL_MASK | XDC_DMACR_SG_DISABLE_MASK); /* * Now transfer the data from the buffer to the FIFO */ XDmaChannel_Transfer(&InstancePtr->SendChannel, (Xuint32 *)BufPtr, (Xuint32 *)(InstancePtr->BaseAddress + XEM_PFIFO_TXDATA_OFFSET), ByteCount); /* * Poll here waiting for DMA to be not busy. We think this will * typically be a single read since DMA should be ahead of the SW. */ do { StatusReg = XDmaChannel_GetStatus(&InstancePtr->SendChannel); } while (StatusReg & XDC_DMASR_BUSY_MASK); /* Return an error if there was a problem with DMA */ if ((StatusReg & XDC_DMASR_BUS_ERROR_MASK) || (StatusReg & XDC_DMASR_BUS_TIMEOUT_MASK)) { InstancePtr->Stats.DmaErrors++; return XST_DMA_ERROR; } } /* * Set the MAC's transmit packet length register to tell it to transmit */ XIo_Out32(InstancePtr->BaseAddress + XEM_TPLR_OFFSET, ByteCount); /* * Bump stats here instead of the Isr since we know the byte count * here but would have to save it in the instance in order to know the * byte count at interrupt time. */ InstancePtr->Stats.XmitFrames++; InstancePtr->Stats.XmitBytes += ByteCount; return XST_SUCCESS;}/*****************************************************************************//**** Receive an Ethernet frame into the buffer passed as an argument. This* function is called in response to the callback function for received frames* being called by the driver. The callback function is set up using* SetFifoRecvHandler, and is invoked when the driver receives an interrupt* indicating a received frame. The driver expects the upper layer software to* call this function, FifoRecv, to receive the frame. The buffer supplied* should be large enough to hold a maximum-size Ethernet frame.** The buffer into which the frame will be received must be 32-bit aligned. If* using simple DMA and the PLB 10/100 Ethernet core, the buffer must be 64-bit* aligned.** If the device is configured with DMA, simple DMA will be used to transfer* the buffer from the Emac to memory. This means that this buffer should not* be cached. See the comment section "Simple DMA" in xemac.h for more* information.** @param InstancePtr is a pointer to the XEmac instance to be worked on.* @param BufPtr is a pointer to a aligned buffer into which the received* Ethernet frame will be copied.* @param ByteCountPtr is both an input and an output parameter. It is a pointer* to a 32-bit word that contains the size of the buffer on entry into* the function and the size the received frame on return from the* function.** @return** - XST_SUCCESS if the frame was sent successfully* - XST_DEVICE_IS_STOPPED if the device has not yet been started* - XST_NOT_INTERRUPT if the device is not in interrupt mode* - XST_NO_DATA if there is no frame to be received from the FIFO* - XST_BUFFER_TOO_SMALL if the buffer to receive the frame is too small for* the frame waiting in the FIFO.* - XST_DEVICE_BUSY if configured for simple DMA and the DMA engine is busy* - XST_DMA_ERROR if an error occurred during the DMA transfer (simple DMA).* The user should treat this as a fatal error that requires a reset of the* EMAC device.** @note** The input buffer must be big enough to hold the largest Ethernet frame.** @internal** The Ethernet MAC uses FIFOs behind its length and status registers. For this* reason, it is important to keep the length, status, and data FIFOs in sync* when reading or writing to them.*******************************************************************************/XStatus XEmac_FifoRecv(XEmac *InstancePtr, Xuint8 *BufPtr, Xuint32 *ByteCountPtr){ XStatus Result; Xuint32 PktLength; Xuint32 StatusReg; XASSERT_NONVOID(InstancePtr != XNULL); XASSERT_NONVOID(BufPtr != XNULL); XASSERT_NONVOID(ByteCountPtr != XNULL); XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); /* * Be sure the device is not configured for polled mode and it is started */ if (InstancePtr->IsPolled) { return XST_NOT_INTERRUPT; } if (InstancePtr->IsStarted != XCOMPONENT_IS_STARTED) { return XST_DEVICE_IS_STOPPED; } /* * Make sure the buffer is big enough to hold the maximum frame size. * We need to do this because as soon as we read the MAC's packet length * register, which is actually a FIFO, we remove that length from the * FIFO. We do not want to read the length FIFO without also reading the * data FIFO since this would get the FIFOs out of sync. So we have to * make this restriction. */ if (*ByteCountPtr < XEM_MAX_FRAME_SIZE) { return XST_BUFFER_TOO_SMALL; } /* * Before reading from the length FIFO, make sure the length FIFO is not * empty. We could cause an underrun error if we try to read from an * empty FIFO. */ StatusReg = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress); if (StatusReg & XEM_EIR_RECV_LFIFO_EMPTY_MASK) { /* * Clear the empty status so the next time through the current status
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -