int is_tx_space_available(xlltemacif_s *emac) { if (XLlTemac_IsDma(&emac->lltemac)) { XLlDma_BdRing *txring = &XLlDma_GetTxRing(&emac->lldma); /* tx space is available as long as there are valid BD's */ return XLlDma_BdRingGetFreeCnt(txring); } else { return ((XLlFifo_TxVacancy(&emac->llfifo) * 4) > XTE_MAX_FRAME_SIZE); } }
/** * * This function demonstrates the usage of the TEMAC by sending and receiving * a single frame in SGDMA interrupt mode. * The source packet will be described by two descriptors. It will be received * into a buffer described by a single descriptor. * * @param TemacInstancePtr is a pointer to the instance of the Temac * component. * * @return XST_SUCCESS to indicate success, otherwise XST_FAILURE. * * @note None. * ******************************************************************************/ int TemacSgDmaIntrSingleFrameExample(XLlTemac * TemacInstancePtr, XLlDma * DmaInstancePtr) { int Status; u32 TxFrameLength; int PayloadSize = 1000; XLlDma_BdRing *RxRingPtr = &XLlDma_GetRxRing(DmaInstancePtr); XLlDma_BdRing *TxRingPtr = &XLlDma_GetTxRing(DmaInstancePtr); XLlDma_Bd *Bd1Ptr; XLlDma_Bd *Bd2Ptr; /* * 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 */ 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); /* * 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); /* * Start the LLTEMAC device and enable the ERROR interrupt */ 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 Bd1Ptr will point to a free BD in the memory * segment setup with the call to XLlTemac_SgSetSpace() */ Status = XLlDma_BdRingAlloc(RxRingPtr, 1, &Bd1Ptr); 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 "last" field of all RxBDs. Therefore we are not required to * issue a XLlDma_Bd_mSetLast(Bd1Ptr) here. */ XLlDma_BdSetBufAddr(Bd1Ptr, &RxFrame); XLlDma_BdSetLength(Bd1Ptr, sizeof(RxFrame)); XLlDma_BdSetStsCtrl(Bd1Ptr, XLLDMA_BD_STSCTRL_SOP_MASK | XLLDMA_BD_STSCTRL_EOP_MASK); /* * Enqueue to HW */ Status = XLlDma_BdRingToHw(RxRingPtr, 1, Bd1Ptr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error committing RxBD to HW"); return XST_FAILURE; } /* * Enable DMA RX interrupt. * * Interrupt coalescing parameters are left at their default settings * which is to interrupt the processor after every frame has been * processed by the DMA engine. */ XLlDma_BdRingIntEnable(RxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK); /* * Start DMA RX channel. Now it's ready to receive data. */ Status = XLlDma_BdRingStart(RxRingPtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Allocate, setup, and enqueue 2 TxBDs. The first BD will describe * the first 32 bytes of TxFrame and the second BD will describe the * rest of the frame. * * The function below will allocate two adjacent BDs with Bd1Ptr being * set as the lead BD. */ Status = XLlDma_BdRingAlloc(TxRingPtr, 2, &Bd1Ptr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error allocating TxBD"); return XST_FAILURE; } /* * Setup TxBD #1 */ XLlDma_BdSetBufAddr(Bd1Ptr, &TxFrame); XLlDma_BdSetLength(Bd1Ptr, 32); XLlDma_BdSetStsCtrl(Bd1Ptr, XLLDMA_BD_STSCTRL_SOP_MASK); /* * Setup TxBD #2 */ Bd2Ptr = XLlDma_BdRingNext(TxRingPtr, Bd1Ptr); XLlDma_BdSetBufAddr(Bd2Ptr, (u32) (&TxFrame) + 32); XLlDma_BdSetLength(Bd2Ptr, TxFrameLength - 32); XLlDma_BdSetStsCtrl(Bd2Ptr, XLLDMA_BD_STSCTRL_EOP_MASK); /* * Enqueue to HW */ Status = XLlDma_BdRingToHw(TxRingPtr, 2, Bd1Ptr); if (Status != XST_SUCCESS) { /* * Undo BD allocation and exit */ XLlDma_BdRingUnAlloc(TxRingPtr, 2, Bd1Ptr); TemacUtilErrorTrap("Error committing TxBD to HW"); return XST_FAILURE; } /* * Enable DMA transmit interrupts */ XLlDma_BdRingIntEnable(TxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK); /* * Start DMA TX channel. Transmission starts at once. */ Status = XLlDma_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 (XLlDma_BdRingFromHw(TxRingPtr, 2, &Bd1Ptr) == 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, 2, Bd1Ptr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error freeing up TxBDs"); return XST_FAILURE; } /* * Wait for Rx indication */ while (!FramesRx); printf("Transmitted Packet!\r\n"); printf("\r\n"); /* * 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, &Bd1Ptr) == 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_BdRead(Bd1Ptr, XLLDMA_BD_USR4_OFFSET) & 0x3FFF) != TxFrameLength) { TemacUtilErrorTrap("Length mismatch"); return XST_FAILURE; } if (TemacUtilFrameVerify(&TxFrame, &RxFrame) != 0) { TemacUtilErrorTrap("Data mismatch"); 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, Bd1Ptr); 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; }
/** * * This function demonstrates the usage usage of the TEMAC by sending by sending * and receiving frames in interrupt driven SGDMA mode. * * * @param IntcInstancePtr is a pointer to the instance of the Intc component. * @param TemacInstancePtr is a pointer to the instance of the Temac * component. * @param TemacDeviceId is Device ID of the Temac Device , typically * XPAR_<TEMAC_instance>_DEVICE_ID value from xparameters.h. * @param TemacIntrId is the Interrupt ID and is typically * XPAR_<INTC_instance>_<TEMAC_instance>_IP2INTC_IRPT_INTR * value from xparameters.h. * * @return XST_SUCCESS to indicate success, otherwise XST_FAILURE. * * @note None. * ******************************************************************************/ int TemacSgDmaIntrExample(XIntc * IntcInstancePtr, XLlTemac * TemacInstancePtr, XLlDma * DmaInstancePtr, u16 TemacDeviceId, u16 TemacIntrId, u16 DmaRxIntrId, u16 DmaTxIntrId) { int Status; u32 Rdy; int dma_mode; XLlTemac_Config *MacCfgPtr; XLlDma_BdRing *RxRingPtr = &XLlDma_GetRxRing(DmaInstancePtr); XLlDma_BdRing *TxRingPtr = &XLlDma_GetTxRing(DmaInstancePtr); XLlDma_Bd BdTemplate; /*************************************/ /* Setup device for first-time usage */ /*************************************/ /* * Initialize instance. Should be configured for SGDMA */ MacCfgPtr = XLlTemac_LookupConfig(TemacDeviceId); Status = XLlTemac_CfgInitialize(TemacInstancePtr, MacCfgPtr, MacCfgPtr->BaseAddress); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error in initialize"); return XST_FAILURE; } XLlDma_Initialize(DmaInstancePtr, TemacInstancePtr->Config.LLDevBaseAddress); /* * Check whether the IPIF interface is correct for this example */ dma_mode = XLlTemac_IsDma(TemacInstancePtr); if (! dma_mode) { TemacUtilErrorTrap ("Device HW not configured for SGDMA mode\r\n"); return XST_FAILURE; } /* * Set the MAC address */ Status = XLlTemac_SetMacAddress(TemacInstancePtr, TemacMAC); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error setting MAC address"); return XST_FAILURE; } /* * Setup RxBD space. * * We have already defined a properly aligned area of memory to store RxBDs * at the beginning of this source code file so just pass its address into * the function. No MMU is being used so the physical and virtual addresses * are the same. * * Setup a BD template for the Rx channel. This template will be copied to * every RxBD. We will not have to explicitly set these again. */ XLlDma_BdClear(&BdTemplate); /* * Create the RxBD ring */ Status = XLlDma_BdRingCreate(RxRingPtr, (u32) &RxBdSpace, (u32) &RxBdSpace, BD_ALIGNMENT, RXBD_CNT); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error setting up RxBD space"); return XST_FAILURE; } Status = XLlDma_BdRingClone(RxRingPtr, &BdTemplate); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error initializing RxBD space"); return XST_FAILURE; } /* * Setup TxBD space. * * Like RxBD space, we have already defined a properly aligned area of * memory to use. */ /* * Create the TxBD ring */ Status = XLlDma_BdRingCreate(TxRingPtr, (u32) &TxBdSpace, (u32) &TxBdSpace, BD_ALIGNMENT, TXBD_CNT); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error setting up TxBD space"); return XST_FAILURE; } /* * We reuse the bd template, as the same one will work for both rx and tx. */ Status = XLlDma_BdRingClone(TxRingPtr, &BdTemplate); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error initializing TxBD space"); return XST_FAILURE; } /* Make sure the hard temac is ready */ Rdy = XLlTemac_ReadReg(TemacInstancePtr->Config.BaseAddress, XTE_RDY_OFFSET); while ((Rdy & XTE_RDY_HARD_ACS_RDY_MASK) == 0) { Rdy = XLlTemac_ReadReg(TemacInstancePtr->Config.BaseAddress, XTE_RDY_OFFSET); } #if !SIM /* * Set PHY to loopback */ TemacUtilEnterLoopback(TemacInstancePtr, TEMAC_LOOPBACK_SPEED); /* * Set PHY<-->MAC data clock */ XLlTemac_SetOperatingSpeed(TemacInstancePtr, TEMAC_LOOPBACK_SPEED); /* * Setting the operating speed of the MAC needs a delay. There * doesn't seem to be register to poll, so please consider this * during your application design. */ TemacUtilPhyDelay(2); #endif /* * Connect to the interrupt controller and enable interrupts */ Status = TemacSetupIntrSystem(IntcInstancePtr, TemacInstancePtr, DmaInstancePtr, TemacIntrId, DmaRxIntrId, DmaTxIntrId); /****************************/ /* Run through the examples */ /****************************/ /* * Run the Temac SGDMA Single Frame Interrupt example */ Status = TemacSgDmaIntrSingleFrameExample(TemacInstancePtr, DmaInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Disable the interrupts for the Temac device */ TemacDisableIntrSystem(IntcInstancePtr, TemacIntrId, DmaRxIntrId, DmaTxIntrId); /* * Stop the device */ XLlTemac_Stop(TemacInstancePtr); return XST_SUCCESS; }
/** * * This function setups the interrupt system so interrupts can occur for the * TEMAC. This function is application-specific since the actual system may or * may not have an interrupt controller. The TEMAC could be directly connected * to a processor without an interrupt controller. The user should modify this * function to fit the application. * * @param IntcInstancePtr is a pointer to the instance of the Intc component. * @param TemacInstancePtr is a pointer to the instance of the Temac * component. * @param TemacIntrId is the Interrupt ID and is typically * XPAR_<INTC_instance>_<TEMAC_instance>_IP2INTC_IRPT_INTR * value from xparameters.h. * * @return XST_SUCCESS if successful, otherwise XST_FAILURE. * * @note None. * ******************************************************************************/ static int TemacSetupIntrSystem(XIntc *IntcInstancePtr, XLlTemac *TemacInstancePtr, XLlDma *DmaInstancePtr, u16 TemacIntrId, u16 DmaRxIntrId, u16 DmaTxIntrId) { XLlDma_BdRing * TxRingPtr = &XLlDma_GetTxRing(DmaInstancePtr); XLlDma_BdRing * RxRingPtr = &XLlDma_GetRxRing(DmaInstancePtr); int Status; #ifndef TESTAPP_GEN /* * Initialize the interrupt controller and connect the ISR */ Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Unable to intialize the interrupt controller"); return XST_FAILURE; } #endif Status = XIntc_Connect(IntcInstancePtr, TemacIntrId, (XInterruptHandler) TemacErrorHandler, TemacInstancePtr); Status |= XIntc_Connect(IntcInstancePtr, DmaTxIntrId, (XInterruptHandler) TxIntrHandler, TxRingPtr); Status |= XIntc_Connect(IntcInstancePtr, DmaRxIntrId, (XInterruptHandler) RxIntrHandler, RxRingPtr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Unable to connect ISR to interrupt controller"); return XST_FAILURE; } #ifndef TESTAPP_GEN /* * Start the interrupt controller */ Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error starting intc"); return XST_FAILURE; } #endif /* * Enable interrupts from the hardware */ XIntc_Enable(IntcInstancePtr, TemacIntrId); XIntc_Enable(IntcInstancePtr, DmaTxIntrId); XIntc_Enable(IntcInstancePtr, DmaRxIntrId); #ifndef TESTAPP_GEN #ifdef __PPC__ /* * Initialize the PPC exception table */ XExc_Init(); /* * Register the interrupt controller with the exception table */ XExc_RegisterHandler(XEXC_ID_NON_CRITICAL_INT, (XExceptionHandler) XIntc_InterruptHandler, IntcInstancePtr); /* * Enable non-critical exceptions */ XExc_mEnableExceptions(XEXC_NON_CRITICAL); #else /* * Connect the interrupt controller interrupt handler to the hardware * interrupt handling logic in the microblaze processor. */ microblaze_register_handler((XInterruptHandler) XIntc_InterruptHandler, IntcInstancePtr); /* * Enable interrupts in the Microblaze */ microblaze_enable_interrupts(); #endif #endif return XST_SUCCESS; }