/** * Retrieve the number of free bytes in the packet FIFOs. * * For the transmit packet FIFO, the number returned is the number of bytes * that can be written by XTemac_FifoWrite(). If a non-zero number is returned, * then at least 1 packet of that size can be transmitted. * * For the receive packet FIFO, the number returned is the number of bytes that * can arrive from an external Ethernet device. This number does not reflect * the state of the receive length FIFO. If this FIFO is full, then arriving * packets will get dropped by the HW if there is no place to store the length. * * @param InstancePtr is a pointer to the instance to be worked on. * @param Direction selects which packet FIFO to examine. If XTE_SEND, then * the transmit packet FIFO is selected. If XTE_RECV, then the receive * packet FIFO is selected. * * @return * Number of bytes available in the selected packet FIFO. * ******************************************************************************/ u32 XTemac_FifoGetFreeBytes(XTemac * InstancePtr, u32 Direction) { u32 RegIPISR; u32 Count; XASSERT_NONVOID(InstancePtr != NULL); XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); XASSERT_NONVOID(!(Direction & ~(XTE_SEND | XTE_RECV))); /* For the send direction, even though there may be room in the * packet FIFO, the length FIFO may be full. When this is the case, * another packet cannot be transmiited so return 0. */ if (Direction == XTE_SEND) { /* Check length FIFO */ RegIPISR = XTemac_mGetIpifReg(XTE_IPISR_OFFSET); if (RegIPISR & XTE_IPXR_XMIT_LFIFO_FULL_MASK) { return (0); } /* Get FIFO entries */ Count = XPF_V200A_GET_COUNT(&InstancePtr->SendFifo.Fifo); } /* Handle receive direction */ else { Count = XPF_V200A_COUNT_MASK - XPF_V200A_GET_COUNT(&InstancePtr->RecvFifo.Fifo); } /* Multiply free entries by the width of the packet FIFO to arrive at * bytes */ return (Count * InstancePtr->RecvFifo.Width); }
/** * * 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. * ******************************************************************************/ int XEmac_FifoSend(XEmac * InstancePtr, u8 *BufPtr, u32 ByteCount) { int Result; volatile u32 StatusReg; XASSERT_NONVOID(InstancePtr != NULL); XASSERT_NONVOID(BufPtr != NULL); 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 = XEMAC_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 { u32 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(u32)) < 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, (u32 *) BufPtr, (u32 *) (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; }
/******************************************************************************* * Algorithm to read from a 64 bit wide receive packet FIFO with through the * holding buffer. * * @param Fptr is a pointer to a Temac FIFO instance to worked on. * @param BufPtr is the destination address on any alignment * @param ByteCount is the number of bytes to transfer * * @return XST_SUCCESS if transfer completed or XST_NO_DATA if the amount of * data being buffered by the driver plus the amount of data in the * packet FIFO is not enough to satisfy the number of bytes requested * by the ByteCount parameter. *******************************************************************************/ static XStatus Read_64(XTemac_PacketFifo * Fptr, void *BufPtr, u32 ByteCount, int Eop) { unsigned BufAlignment = (unsigned)BufPtr & 3; unsigned PartialBytes; unsigned MaxBytes; unsigned HoldAlignment = mHold_GetIndex(Fptr); /* Determine how many bytes can be read from the packet FIFO */ MaxBytes = XPF_V200A_COUNT_MASK & XPF_V200A_GET_COUNT(&Fptr->Fifo); MaxBytes *= PFIFO_64BIT_WIDTH_BYTES; /* Case 1: Buffer aligned on 4-byte boundary and Hold is empty * * 1. Read all bytes using the fastest transfer method */ if ((BufAlignment == 0) && (mHoldR_IsEmpty(Fptr))) { /* Enough data in fifo? */ if (ByteCount > MaxBytes) { return (XST_NO_DATA); } Read64_Aligned(Fptr, (u32 *) BufPtr, ByteCount); } /* Case 2: Buffer and Hold are byte aligned with each other * * 1. Transfer enough bytes from the Hold to the buffer to trigger a * read from the FIFO. * * 2. The state of the buffer and Hold are now as described by Case 1 so * read remaining bytes using the fastest transfer method */ else if (BufAlignment == (HoldAlignment % PFIFO_64BIT_WIDTH_BYTES)) { PartialBytes = PFIFO_64BIT_WIDTH_BYTES - HoldAlignment; if (ByteCount < PartialBytes) { PartialBytes = ByteCount; } /* Enough data in fifo? Must account for the number of bytes the driver * is currently buffering */ if (ByteCount > (MaxBytes + PartialBytes)) { return (XST_NO_DATA); } Read64_Unaligned(Fptr, BufPtr, PartialBytes); Read64_Aligned(Fptr, (u32 *) ((u32) BufPtr + PartialBytes), ByteCount - PartialBytes); } /* Case 3: No alignment to take advantage of * * 1. Read FIFOs using the slower method. */ else { /* Enough data in fifo? Must account for the number of bytes the driver * is currently buffering */ PartialBytes = PFIFO_64BIT_WIDTH_BYTES - HoldAlignment; if (ByteCount > (MaxBytes + PartialBytes)) { return (XST_NO_DATA); } Read64_Unaligned(Fptr, BufPtr, ByteCount); } /* If this marks the end of packet, then dump any remaining data in the * hold. The dumped data in this context is meaningless. */ if (Eop == XTE_END_OF_PACKET) { mHoldR_SetEmpty(Fptr); } return (XST_SUCCESS); }