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(Ð_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; }
/* * * 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(Ð_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 {