/**
* 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;
}
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 and receives a single packet in loopback mode with checksum
* offloading support.
*
* The transmit frame will be checksummed over the entire Ethernet payload
* and inserted into the last 2 bytes of the frame.
*
* On receive, HW should calculate the Ethernet payload checksum and return a
* value of 0xFFFF which means the payload data was likely not corrupted.
*
* @param    TemacInstancePtr is a pointer to the instance of the Temac
*           component.
*
* @return   XST_SUCCESS to indicate success, otherwise XST_FAILURE.
*
* @note     None.
*
******************************************************************************/
int TemacSgDmaChecksumOffloadExample(XLlTemac * TemacInstancePtr,
				     XLlDma * DmaInstancePtr)
{
	int Status;
	u32 TxFrameLength;
	int PayloadSize = 1000;
	XLlDma_BdRing *RxRingPtr = &XLlDma_mGetRxRing(DmaInstancePtr);
	XLlDma_BdRing *TxRingPtr = &XLlDma_mGetTxRing(DmaInstancePtr);
	XLlDma_Bd *BdPtr;

	/*
	 * Cannot run this example if checksum offloading support is not available
	 */
	if (!(XLlTemac_IsRxCsum(TemacInstancePtr) &&
	      XLlTemac_IsTxCsum(TemacInstancePtr))) {
		TemacUtilErrorTrap("Checksum offloading not available");
		return XST_FAILURE;
	}

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

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

	/*
	 * Setup the packet to be transmitted,
	 * Last 2 bytes are reserved for checksum
	 */
	TemacUtilFrameMemClear(&TxFrame);
	TemacUtilFrameHdrFormatMAC(&TxFrame, TemacMAC);
	TemacUtilFrameHdrFormatType(&TxFrame, PayloadSize);
	TemacUtilFrameSetPayloadData(&TxFrame, PayloadSize - 2);

        /*
         * 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);

	/*
	 * Clear out receive packet memory area
	 */
	TemacUtilFrameMemClear(&RxFrame);

        /*
         * Invalidate the RX frame before giving it to DMA RX channel to
         * receive data, in case D-Caching is turned on.
         */
	XCACHE_INVALIDATE_DCACHE_RANGE(&RxFrame, TxFrameLength);

	/*
	 * Interrupt coalescing parameters are set to their default settings
	 * which is to interrupt the processor after every frame has been
	 * processed by the DMA engine.
	 */
	Status = XLlDma_BdRingSetCoalesce(TxRingPtr, 1, 1);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error setting coalescing for transmit");
		return XST_FAILURE;
	}

	Status = XLlDma_BdRingSetCoalesce(RxRingPtr, 1, 1);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error setting coalescing for recv");
		return XST_FAILURE;
	}

	/*
	 * Make sure Tx and Rx are enabled
	 */
	Status = XLlTemac_SetOptions(TemacInstancePtr,
				     XTE_RECEIVER_ENABLE_OPTION |
				     XTE_TRANSMITTER_ENABLE_OPTION);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error setting options");
		return XST_FAILURE;
	}

	/*
	 * Start the LLTEMAC and enable its ERROR interrupts
	 */
	XLlTemac_Start(TemacInstancePtr);
	XLlTemac_IntEnable(TemacInstancePtr, XTE_INT_RECV_ERROR_MASK);

	/*
	 * Allocate 1 RxBD. Note that TEMAC utilizes an in-place allocation
	 * scheme. The returned BdPtr will point to a free BD in the memory
	 * segment setup with the call to XLlTemac_SgSetSpace()
	 */
	Status = XLlDma_BdRingAlloc(RxRingPtr, 1, &BdPtr);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error allocating RxBD");
		return XST_FAILURE;
	}

	/*
	 * Setup the BD. The BD template used in the call to XLlTemac_SgSetSpace()
	 * set the SOP and EOP fields of all RxBDs.
	 */
	XLlDma_mBdSetBufAddr(BdPtr, &RxFrame);
	XLlDma_mBdSetLength(BdPtr, sizeof(RxFrame));
	XLlDma_mBdSetStsCtrl(BdPtr, XLLDMA_BD_STSCTRL_SOP_MASK |
			     XLLDMA_BD_STSCTRL_EOP_MASK);


	/*
	 * Enqueue to HW
	 */
	Status = XLlDma_BdRingToHw(RxRingPtr, 1, BdPtr);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error committing RxBD to HW");
		return XST_FAILURE;
	}

	/*
	 * Enable DMA receive related interrupts
	 */
	XLlDma_mBdRingIntEnable(RxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK);

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

	/*
	 * Allocate 1 TxBD
	 */
	Status = XLlDma_BdRingAlloc(TxRingPtr, 1, &BdPtr);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error allocating TxBD");
		return XST_FAILURE;
	}

	/*
	 * Setup the TxBD
	 */
	XLlDma_mBdSetBufAddr(BdPtr, &TxFrame);
	XLlDma_mBdSetLength(BdPtr, TxFrameLength);
	XLlDma_mBdSetStsCtrl(BdPtr, XLLDMA_BD_STSCTRL_SOP_MASK |
			     XLLDMA_BD_STSCTRL_EOP_MASK);

	/*
	 * Setup TxBd checksum offload attributes.
	 * Note that the checksum offload values can be set globally for all TxBds
	 * when XLlDma_BdRingClone() is called to setup Tx BD space. This would
	 * eliminate the need to set them here.
	 */

	/* Enable hardware checksum computation for the buffer descriptor */
	XLlDma_mBdWrite((BdPtr), XLLDMA_BD_STSCTRL_USR0_OFFSET,
			(XLlDma_mBdRead((BdPtr), XLLDMA_BD_STSCTRL_USR0_OFFSET)
			 | CSUM_ENABLE));
	/* Write Start Offset and Insert Offset into BD */
	XLlDma_mBdWrite(BdPtr, XLLDMA_BD_USR1_OFFSET,
					XTE_HDR_SIZE << 16 | TxFrameLength - 2);
	/* Write 0, as the seed value, to the BD */
	XLlDma_mBdWrite(BdPtr, XLLDMA_BD_USR2_OFFSET, 0);
	/*
	 * Enqueue to HW
	 */
	Status = XLlDma_BdRingToHw(TxRingPtr, 1, BdPtr);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error committing TxBD to HW");
		return XST_FAILURE;
	}

	/*
	 * Enable DMA transmit related interrupts
	 */
	XLlDma_mBdRingIntEnable(TxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK);

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

	/*
	 * Wait for transmission to complete
	 */
	while (!FramesTx);
	/*
	 * Now that the frame has been sent, post process our TxBDs.
	 * Since we have only submitted 2 to HW, then there should be only 2 ready
	 * for post processing.
	 */
	if (XLlDma_BdRingFromHw(TxRingPtr, 1, &BdPtr) == 0) {
		TemacUtilErrorTrap("TxBDs were not ready for post processing");
		return XST_FAILURE;
	}

	/*
	 * Examine the TxBDs.
	 *
	 * There isn't much to do. The only thing to check would be DMA exception
	 * bits. But this would also be caught in the error handler. So we just
	 * return these BDs to the free list
	 */
	Status = XLlDma_BdRingFree(TxRingPtr, 1, BdPtr);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error freeing up TxBDs");
		return XST_FAILURE;
	}

	/*
	 * Wait for Rx indication
	 */
	while (!FramesRx);
	/*
	 * Now that the frame has been received, post process our RxBD.
	 * Since we have only submitted 1 to HW, then there should be only 1 ready
	 * for post processing.
	 */
	if (XLlDma_BdRingFromHw(RxRingPtr, 1, &BdPtr) == 0) {
		TemacUtilErrorTrap("RxBD was not ready for post processing");
		return XST_FAILURE;
	}

	/*
	 * There is no device status to check. If there was a DMA error, it should
	 * have been reported to the error handler. Check the receive length against
	 * the transmitted length, then verify the data.
	 *
	 * Note in LLTEMAC case, USR4_OFFSET word in the RX BD is used to store
	 * the real length of the received packet
	 */
	if (XLlDma_mBdRead(BdPtr, XLLDMA_BD_USR4_OFFSET) != TxFrameLength) {
		TemacUtilErrorTrap("Length mismatch");
	}

	/*
	 * Verify the checksum as computed by HW. It should add up to 0xFFFF
	 * if frame was uncorrupted
	 */
	if ((u16) (XLlDma_mBdRead(BdPtr, XLLDMA_BD_USR3_OFFSET))
		!= 0xFFFF) {
		TemacUtilErrorTrap("Rx checksum incorrect");
		return XST_FAILURE;
	}

	/*
	 * Return the RxBD back to the channel for later allocation. Free the
	 * exact number we just post processed.
	 */
	Status = XLlDma_BdRingFree(RxRingPtr, 1, BdPtr);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error freeing up TxBDs");
		return XST_FAILURE;
	}

	/*
	 * Finished this example. If everything worked correctly, all TxBDs and
	 * RxBDs should be free for allocation. Stop the device.
	 */
	XLlTemac_Stop(TemacInstancePtr);
	return XST_SUCCESS;
}