コード例 #1
0
/**
 * 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);
}
コード例 #2
0
/**
*
* 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;
}
コード例 #3
0
/*******************************************************************************
* 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);
}