/**
* This function resets the device but preserves the options set by the user.
*
* The descriptor list could be reinitialized with the same calls to
* XLlTemac_SgSetSpace() as used in main(). Doing this is a matter of preference.
* In many cases, an OS may have resources tied up in the descriptors.
* Reinitializing in this case may bad for the OS since its resources may be
* permamently lost.
*
* @param    TemacInstancePtr is a pointer to the instance of the Temac
*           component.
*
* @return   XST_SUCCESS if successful, else XST_FAILURE.
*
* @note     None.
*
******************************************************************************/
static int TemacResetDevice(XLlTemac * TemacInstancePtr,
				XLlDma * DmaInstancePtr)
{
	int Status;
	u8 MacSave[6];
	u32 Options;
	//u32 RxThreshold = 1;
	//u32 TxThreshold = 1;
	//u32 RxWaitbound = 0;
	//u32 TxWaitbound = 0;
	//XLlDma_BdRing * RxRingPtr = &XLlDma_GetRxRing(DmaInstancePtr);
	//XLlDma_BdRing * TxRingPtr = &XLlDma_GetTxRing(DmaInstancePtr);

	/*
	 * Stop LLTEMAC device
	 */
	XLlTemac_Stop(TemacInstancePtr);

	/*
	 * Save the device state
	 */
	XLlTemac_GetMacAddress(TemacInstancePtr, MacSave);
	Options = XLlTemac_GetOptions(TemacInstancePtr);

	/*
	 * Stop and reset the device
	 */
	XLlTemac_Reset(TemacInstancePtr, XTE_NORESET_HARD);

	/*
	 * Restore the state
	 */
	Status = XLlTemac_SetMacAddress(TemacInstancePtr, MacSave);
	Status |= XLlTemac_SetOptions(TemacInstancePtr, Options);
	Status |= XLlTemac_ClearOptions(TemacInstancePtr, ~Options);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error restoring state after reset");
		return XST_FAILURE;
	}

	/*
	 * Restart the device
	 */
	XLlTemac_Start(TemacInstancePtr);
	return XST_SUCCESS;
}
/**
* This function resets the device but preserves the options set by the user.
*
* @param    None.
*
* @return   XST_SUCCESS if successful, else XST_FAILURE.
*
* @note     None.
*
******************************************************************************/
int TemacResetDevice(void)
{
	int Status;
	u8 MacSave[6];
	u32 Options;

	/*
	 * Stop device
	 */
	XLlTemac_Stop(&TemacInstance);

	/*
	 * Save the device state
	 */
	XLlTemac_GetMacAddress(&TemacInstance, MacSave);
	Options = XLlTemac_GetOptions(&TemacInstance);

	/*
	 * Stop and reset both the fifo and the temac the devices
	 */
	XLlFifo_Reset(&FifoInstance);
	XLlTemac_Reset(&TemacInstance, XTE_NORESET_HARD);

	/*
	 * Restore the state
	 */
	Status = XLlTemac_SetMacAddress(&TemacInstance, MacSave);
	Status |= XLlTemac_SetOptions(&TemacInstance, Options);
	Status |= XLlTemac_ClearOptions(&TemacInstance, ~Options);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error restoring state after reset");
		return XST_FAILURE;
	}

	return XST_SUCCESS;
}
Exemplo n.º 3
0
void
init_lltemac(xlltemacif_s *xlltemacif, struct netif *netif)
{
	int rdy;
	unsigned mac_address = (unsigned)(netif->state);
	unsigned link_speed = 1000;
	unsigned options;
        unsigned lock_message_printed = 0;

	/* obtain config of this emac */
	XLlTemac_Config *mac_config = lookup_config(mac_address);

	XLlTemac *xlltemacp = &xlltemacif->lltemac;

	XLlTemac_CfgInitialize(xlltemacp, mac_config, mac_config->BaseAddress);

	options = XLlTemac_GetOptions(xlltemacp);
	options |= XTE_FLOW_CONTROL_OPTION;
	options |= XTE_JUMBO_OPTION;
	options |= XTE_TRANSMITTER_ENABLE_OPTION;
	options |= XTE_RECEIVER_ENABLE_OPTION;
	options |= XTE_FCS_STRIP_OPTION;
	options |= XTE_MULTICAST_OPTION;
	XLlTemac_SetOptions(xlltemacp, options);
	XLlTemac_ClearOptions(xlltemacp, ~options);

	/* set mac address */
	XLlTemac_SetMacAddress(xlltemacp, (Xuint8*)(netif->hwaddr));

	/* make sure the hard TEMAC is ready */
	rdy = XLlTemac_ReadReg(xlltemacp->Config.BaseAddress,
			XTE_RDY_OFFSET);
	while ((rdy & XTE_RDY_HARD_ACS_RDY_MASK) == 0) {
		rdy = XLlTemac_ReadReg(xlltemacp->Config.BaseAddress,
				XTE_RDY_OFFSET);
	}

	link_speed = Phy_Setup(xlltemacp);
    	XLlTemac_SetOperatingSpeed(xlltemacp, link_speed);

	/* Setting the operating speed of the MAC needs a delay. */
	{
		volatile int wait;
		for (wait=0; wait < 100000; wait++);
		for (wait=0; wait < 100000; wait++);
	}

        /* in a soft temac implementation, we need to explicitly make sure that
         * the RX DCM has been locked. See xps_ll_temac manual for details.
         * This bit is guaranteed to be 1 for hard temac's
         */
        lock_message_printed = 0;
        while (!(XLlTemac_ReadReg(xlltemacp->Config.BaseAddress, XTE_IS_OFFSET)
                    & XTE_INT_RXDCM_LOCK_MASK)) {
                int first = 1;
                if (first) {
                        print("Waiting for RX DCM to lock..");
                        first = 0;
                        lock_message_printed = 1;
                }
        }

        if (lock_message_printed)
                print("RX DCM locked.\r\n");

	/* start the temac */
    	XLlTemac_Start(xlltemacp);

	/* enable TEMAC interrupts */
	XLlTemac_IntEnable(xlltemacp, XTE_INT_RECV_ERROR_MASK);
}
/**
*
* This example sends frames with the interrupt coalescing settings altered
* from their defaults.
*
* The default settings will interrupt the processor after every frame has been
* sent. This example will increase the threshold resulting in lower CPU
* utilization since it spends less time servicing interrupts.
*
* @param    TemacInstancePtr is a pointer to the instance of the Temac
*           component.
*
* @return   XST_SUCCESS to indicate success, otherwise XST_FAILURE.
*
* @note     None.
*
******************************************************************************/
int TemacSgDmaIntrCoalescingExample(XLlTemac * TemacInstancePtr,
				    XLlDma * DmaInstancePtr)
{
	int Status;
	u32 TxFrameLength;
	int TxFramesToSend = 1000;
	int TxFramesSent = 0;
	int PayloadSize = XTE_MTU;
	u32 Index;
	u32 NumBd;
	u16 Threshold = 64;
	XLlDma_BdRing *RxRingPtr = &XLlDma_mGetRxRing(DmaInstancePtr);
	XLlDma_BdRing *TxRingPtr = &XLlDma_mGetTxRing(DmaInstancePtr);
	XLlDma_Bd *BdPtr, *BdCurPtr;

	/*
	 * Clear variables shared with callbacks
	 */
	FramesRx = 0;
	FramesTx = 0;
	DeviceErrors = 0;

	/*
	 * Calculate the frame length (not including FCS)
	 */
	TxFrameLength = XTE_HDR_SIZE + PayloadSize;

	/*
	 * Setup packet to be transmitted. The same packet will be transmitted
	 * over and over
	 */
	TemacUtilFrameHdrFormatMAC(&TxFrame, TemacMAC);
	TemacUtilFrameHdrFormatType(&TxFrame, PayloadSize);
	TemacUtilFrameSetPayloadData(&TxFrame, PayloadSize);

        /*
         * Flush the TX frame before giving it to DMA TX channel to transmit,
         * in case D-Caching is turned on.
         */
	XCACHE_FLUSH_DCACHE_RANGE(&TxFrame, TxFrameLength);

	/*
	 * We don't care about the receive channel for this example, so turn it off
	 */
	Status = XLlTemac_ClearOptions(TemacInstancePtr,
				       XTE_RECEIVER_ENABLE_OPTION);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error clearing option");
		return XST_FAILURE;
	}

	/*
	 * Set the interrupt coalescing parameters for the test. The waitbound timer
	 * is set to 1 (ms) to catch the last few frames.
	 *
	 * If you set variable Threshold to some value larger than TXBD_CNT, then
	 * there can never be enough frames sent to meet the threshold. In this case
	 * the waitbound timer will always cause the interrupt to occur.
	 */
	Status = XLlDma_BdRingSetCoalesce(TxRingPtr, Threshold, 1);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error setting coalescing settings");
		return XST_FAILURE;
	}

	/*
	 * Prime the engine, allocate all BDs and assign them to the same buffer
	 */
	Status = XLlDma_BdRingAlloc(TxRingPtr, TXBD_CNT, &BdPtr);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error allocating TxBDs prior to starting");
		return XST_FAILURE;
	}

	/*
	 * Setup the TxBDs
	 */
	BdCurPtr = BdPtr;

	for (Index = 0; Index < TXBD_CNT; Index++) {
		XLlDma_mBdSetBufAddr(BdCurPtr, &TxFrame);
		XLlDma_mBdSetLength(BdCurPtr, TxFrameLength);
		XLlDma_mBdSetStsCtrl(BdCurPtr, XLLDMA_BD_STSCTRL_SOP_MASK |
				     XLLDMA_BD_STSCTRL_EOP_MASK);
		BdCurPtr = XLlDma_mBdRingNext(TxRingPtr, BdCurPtr);
	}

	/*
	 *  Enqueue all TxBDs to HW
	 */
	Status = XLlDma_BdRingToHw(TxRingPtr, TXBD_CNT, BdPtr);

	TxFramesSent += TXBD_CNT;
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error committing TxBDs prior to starting");
		return XST_FAILURE;
	}

	/*
	 * Enable the send interrupts. Nothing should be transmitted yet as the
	 * device has not been started
	 */
	XLlDma_mBdRingIntEnable(TxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK);
	/* Enable temac interrupts to capture errors */
	XLlTemac_IntEnable(TemacInstancePtr, XTE_INT_RECV_ERROR_MASK);

	/*
	 * Start the device. Transmission commences now!
	 */
	XLlTemac_Start(TemacInstancePtr);

	/*
	 * As DMA TX channel has been started in
	 * TemacSgDmaIntrSingleFrameExample() above, there is no need to start
	 * it again here
	 */

	while (TxFramesSent < TxFramesToSend) {
		/*
		 * Wait for the interrupt
		 */
		while (!FramesTx);

		/*
		 * Some TxBDs are ready for post processing. Get all that are available
		 * at the moment, free them, then allocate the same number and
		 * re-enqueue back to HW. At the same time this all occurs here,
		 * the DMA engine should be processing other TxBDs. If we can stay ahead
		 * of the transmitter like this, then throughput should be at or near
		 * line-rate.
		 *
		 * Note that this retrieves up to TXBD_CNT outstanding packets,
		 * so we may be processing more packets here than the threshold
		 * value, which may result in a seemingly spurious interrupt
		 * next time if we grab twice (or more) of the threshold value
		 * this time around (clear as mud, eh!).  Bottom line is that we
		 * ignore if NumBd returns as zero.
		 */
		NumBd = XLlDma_BdRingFromHw(TxRingPtr, TXBD_CNT, &BdPtr);
		if (NumBd > 0) {
			TxFramesSent += NumBd;

			/*
			 * Don't bother to check the BDs status, just free them
			 */
			Status = XLlDma_BdRingFree(TxRingPtr, NumBd, BdPtr);
			if (Status != XST_SUCCESS) {
				TemacUtilErrorTrap("Error freeing TxBDs");
			}

			/*
			 * Allocate the same number of BDs just freed
			 */
			Status = XLlDma_BdRingAlloc(TxRingPtr, NumBd, &BdPtr);
			if (Status != XST_SUCCESS) {
				TemacUtilErrorTrap("Error allocating TxBDs");
				return XST_FAILURE;
			}

			/*
			 * Setup the TxBDs
			 */
			BdCurPtr = BdPtr;
			for (Index = 0; Index < NumBd; Index++) {
				XLlDma_mBdSetBufAddr(BdCurPtr, &TxFrame);
				XLlDma_mBdSetLength(BdCurPtr, TxFrameLength);
				XLlDma_mBdSetStsCtrl(BdCurPtr,
						     XLLDMA_BD_STSCTRL_SOP_MASK
						     |
						     XLLDMA_BD_STSCTRL_EOP_MASK);
				BdCurPtr =
					XLlDma_mBdRingNext(TxRingPtr, BdCurPtr);
			}

			/*
			 * Enqueue TxBDs to HW
			 */
			Status = XLlDma_BdRingToHw(TxRingPtr, NumBd, BdPtr);
			if (Status != XST_SUCCESS) {
				TemacUtilErrorTrap
					("Error committing TxBDs prior to starting");
				return XST_FAILURE;
			}
		}

		/*
		 * Re-enable the interrupts
		 */
		FramesTx = 0;
		XLlDma_mBdRingIntEnable(TxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK);
	}

	/*
	 * Wait a second and collect any remaining frames that had been
	 * queued up but not post processed
	 */
#ifndef __MICROBLAZE__
	usleep(1000000);
#else
	/*
	 * Not sure if we should depend on there being a timer core in a
	 * microblaze system
	 */
	TemacUtilPhyDelay(1);
#endif

	NumBd = XLlDma_BdRingFromHw(TxRingPtr, 0xFFFFFFFF, &BdPtr);

	if (NumBd > 0) {
		Status = XLlDma_BdRingFree(TxRingPtr, NumBd, BdPtr);
		if (Status != XST_SUCCESS) {
			TemacUtilErrorTrap("Error freeing TxBDs");
		}
	}

	/*
	 * Done sending frames. Stop the device
	 */
	XLlTemac_Stop(TemacInstancePtr);

	return XST_SUCCESS;
}