int wlan_eth_dma_send(u8* pkt_ptr, u32 length) {
	int status;
	XAxiDma_BdRing *txRing_ptr;
	XAxiDma_Bd *cur_bd_ptr;

	//Flush the data cache of the pkt buffer
	// Comment this back in if the dcache is enabled
	//Xil_DCacheFlushRange((u32)TxPacket, MAX_PKT_LEN);

	txRing_ptr = XAxiDma_GetTxRing(&ETH_A_DMA_Instance);

	status = XAxiDma_BdRingAlloc(txRing_ptr, 1, &cur_bd_ptr);
	status |= XAxiDma_BdSetBufAddr(cur_bd_ptr, (u32)pkt_ptr);
	status |= XAxiDma_BdSetLength(cur_bd_ptr, length, txRing_ptr->MaxTransferLen);
	if(status != XST_SUCCESS) {xil_printf("Error in setting ETH Tx BD! Err = %d\n", status); return -1;}

	//When using 1 BD for 1 pkt set both SOF and EOF
	XAxiDma_BdSetCtrl(cur_bd_ptr, (XAXIDMA_BD_CTRL_TXSOF_MASK | XAXIDMA_BD_CTRL_TXEOF_MASK) );

	//Set arbitrary ID
	XAxiDma_BdSetId(cur_bd_ptr, (u32)pkt_ptr);

	//Push the BD ring to hardware; this initiates the actual DMA transfer and Ethernet Tx
	status = XAxiDma_BdRingToHw(txRing_ptr, 1, cur_bd_ptr);
	if(status != XST_SUCCESS) {xil_printf("Error in XAxiDma_BdRingToHw(txRing_ptr)! Err = %d\n", status); return -1;}

	//Wait for this DMA transfer to finish (will be replaced by post-Tx ISR)
	while (XAxiDma_BdRingFromHw(txRing_ptr, 1, &cur_bd_ptr) == 0) {/*Do Nothing*/}
	status = XAxiDma_BdRingFree(txRing_ptr, 1, cur_bd_ptr);
	if(status != XST_SUCCESS) {xil_printf("Error in XAxiDma_BdRingFree(txRing_ptr, 1)! Err = %d\n", status); return -1;}

	return 0;
}
Пример #2
0
/*
*
* This is the DMA RX callback function called by the RX interrupt handler.
* This function handles finished BDs by hardware, attaches new buffers to those
* BDs, and give them back to hardware to receive more incoming packets
*
* @param	RxRingPtr is a pointer to RX channel of the DMA engine.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void RxCallBack(XAxiDma_BdRing * RxRingPtr)
{
	int BdCount;
	XAxiDma_Bd *BdPtr;
	XAxiDma_Bd *BdCurPtr;
	u32 BdSts;
	int Index;

	/* Get finished BDs from hardware */
	BdCount = XAxiDma_BdRingFromHw(RxRingPtr, XAXIDMA_ALL_BDS, &BdPtr);

	BdCurPtr = BdPtr;
	for (Index = 0; Index < BdCount; Index++) {

		/*
		 * Check the flags set by the hardware for status
		 * If error happens, processing stops, because the DMA engine
		 * is halted after this BD.
		 */
		BdSts = XAxiDma_BdGetSts(BdCurPtr);
		if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) ||
		    (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) {
			Error = 1;
			break;
		}

		/* Find the next processed BD */
		BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr);
		RxDone += 1;
	}

}
/*
*
* This is the DMA TX callback function to be called by TX interrupt handler.
* This function handles BDs finished by hardware.
*
* @param	TxRingPtr is a pointer to TX channel of the DMA engine.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void TxCallBack(XAxiDma *AxiDmaPtr)
{
	int BdCount;
	u32 BdSts;
	XAxiDma_Bd *BdPtr;
	XAxiDma_Bd *BdCurPtr;
	int Status;
	int Index;
	XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(AxiDmaPtr);

	/* Get all processed BDs from hardware */
	BdCount = XAxiDma_BdRingFromHw(TxRingPtr, XAXIDMA_ALL_BDS, &BdPtr);

	/* Handle the BDs */
	BdCurPtr = BdPtr;
	for (Index = 0; Index < BdCount; Index++) {

		/*
		 * Check the status in each BD
		 * If error happens, the DMA engine will be halted after this
		 * BD processing stops.
		 */
		BdSts = XAxiDma_BdGetSts(BdCurPtr);
		if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) ||
		    (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) {

			Error = 1;
			break;
		}

		/*
		 * Here we don't need to do anything. But if a RTOS is being
		 * used, we may need to free the packet buffer attached to
		 * the processed BD
		 */

		/* Find the next processed BD */
		BdCurPtr = XAxiDma_BdRingNext(TxRingPtr, BdCurPtr);
	}

	/* Free all processed BDs for future transmission */
	Status = XAxiDma_BdRingFree(TxRingPtr, BdCount, BdPtr);
	if (Status != XST_SUCCESS) {
		Error = 1;
	}

	if(!Error) {
		TxDone += BdCount;
	}
}
void wlan_poll_eth() {
	XAxiDma_BdRing *rxRing_ptr;
	XAxiDma_Bd *cur_bd_ptr;
	XAxiDma_Bd *first_bd_ptr;
	u8* mpdu_start_ptr;
	u8* eth_start_ptr;
	u8* eth_mid_ptr;
	packet_bd* tx_queue;
	u32 eth_rx_len, eth_rx_buf;
	u32 mpdu_tx_len;
	packet_bd_list tx_queue_list;
	u32 i;
	u8 continue_loop;

	int bd_count;
	int status;
	int packet_is_queued;

	ethernet_header* eth_hdr;
	ipv4_header* ip_hdr;
	arp_packet* arp;
	udp_header* udp;
	dhcp_packet* dhcp;

	llc_header* llc_hdr;
	u8 eth_dest[6];
	u8 eth_src[6];

	static u32 max_bd_count = 0;

	rxRing_ptr = XAxiDma_GetRxRing(&ETH_A_DMA_Instance);

	//Check if any Rx BDs have been executed
	//TODO: process XAXIDMA_ALL_BDS instead of 1 at a time
	//bd_count = XAxiDma_BdRingFromHw(rxRing_ptr, 1, &cur_bd_ptr);
	bd_count = XAxiDma_BdRingFromHw(rxRing_ptr, XAXIDMA_ALL_BDS, &first_bd_ptr);
	cur_bd_ptr = first_bd_ptr;

	if(bd_count > max_bd_count){
		max_bd_count = bd_count;
		//xil_printf("max_bd_count = %d\n",max_bd_count);
	}

	if(bd_count == 0) {
		//No Rx BDs have been processed - no new Eth receptions waiting
		return;
	}

	for(i=0;i<bd_count;i++){

		//A packet has been received and transferred by DMA
		tx_queue = (packet_bd*)XAxiDma_BdGetId(cur_bd_ptr);

		//xil_printf("DMA has filled in packet_bd at 0x%08x\n", tx_queue);

		eth_rx_len = XAxiDma_BdGetActualLength(cur_bd_ptr, rxRing_ptr->MaxTransferLen);
		eth_rx_buf = XAxiDma_BdGetBufAddr(cur_bd_ptr);

		//After encapsulation, byte[0] of the MPDU will be at byte[0] of the queue entry frame buffer
		mpdu_start_ptr = (void*)((tx_packet_buffer*)(tx_queue->buf_ptr))->frame;

		eth_start_ptr = (u8*)eth_rx_buf;

		//Calculate actual wireless Tx len (eth payload - eth header + wireless header)
		mpdu_tx_len = eth_rx_len - sizeof(ethernet_header) + sizeof(llc_header) + sizeof(mac_header_80211);

		//Helper pointers to interpret/fill fields in the new MPDU
		eth_hdr = (ethernet_header*)eth_start_ptr;
		llc_hdr = (llc_header*)(mpdu_start_ptr + sizeof(mac_header_80211));

		//Copy the src/dest addresses from the received Eth packet to temp space
		memcpy(eth_src, eth_hdr->address_source, 6);
		memcpy(eth_dest, eth_hdr->address_destination, 6);

		//Prepare the MPDU LLC header
		llc_hdr->dsap = LLC_SNAP;
		llc_hdr->ssap = LLC_SNAP;
		llc_hdr->control_field = LLC_CNTRL_UNNUMBERED;
		bzero((void *)(llc_hdr->org_code), 3); //Org Code 0x000000: Encapsulated Ethernet

		packet_is_queued = 0;
		packet_bd_list tx_queue_list;
		packet_bd_list_init(&tx_queue_list);
		packet_bd_insertEnd(&tx_queue_list, tx_queue);

		switch(eth_encap_mode){
			case ENCAP_MODE_AP:

				switch(eth_hdr->type) {
					case ETH_TYPE_ARP:
						llc_hdr->type = LLC_TYPE_ARP;
						packet_is_queued = eth_rx_callback(&tx_queue_list, eth_dest, eth_src, mpdu_tx_len);
					break;
					case ETH_TYPE_IP:
						llc_hdr->type = LLC_TYPE_IP;
						packet_is_queued = eth_rx_callback(&tx_queue_list, eth_dest, eth_src, mpdu_tx_len);
					break;

					/* WMP_START */
					case WMP4WARP_ETHER_TYPE:
						wmp_high_util_handle_wmp_cmd_from_ethernet(eth_hdr);
					break;
					/* WMP_END */
					default:
						//Unknown/unsupported EtherType; don't process the Eth frame
					break;
				}

			break;

			case ENCAP_MODE_STA:

				//Save this ethernet src address for d
				memcpy(eth_sta_mac_addr, eth_src, 6);
				memcpy(eth_src, hw_info.hw_addr_wlan, 6);

				switch(eth_hdr->type) {
					case ETH_TYPE_ARP:
						arp = (arp_packet*)((void*)eth_hdr + sizeof(ethernet_header));

						//Here we hijack ARP messages and overwrite their source MAC address field with
						//the station's wireless MAC address.
						memcpy(arp->eth_src, hw_info.hw_addr_wlan, 6);

						llc_hdr->type = LLC_TYPE_ARP;
						packet_is_queued = eth_rx_callback(&tx_queue_list, eth_dest, eth_src, mpdu_tx_len);


					break;
					case ETH_TYPE_IP:
						llc_hdr->type = LLC_TYPE_IP;
						ip_hdr = (ipv4_header*)((void*)eth_hdr + sizeof(ethernet_header));

						if(ip_hdr->prot == IPV4_PROT_UDP){
							udp = (udp_header*)((void*)ip_hdr + 4*((u8)(ip_hdr->ver_ihl) & 0xF));
							udp->checksum = 0; //Disable the checksum since we are about to mess with the bytes in the packet

							if(Xil_Ntohs(udp->src_port) == UDP_SRC_PORT_BOOTPC || Xil_Ntohs(udp->src_port) == UDP_SRC_PORT_BOOTPS){
								//This is a DHCP Discover packet, which contains the source hardware address
								//deep inside the packet (in addition to its usual location in the Eth header).
								//For STA encapsulation, we need to overwrite this address with the MAC addr
								//of the wireless station.

								dhcp = (dhcp_packet*)((void*)udp + sizeof(udp_header));

								if(Xil_Ntohl(dhcp->magic_cookie) == DHCP_MAGIC_COOKIE){
									eth_mid_ptr = (u8*)((void*)dhcp + sizeof(dhcp_packet));

									dhcp->flags = Xil_Htons(DHCP_BOOTP_FLAGS_BROADCAST);

									//Tagged DHCP Options
									continue_loop = 1;

									while(continue_loop){
										switch(eth_mid_ptr[0]){

											case DHCP_OPTION_TAG_TYPE:
												switch(eth_mid_ptr[2]){
													case DHCP_OPTION_TYPE_DISCOVER:
													case DHCP_OPTION_TYPE_REQUEST:
														//memcpy(dhcp->chaddr,hw_info.hw_addr_wlan,6);
													break;

												}

											break;

											case DHCP_OPTION_TAG_IDENTIFIER:
												//memcpy(&(eth_mid_ptr[3]),hw_info.hw_addr_wlan,6);

											break;

											case DHCP_OPTION_END:
												continue_loop = 0;
											break;
										}
										eth_mid_ptr += (2+eth_mid_ptr[1]);
									}
								}
							}
						}
						packet_is_queued = eth_rx_callback(&tx_queue_list, eth_dest, eth_src, mpdu_tx_len);

					break;

					/* WMP_START */
					case WMP4WARP_ETHER_TYPE:{
						wmp_high_util_handle_wmp_cmd_from_ethernet(eth_hdr);
					break;}
					/* WMP_END */
					default:
						//Unknown/unsupported EtherType; don't process the Eth frame
					break;
			}

			break;

		}

		if(packet_is_queued == 0){
			//xil_printf("   ...checking in\n");
			queue_checkin(&tx_queue_list);
		}

		//TODO: Option A: We free this single BD and run the routine to checkout as many queues as we can and hook them up to BDs
		//Results: pretty good TCP performance
		//Free this bd
		status = XAxiDma_BdRingFree(rxRing_ptr, 1, cur_bd_ptr);
		if(status != XST_SUCCESS) {xil_printf("Error in XAxiDma_BdRingFree of Rx BD! Err = %d\n", status); return;}
		wlan_eth_dma_update();

		//Update cur_bd_ptr to the next BD in the chain for the next iteration
		cur_bd_ptr = XAxiDma_BdRingNext(rxRing_ptr, cur_bd_ptr);

	}
	//TODO: Option B: We free all BDs at once and run the routine to checkout as many queues as we can and hook them up to BDs
	//Results: pretty lackluster TCP performance. needs further investigation
	//Free this bd
	//status = XAxiDma_BdRingFree(rxRing_ptr, bd_count, first_bd_ptr);
	//if(status != XST_SUCCESS) {xil_printf("Error in XAxiDma_BdRingFree of Rx BD! Err = %d\n", status); return;}
	//wlan_eth_dma_update();

	return;
}
/**
*
* This function waits until the DMA transaction is finished, checks data,
* and cleans up.
*
* @return   - XST_SUCCESS if DMA transfer is successful and data is correct,
*           - XST_FAILURE otherwise.
*
* @note     None.
*
******************************************************************************/
static int CheckDmaResult(XAxiDma * AxiDmaInstPtr)
{
	XAxiDma_BdRing *TxRingPtr;
	XAxiDma_BdRing *RxRingPtr;
	XAxiDma_Bd *BdPtr;
	int ProcessedBdCount;
	int FreeBdCount;
	int Status;

	TxRingPtr = XAxiDma_GetTxRing(AxiDmaInstPtr);
	RxRingPtr = XAxiDma_GetRxRing(AxiDmaInstPtr);

	/* Wait until the one BD TX transaction is done */
	while ((ProcessedBdCount = XAxiDma_BdRingFromHw(TxRingPtr,
						       XAXIDMA_ALL_BDS,
						       &BdPtr)) == 0) {
	}

	/* Free all processed TX BDs for future transmission */
	Status = XAxiDma_BdRingFree(TxRingPtr, ProcessedBdCount, BdPtr);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Failed to free %d tx BDs %d\r\n",
		    ProcessedBdCount, Status);
		return XST_FAILURE;
	}

	/* Wait until the data has been received by the Rx channel */
	while ((ProcessedBdCount = XAxiDma_BdRingFromHw(RxRingPtr,
						       XAXIDMA_ALL_BDS,
						       &BdPtr)) == 0) {
	}

	/* Check received data */
	if (CheckData() != XST_SUCCESS) {

		return XST_FAILURE;
	}

	/* Free all processed RX BDs for future transmission */
	Status = XAxiDma_BdRingFree(RxRingPtr, ProcessedBdCount, BdPtr);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Failed to free %d rx BDs %d\r\n",
		    ProcessedBdCount, Status);
		return XST_FAILURE;
	}

	/* Return processed BDs to RX channel so we are ready to receive new
	 * packets:
	 *    - Allocate all free RX BDs
	 *    - Pass the BDs to RX channel
	 */
	FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr);
	Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR, "bd alloc failed\r\n");
		return XST_FAILURE;
	}

	Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Submit %d rx BDs failed %d\r\n", FreeBdCount, Status);
		return XST_FAILURE;
	}

	return XST_SUCCESS;
}
/**
*
* This example sends and receives a single packet in loopback mode with
* extended VLAN support.
*
* The transmit frame will have VLAN field populated.
*
* On receive, HW should pass the VLAN field to receive BDs.
*
* @param	AxiEthernetInstancePtr is a pointer to the instance of the
*		AxiEthernet component.
* @param	DmaInstancePtr   is a pointer to the instance of the Dma
*		component.
*
* @return	-XST_SUCCESS to indicate success.
*		-XST_FAILURE to indicate failure.
*
* @note		Summary of VLAN tags handling in this example
*
* Frame setup with Tpid1+Cfi1+TxPid => 0x88A83111
* Frame translated to TxTransVid => 0x88A83222
* Frame tagged to Tpid2+Cfi2+TxTagVid => 0x9100C333 + 0x88A83222
* Frame sent and loopbacked.
*
* Frame stripped with RxStrpVid(0x333) => 0x88A83222
* Frame translated (key:RxVid:0x222) RxTransVid => 0x88A83444
*
******************************************************************************/
int AxiEthernetSgDmaIntrExtVlanExample(XAxiEthernet *AxiEthernetInstancePtr,
				XAxiDma *DmaInstancePtr)
{
	int Status;
	u32 TxFrameLength;
	u32 RxFrameLength;
	int PayloadSize = PAYLOAD_SIZE;
	u16 Tpid1 = 0x88A8;
	u16 Tpid2 = 0x9100;
	u8  Cfi1  = 0x03;
	u8  Cfi2  = 0x0C;
	u16 TxVid      = 0x0111;
	u16 TxTransVid = 0x0222;
	u16 TxTagVid   = 0x0333;
	u16 RxVid      = 0x0222;
	u16 RxTransVid = 0x0444;
	u16 RxStrpVid  = 0x0333;
	u32 VTagCfiVid;
	u16 RxCfiVid;
	u16 RxTpid;
	u32 RxStatusControlWord;
	int Valid;


	XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr);
	XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr);
	XAxiDma_Bd *BdPtr;
	XAxiDma_Bd *BdCurPtr;
	u32 BdSts;

	/*
	 * Cannot run this example if extended features support is not enabled
	 */
	if (!(XAxiEthernet_IsTxVlanTran(AxiEthernetInstancePtr) &&
		XAxiEthernet_IsTxVlanStrp(AxiEthernetInstancePtr) &&
		XAxiEthernet_IsTxVlanTag(AxiEthernetInstancePtr)  &&
		XAxiEthernet_IsRxVlanTran(AxiEthernetInstancePtr) &&
		XAxiEthernet_IsRxVlanStrp(AxiEthernetInstancePtr) &&
		XAxiEthernet_IsRxVlanTag(AxiEthernetInstancePtr))) {
		AxiEthernetUtilErrorTrap("Extended VLAN not available");
		return XST_FAILURE;
	}

	/*
	 * Clear variables shared with callbacks
	 */
	FramesRx = 0;
	FramesTx = 0;
	DeviceErrors = 0;
	memset(RxFrame,0,sizeof(RxFrame));
	memset(TxFrame,0,sizeof(TxFrame));

	/*
	 * Calculate frame length (not including FCS) plus one VLAN tag
	 */
	TxFrameLength = XAE_HDR_VLAN_SIZE + PayloadSize;

	/*
	 * Setup the packet with one VALN tag = VtagCfiVid to be transmitted
	 * initially.
	 */
	VTagCfiVid = (((u32)Tpid1 << 16) | ((u32)Cfi1 << 12) | TxVid);
	AxiEthernetUtilFrameMemClear(&TxFrame);
	AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC);
	AxiEthernetUtilFrameHdrVlanFormatVid(&TxFrame, 0, VTagCfiVid);
	AxiEthernetUtilFrameHdrVlanFormatType(&TxFrame, PayloadSize, 1);
	AxiEthernetUtilFrameSetVlanPayloadData(&TxFrame, PayloadSize, 1);

	/* Intended VLAN setup:
	 * TX translation and tagging. RX stripping and translation.
	 *
	 * Frame setup with Tpid1+Cfi1+TxPid => 0x88A83111
	 * Frame translated to TxTransVid => 0x88A83222
	 * Frame tagged to Tpid2+Cfi2+TxTagVid => 0x9100C333 + 0x88A83222
	 * Frame sent and loopbacked.
	 *
	 * Frame stripped with RxStrpVid(0x333) => 0x88A83222
	 * Frame translated (key:RxVid:0x222) RxTransVid => 0x88A83444
	 */

	/* Extended VLAN transmit side. Stripping->Translation->Tagging */
	/*
	 * Configure VLAN TX tag mode, set to XAE_VTAG_SELECT.
	 */
	Status  = XAxiEthernet_SetOptions(AxiEthernetInstancePtr,
						XAE_EXT_TXVLAN_TAG_OPTION);
	Status |= XAxiEthernet_SetVTagMode(AxiEthernetInstancePtr,
						XAE_VTAG_SELECT, XAE_TX);

	/*
	 * TX VLAN translation from TxVid to TxTransVid and enable tagging.
	 */
	Status |= XAxiEthernet_SetOptions(AxiEthernetInstancePtr,
						XAE_EXT_TXVLAN_TRAN_OPTION);
	Status |= XAxiEthernet_SetVidTable(AxiEthernetInstancePtr, TxVid,
						TxTransVid,0, 1, XAE_TX);

	/*
	 * TX VLAN tagging is keyed on TxVid to add one additional tag based
	 * on register XAE_TTAG_OFFSET value.
	 */
	VTagCfiVid = (((u32)Tpid2 << 16) | ((u32)Cfi2 << 12) | TxTagVid);
	Status |= XAxiEthernet_SetVTagValue(AxiEthernetInstancePtr,
							VTagCfiVid, XAE_TX);
	if (Status != XST_SUCCESS) {
		AxiEthernetUtilErrorTrap("Error setting TX VLAN");
		return XST_FAILURE;
	}

	/* Extended VLAN receive side. Stripping->Translation->Tagging */
	/*
	 * Configure VLAN RX strip mode, set to XAE_VSTRP_SELECT.
	 */
	Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr,
						XAE_EXT_RXVLAN_STRP_OPTION);
	Status |= XAxiEthernet_SetVStripMode(AxiEthernetInstancePtr,
						XAE_VSTRP_SELECT, XAE_RX);

	/*
	 * RX VLAN strips based on RxStrpVid and enable stripping.
	 */
	Status |= XAxiEthernet_SetVidTable(AxiEthernetInstancePtr, RxStrpVid,
						RxStrpVid, 1, 0, XAE_RX);

	/*
	 * RX VLAN translation from RxVid to RxTransVid only.
	 */
	Status |= XAxiEthernet_SetOptions(AxiEthernetInstancePtr,
						XAE_EXT_RXVLAN_TRAN_OPTION);
	Status |= XAxiEthernet_SetVidTable(AxiEthernetInstancePtr, RxVid,
						RxTransVid, 0, 0, XAE_RX);

	if (Status != XST_SUCCESS) {
		AxiEthernetUtilErrorTrap("Error setting RX VLAN");
		return XST_FAILURE;
	}

	/* Configure VLAN TPIDs for HW to recognize. */
	Status  = XAxiEthernet_SetTpid(AxiEthernetInstancePtr, Tpid1, 0);
	Status |= XAxiEthernet_SetTpid(AxiEthernetInstancePtr, Tpid2, 1);
	if (Status != XST_SUCCESS) {
		AxiEthernetUtilErrorTrap("Error setting TPIDs");
		return XST_FAILURE;
	}

	/*
	 * Flush the TX frame before giving it to DMA TX channel to transmit.
	 */
	Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength);

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

	/*
	 * Invalidate the RX frame before giving it to DMA RX channel to
	 * receive data.
 	 */
	Xil_DCacheInvalidateRange((u32)&RxFrame, TxFrameLength + 4);

	/*
	 * 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 = XAxiDma_BdRingSetCoalesce(TxRingPtr, 1, 1);
	if (Status != XST_SUCCESS) {
		AxiEthernetUtilErrorTrap("Error setting coalescing for transmit");
		return XST_FAILURE;
	}

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

	/*
	 * Make sure Tx and Rx are enabled
	 */
	Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr,
					XAE_RECEIVER_ENABLE_OPTION |
					XAE_TRANSMITTER_ENABLE_OPTION );
	if (Status != XST_SUCCESS) {
		AxiEthernetUtilErrorTrap("Error setting options");
		return XST_FAILURE;
	}

	Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr,
					XAE_JUMBO_OPTION);
	if (Status != XST_SUCCESS) {
		AxiEthernetUtilErrorTrap("Error setting options");
		return XST_FAILURE;
	}

	/*
	 * Start the AxiEthernet and enable its ERROR interrupts
	 */
	XAxiEthernet_Start(AxiEthernetInstancePtr);
	XAxiEthernet_IntEnable(&AxiEthernetInstance,
					XAE_INT_RECV_ERROR_MASK);

	/*
	 * Enable DMA receive related interrupts
	 */
	XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);

	/*
	 * Allocate 1 RxBD.
	 */
	Status = XAxiDma_BdRingAlloc(RxRingPtr, 1, &BdPtr);
	if (Status != XST_SUCCESS) {
		AxiEthernetUtilErrorTrap("Error allocating RxBD");
		return XST_FAILURE;
	}

	/*
	 * Setup the BD.
	 */
	XAxiDma_BdSetBufAddr(BdPtr, (u32)&RxFrame);
#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL
	XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame));
#else
	XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame),
				RxRingPtr->MaxTransferLen);
#endif
	XAxiDma_BdSetCtrl(BdPtr, 0);

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

	/*
	 * Start DMA RX channel. Now it's ready to receive data.
	 */
	Status = XAxiDma_BdRingStart(RxRingPtr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Enable DMA transmit related interrupts
	 */
	XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK);

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

	/*
	 * Setup the TxBD
	 */
	XAxiDma_BdSetBufAddr(BdPtr, (u32)&TxFrame);
#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL
	XAxiDma_BdSetLength(BdPtr, TxFrameLength);
#else
	XAxiDma_BdSetLength(BdPtr, TxFrameLength,
				TxRingPtr->MaxTransferLen);
#endif
	XAxiDma_BdSetCtrl(BdPtr, XAXIDMA_BD_CTRL_TXSOF_MASK |
						XAXIDMA_BD_CTRL_TXEOF_MASK);

	/*
	 * Enqueue to HW
	 */
	Status = XAxiDma_BdRingToHw(TxRingPtr, 1, BdPtr);
	if (Status != XST_SUCCESS) {
		AxiEthernetUtilErrorTrap("Error committing TxBD to HW");
		return XST_FAILURE;
	}

	/*
	 * Start DMA TX channel. Transmission starts at once.
	 */
	Status = XAxiDma_BdRingStart(TxRingPtr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * 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 (XAxiDma_BdRingFromHw(TxRingPtr, 1, &BdPtr) == 0) {
		AxiEthernetUtilErrorTrap("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 = XAxiDma_BdRingFree(TxRingPtr, 1, BdPtr);
	if (Status != XST_SUCCESS) {
		AxiEthernetUtilErrorTrap("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 (XAxiDma_BdRingFromHw(RxRingPtr, 1, &BdPtr) == 0) {
		AxiEthernetUtilErrorTrap("RxBD was not ready for post processing");
		return XST_FAILURE;
	}

	BdCurPtr = BdPtr;
	BdSts = XAxiDma_BdGetSts(BdCurPtr);

	if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) ||
		(!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) {
			AxiEthernetUtilErrorTrap("Rx Error");
			return XST_FAILURE;
	}
	else {

		RxFrameLength =
		(XAxiDma_BdRead(BdCurPtr,XAXIDMA_BD_USR4_OFFSET)) & 0x0000FFFF;
	}

	/* Expected RX TPID+CFI+VID !!! */
	VTagCfiVid = (((u32)Tpid2 << 16) | ((u32)Cfi2 << 12) | RxStrpVid);

	/* Check on the VLAN CFI and VID */
	RxStatusControlWord = XAxiDma_BdGetAppWord(BdPtr,
						BD_VLAN_VID_OFFSET, &Valid);
	if(Valid) {
		RxCfiVid = RxStatusControlWord >> 16;
		RxCfiVid = Xil_Ntohs(RxCfiVid);
		if(RxCfiVid != (VTagCfiVid & 0x0000FFFF)) {
			AxiEthernetUtilErrorTrap("VLAN CFI and VID mismatch\n");
			return XST_FAILURE;
		}
	}
	else {