/** @file Copyright (c) 2020 Jared McNeill. All rights reserved. Copyright (c) 2020 Andrey Warkentin SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include "BcmGenetDxe.h" #define GENET_PHY_RETRY 1000 STATIC CONST EFI_PHYSICAL_ADDRESS mDmaAddressLimit = FixedPcdGet64 (PcdDmaDeviceLimit) - FixedPcdGet64 (PcdDmaDeviceOffset); /** Read a memory-mapped device CSR. @param Genet[in] Pointer to GENERIC_PHY_PRIVATE_DATA instance. @param Offset[in] Register offset. @retval Value **/ STATIC UINT32 GenetMmioRead ( IN GENET_PRIVATE_DATA *Genet, IN UINT32 Offset ) { ASSERT ((Offset & 3) == 0); return MmioRead32 (Genet->RegBase + Offset); } /** Write a memory-mapped device CSR. @param Genet[in] Pointer to GENERIC_PHY_PRIVATE_DATA instance. @param Offset[in] Register offset. @param Data[in] Data to write. @retval Value **/ STATIC VOID GenetMmioWrite ( IN GENET_PRIVATE_DATA *Genet, IN UINT32 Offset, IN UINT32 Data ) { ASSERT ((Offset & 3) == 0); MemoryFence (); MmioWrite32 (Genet->RegBase + Offset, Data); } /** Perform a GENET PHY register read. @param Priv[in] Pointer to GENET_PRIVATE_DATA. @param PhyAddr[in] PHY address. @param Reg[in] PHY register. @param Data[out] Pointer to register data read. @retval EFI_SUCCESS Data read successfully. @retval EFI_DEVICE_ERROR Failed to read data. **/ EFI_STATUS EFIAPI GenetPhyRead ( IN VOID *Priv, IN UINT8 PhyAddr, IN UINT8 Reg, OUT UINT16 *Data ) { GENET_PRIVATE_DATA *Genet; UINTN Retry; UINT32 Value; Genet = Priv; Value = GENET_MDIO_READ | GENET_MDIO_START_BUSY | SHIFTIN (PhyAddr, GENET_MDIO_PMD) | SHIFTIN (Reg, GENET_MDIO_REG); GenetMmioWrite (Genet, GENET_MDIO_CMD, Value); for (Retry = GENET_PHY_RETRY; Retry > 0; Retry--) { Value = GenetMmioRead (Genet, GENET_MDIO_CMD); if ((Value & GENET_MDIO_START_BUSY) == 0) { *Data = Value & 0xffff; break; } gBS->Stall (10); } if (Retry == 0) { DEBUG ((DEBUG_ERROR, "%a: Timeout reading PhyAddr %d, Reg %d\n", __FUNCTION__, PhyAddr, Reg)); return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } /** Perform a GENET PHY register write. @param Priv[in] Pointer to GENET_PRIVATE_DATA. @param PhyAddr[in] PHY address. @param Reg[in] PHY register. @param Data[in] Pointer to register data to write. @retval EFI_SUCCESS Data written successfully. @retval EFI_DEVICE_ERROR Failed to write data. **/ EFI_STATUS EFIAPI GenetPhyWrite ( IN VOID *Priv, IN UINT8 PhyAddr, IN UINT8 Reg, IN UINT16 Data ) { GENET_PRIVATE_DATA *Genet; UINTN Retry; UINT32 Value; Genet = Priv; Value = GENET_MDIO_WRITE | GENET_MDIO_START_BUSY | SHIFTIN (PhyAddr, GENET_MDIO_PMD) | SHIFTIN (Reg, GENET_MDIO_REG); GenetMmioWrite (Genet, GENET_MDIO_CMD, Value | Data); for (Retry = GENET_PHY_RETRY; Retry > 0; Retry--) { Value = GenetMmioRead (Genet, GENET_MDIO_CMD); if ((Value & GENET_MDIO_START_BUSY) == 0) { break; } gBS->Stall (10); } if (Retry == 0) { DEBUG ((DEBUG_ERROR, "%a: Timeout writing PhyAddr %d, Reg %d\n", __FUNCTION__, PhyAddr, Reg)); return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } /** Process a PHY link speed change (e.g. with MAC layer). @param Priv[in] Pointer to GENET_PRIVATE_DATA. @param Speed[in] Speed setting. @param Duplex[in] Duplex setting. **/ VOID EFIAPI GenetPhyConfigure ( IN VOID *Priv, IN GENERIC_PHY_SPEED Speed, IN GENERIC_PHY_DUPLEX Duplex ) { GENET_PRIVATE_DATA *Genet; UINT32 Value; Genet = Priv; Value = GenetMmioRead (Genet, GENET_EXT_RGMII_OOB_CTRL); Value &= ~GENET_EXT_RGMII_OOB_OOB_DISABLE; Value |= GENET_EXT_RGMII_OOB_RGMII_LINK; Value |= GENET_EXT_RGMII_OOB_RGMII_MODE_EN; if (Genet->PhyMode == GENET_PHY_MODE_RGMII) { Value |= GENET_EXT_RGMII_OOB_ID_MODE_DISABLE; } else { Value &= ~GENET_EXT_RGMII_OOB_ID_MODE_DISABLE; } GenetMmioWrite (Genet, GENET_EXT_RGMII_OOB_CTRL, Value); Value = GenetMmioRead (Genet, GENET_UMAC_CMD); Value &= ~GENET_UMAC_CMD_SPEED; switch (Speed) { case PHY_SPEED_1000: Value |= SHIFTIN (GENET_UMAC_CMD_SPEED_1000, GENET_UMAC_CMD_SPEED); break; case PHY_SPEED_100: Value |= SHIFTIN (GENET_UMAC_CMD_SPEED_100, GENET_UMAC_CMD_SPEED); break; default: Value |= SHIFTIN (GENET_UMAC_CMD_SPEED_10, GENET_UMAC_CMD_SPEED); break; } if (Duplex == PHY_DUPLEX_FULL) { Value &= ~GENET_UMAC_CMD_HD_EN; } else { Value |= GENET_UMAC_CMD_HD_EN; } GenetMmioWrite (Genet, GENET_UMAC_CMD, Value); } /** Extra action to run after a PHY reset. This adds the appropriate clock delay based on the PHY mode. @param Priv[in] Pointer to GENET_PRIVATE_DATA. **/ EFI_STATUS EFIAPI GenetPhyResetAction ( IN VOID *Priv ) { GENET_PRIVATE_DATA *Genet; UINT16 Value; EFI_STATUS Status; Genet = Priv; Status = GenetPhyWrite (Priv, Genet->Phy.PhyAddr, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_SHADOW_MISC | (BRGPHY_AUXCTL_SHADOW_MISC << BRGPHY_AUXCTL_MISC_READ_SHIFT)); if (EFI_ERROR (Status)) { return Status; } Status = GenetPhyRead (Priv, Genet->Phy.PhyAddr, BRGPHY_MII_AUXCTL, &Value); if (EFI_ERROR (Status)) { return Status; } Value &= BRGPHY_AUXCTL_MISC_DATA_MASK; if (Genet->PhyMode == GENET_PHY_MODE_RGMII_RXID || Genet->PhyMode == GENET_PHY_MODE_RGMII_ID) { Value |= BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN; } else { Value &= ~BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN; } Status = GenetPhyWrite (Priv, Genet->Phy.PhyAddr, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_MISC_WRITE_EN | BRGPHY_AUXCTL_SHADOW_MISC | Value); if (EFI_ERROR (Status)) { return Status; } Status = GenetPhyWrite (Priv, Genet->Phy.PhyAddr, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_CLK_CTRL); if (EFI_ERROR (Status)) { return Status; } Status = GenetPhyRead (Priv, Genet->Phy.PhyAddr, BRGPHY_MII_SHADOW_1C, &Value); if (EFI_ERROR (Status)) { return Status; } Value &= BRGPHY_SHADOW_1C_DATA_MASK; if (Genet->PhyMode == GENET_PHY_MODE_RGMII_TXID || Genet->PhyMode == GENET_PHY_MODE_RGMII_ID) { Value |= BRGPHY_SHADOW_1C_GTXCLK_EN; } else { Value &= ~BRGPHY_SHADOW_1C_GTXCLK_EN; } Status = GenetPhyWrite (Priv, Genet->Phy.PhyAddr, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_WRITE_EN | BRGPHY_SHADOW_1C_CLK_CTRL | Value); if (EFI_ERROR (Status)) { return Status; } return EFI_SUCCESS; } /** Reset GENET. @param Genet[in] Pointer to GENET_PRIVATE_DATA. **/ VOID GenetReset ( IN GENET_PRIVATE_DATA *Genet ) { UINT32 Value; Value = GenetMmioRead (Genet, GENET_SYS_RBUF_FLUSH_CTRL); Value |= GENET_SYS_RBUF_FLUSH_RESET; GenetMmioWrite (Genet, GENET_SYS_RBUF_FLUSH_CTRL, Value); gBS->Stall (10); Value &= ~GENET_SYS_RBUF_FLUSH_RESET; GenetMmioWrite (Genet, GENET_SYS_RBUF_FLUSH_CTRL, Value); gBS->Stall (10); GenetMmioWrite (Genet, GENET_SYS_RBUF_FLUSH_CTRL, 0); gBS->Stall (10); GenetMmioWrite (Genet, GENET_UMAC_CMD, 0); GenetMmioWrite (Genet, GENET_UMAC_CMD, GENET_UMAC_CMD_LCL_LOOP_EN | GENET_UMAC_CMD_SW_RESET); gBS->Stall (10); GenetMmioWrite (Genet, GENET_UMAC_CMD, 0); GenetMmioWrite (Genet, GENET_UMAC_MIB_CTRL, GENET_UMAC_MIB_RESET_RUNT | GENET_UMAC_MIB_RESET_RX | GENET_UMAC_MIB_RESET_TX); GenetMmioWrite (Genet, GENET_UMAC_MIB_CTRL, 0); GenetMmioWrite (Genet, GENET_UMAC_MAX_FRAME_LEN, GENET_MAX_PACKET_SIZE); Value = GenetMmioRead (Genet, GENET_RBUF_CTRL); Value |= GENET_RBUF_ALIGN_2B; GenetMmioWrite (Genet, GENET_RBUF_CTRL, Value); GenetMmioWrite (Genet, GENET_RBUF_TBUF_SIZE_CTRL, 1); } /** Set the station address. @param Genet[in] Pointer to GENET_PRIVATE_DATA. @param MacAddr[in] MAC address to set. **/ VOID EFIAPI GenetSetMacAddress ( IN GENET_PRIVATE_DATA *Genet, IN EFI_MAC_ADDRESS *MacAddr ) { UINT32 Value; Value = MacAddr->Addr[3] | MacAddr->Addr[2] << 8 | MacAddr->Addr[1] << 16 | MacAddr->Addr[0] << 24; GenetMmioWrite (Genet, GENET_UMAC_MAC0, Value); Value = MacAddr->Addr[5] | MacAddr->Addr[4] << 8; GenetMmioWrite (Genet, GENET_UMAC_MAC1, Value); } /** Set a PHY mode. @param Genet[in] Pointer to GENET_PRIVATE_DATA. @param PhyMode[in] Mode to set. **/ VOID GenetSetPhyMode ( IN GENET_PRIVATE_DATA *Genet, IN GENET_PHY_MODE PhyMode ) { UINT32 Value; switch (PhyMode) { case GENET_PHY_MODE_RGMII: case GENET_PHY_MODE_RGMII_RXID: case GENET_PHY_MODE_RGMII_TXID: case GENET_PHY_MODE_RGMII_ID: Value = GENET_SYS_PORT_MODE_EXT_GPHY; break; default: Value = 0; break; } GenetMmioWrite (Genet, GENET_SYS_PORT_CTRL, Value); } /** Enable TX/RX. @param Genet[in] Pointer to GENET_PRIVATE_DATA. **/ VOID GenetEnableTxRx ( IN GENET_PRIVATE_DATA *Genet ) { UINT32 Value; // Start TX DMA on default queue Value = GenetMmioRead (Genet, GENET_TX_DMA_CTRL); Value |= GENET_TX_DMA_CTRL_EN | GENET_TX_DMA_CTRL_RBUF_EN (GENET_DMA_DEFAULT_QUEUE); GenetMmioWrite (Genet, GENET_TX_DMA_CTRL, Value); // Start RX DMA on default queue Value = GenetMmioRead (Genet, GENET_RX_DMA_CTRL); Value |= GENET_RX_DMA_CTRL_EN | GENET_RX_DMA_CTRL_RBUF_EN (GENET_DMA_DEFAULT_QUEUE); GenetMmioWrite (Genet, GENET_RX_DMA_CTRL, Value); // Enable transmitter and receiver Value = GenetMmioRead (Genet, GENET_UMAC_CMD); Value |= GENET_UMAC_CMD_TXEN | GENET_UMAC_CMD_RXEN; GenetMmioWrite (Genet, GENET_UMAC_CMD, Value); // Enable interrupts GenetMmioWrite (Genet, GENET_INTRL2_CPU_CLEAR_MASK, GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE); } /** Disable TX/RX. @param Genet[in] Pointer to GENET_PRIVATE_DATA. **/ VOID GenetDisableTxRx ( IN GENET_PRIVATE_DATA *Genet ) { UINT32 Value; // Disable interrupts GenetMmioWrite (Genet, GENET_INTRL2_CPU_SET_MASK, 0xFFFFFFFF); GenetMmioWrite (Genet, GENET_INTRL2_CPU_CLEAR, 0xFFFFFFFF); // Disable receiver Value = GenetMmioRead (Genet, GENET_UMAC_CMD); Value &= ~GENET_UMAC_CMD_RXEN; GenetMmioWrite (Genet, GENET_UMAC_CMD, Value); // Stop RX DMA Value = GenetMmioRead (Genet, GENET_RX_DMA_CTRL); Value &= ~GENET_RX_DMA_CTRL_EN; Value &= ~GENET_RX_DMA_CTRL_RBUF_EN (GENET_DMA_DEFAULT_QUEUE); GenetMmioWrite (Genet, GENET_RX_DMA_CTRL, Value); // Stop TX DMA Value = GenetMmioRead (Genet, GENET_TX_DMA_CTRL); Value &= ~GENET_TX_DMA_CTRL_EN; Value &= ~GENET_TX_DMA_CTRL_RBUF_EN (GENET_DMA_DEFAULT_QUEUE); GenetMmioWrite (Genet, GENET_TX_DMA_CTRL, Value); // Flush data in the TX FIFO GenetMmioWrite (Genet, GENET_UMAC_TX_FLUSH, 1); gBS->Stall (10); GenetMmioWrite (Genet, GENET_UMAC_TX_FLUSH, 0); // Disable transmitter Value = GenetMmioRead (Genet, GENET_UMAC_CMD); Value &= ~GENET_UMAC_CMD_TXEN; GenetMmioWrite (Genet, GENET_UMAC_CMD, Value); } /** Change promiscuous mode state. @param Genet[in] Pointer to GENET_PRIVATE_DATA. @param Enable[in] Promiscuous mode state. **/ VOID GenetSetPromisc ( IN GENET_PRIVATE_DATA *Genet, IN BOOLEAN Enable ) { UINT32 Value; Value = GenetMmioRead (Genet, GENET_UMAC_CMD); if (Enable) { Value |= GENET_UMAC_CMD_PROMISC; } else { Value &= ~GENET_UMAC_CMD_PROMISC; } GenetMmioWrite (Genet, GENET_UMAC_CMD, Value); } /** Enable the MAC filter for the Ethernet broadcast address @param Genet[in] Pointer to GENET_PRIVATE_DATA. @param Enable[in] Promiscuous mode state. **/ VOID GenetEnableBroadcastFilter ( IN GENET_PRIVATE_DATA *Genet, IN BOOLEAN Enable ) { CONST EFI_MAC_ADDRESS *MacAddr; UINT32 Value; if (Enable) { MacAddr = &Genet->SnpMode.CurrentAddress; GenetMmioWrite (Genet, GENET_UMAC_MDF_ADDR0 (0), MacAddr->Addr[1] | MacAddr->Addr[0] << 8); GenetMmioWrite (Genet, GENET_UMAC_MDF_ADDR1 (0), MacAddr->Addr[5] | MacAddr->Addr[4] << 8 | MacAddr->Addr[3] << 16 | MacAddr->Addr[2] << 24); GenetMmioWrite (Genet, GENET_UMAC_MDF_ADDR0 (1), 0xffff); GenetMmioWrite (Genet, GENET_UMAC_MDF_ADDR1 (1), 0xffffffff); Value = BIT16 | BIT15; // enable filters 0 and 1 } else { Value = 0; } GenetMmioWrite (Genet, GENET_UMAC_MDF_CTRL, Value); } /** Configure DMA TX and RX queues, enabling them. @param Genet[in] Pointer to GENET_PRIVATE_DATA. **/ VOID GenetDmaInitRings ( IN GENET_PRIVATE_DATA *Genet ) { UINT8 Qid; Qid = GENET_DMA_DEFAULT_QUEUE; Genet->TxQueued = 0; Genet->TxNext = 0; Genet->TxConsIndex = 0; Genet->TxProdIndex = 0; Genet->RxConsIndex = 0; Genet->RxProdIndex = 0; // Configure TX queue GenetMmioWrite (Genet, GENET_TX_SCB_BURST_SIZE, 0x08); GenetMmioWrite (Genet, GENET_TX_DMA_READ_PTR_LO (Qid), 0); GenetMmioWrite (Genet, GENET_TX_DMA_READ_PTR_HI (Qid), 0); GenetMmioWrite (Genet, GENET_TX_DMA_CONS_INDEX (Qid), 0); GenetMmioWrite (Genet, GENET_TX_DMA_PROD_INDEX (Qid), 0); GenetMmioWrite (Genet, GENET_TX_DMA_RING_BUF_SIZE (Qid), SHIFTIN (GENET_DMA_DESC_COUNT, GENET_TX_DMA_RING_BUF_SIZE_DESC_COUNT) | SHIFTIN (GENET_MAX_PACKET_SIZE, GENET_TX_DMA_RING_BUF_SIZE_BUF_LENGTH)); GenetMmioWrite (Genet, GENET_TX_DMA_START_ADDR_LO (Qid), 0); GenetMmioWrite (Genet, GENET_TX_DMA_START_ADDR_HI (Qid), 0); GenetMmioWrite (Genet, GENET_TX_DMA_END_ADDR_LO (Qid), GENET_DMA_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1); GenetMmioWrite (Genet, GENET_TX_DMA_END_ADDR_HI (Qid), 0); GenetMmioWrite (Genet, GENET_TX_DMA_MBUF_DONE_THRES (Qid), 1); GenetMmioWrite (Genet, GENET_TX_DMA_FLOW_PERIOD (Qid), 0); GenetMmioWrite (Genet, GENET_TX_DMA_WRITE_PTR_LO (Qid), 0); GenetMmioWrite (Genet, GENET_TX_DMA_WRITE_PTR_HI (Qid), 0); // Enable TX queue GenetMmioWrite (Genet, GENET_TX_DMA_RING_CFG, (1U << Qid)); // Configure RX queue GenetMmioWrite (Genet, GENET_RX_SCB_BURST_SIZE, 0x08); GenetMmioWrite (Genet, GENET_RX_DMA_WRITE_PTR_LO (Qid), 0); GenetMmioWrite (Genet, GENET_RX_DMA_WRITE_PTR_HI (Qid), 0); GenetMmioWrite (Genet, GENET_RX_DMA_PROD_INDEX (Qid), 0); GenetMmioWrite (Genet, GENET_RX_DMA_CONS_INDEX (Qid), 0); GenetMmioWrite (Genet, GENET_RX_DMA_RING_BUF_SIZE (Qid), SHIFTIN (GENET_DMA_DESC_COUNT, GENET_RX_DMA_RING_BUF_SIZE_DESC_COUNT) | SHIFTIN (GENET_MAX_PACKET_SIZE, GENET_RX_DMA_RING_BUF_SIZE_BUF_LENGTH)); GenetMmioWrite (Genet, GENET_RX_DMA_START_ADDR_LO (Qid), 0); GenetMmioWrite (Genet, GENET_RX_DMA_START_ADDR_HI (Qid), 0); GenetMmioWrite (Genet, GENET_RX_DMA_END_ADDR_LO (Qid), GENET_DMA_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1); GenetMmioWrite (Genet, GENET_RX_DMA_END_ADDR_HI (Qid), 0); GenetMmioWrite (Genet, GENET_RX_DMA_XON_XOFF_THRES (Qid), SHIFTIN (5, GENET_RX_DMA_XON_XOFF_THRES_LO) | SHIFTIN (GENET_DMA_DESC_COUNT >> 4, GENET_RX_DMA_XON_XOFF_THRES_HI)); GenetMmioWrite (Genet, GENET_RX_DMA_READ_PTR_LO (Qid), 0); GenetMmioWrite (Genet, GENET_RX_DMA_READ_PTR_HI (Qid), 0); // Enable RX queue GenetMmioWrite (Genet, GENET_RX_DMA_RING_CFG, (1U << Qid)); } /** Allocate DMA buffers for RX. @param Genet[in] Pointer to GENET_PRIVATE_DATA. @retval EFI_SUCCESS DMA buffers allocated. @retval EFI_OUT_OF_RESOURCES DMA buffers could not be allocated. **/ EFI_STATUS GenetDmaAlloc ( IN GENET_PRIVATE_DATA *Genet ) { EFI_STATUS Status; Genet->RxBuffer = mDmaAddressLimit; Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES (GENET_MAX_PACKET_SIZE * GENET_DMA_DESC_COUNT), &Genet->RxBuffer); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Failed to allocate RX buffer: %r\n", __FUNCTION__, Status)); } return Status; } /** Given an RX buffer descriptor index, program the IO address of the buffer into the hardware. @param Genet[in] Pointer to GENET_PRIVATE_DATA. @param DescIndex[in] Index of RX buffer descriptor. @retval EFI_SUCCESS DMA buffers allocated. @retval Others Programmatic errors, as buffers come from DmaAllocateBuffer, and thus cannot fail DmaMap (for the expected NonCoherentDmaLib). **/ EFI_STATUS GenetDmaMapRxDescriptor ( IN GENET_PRIVATE_DATA * Genet, IN UINT8 DescIndex ) { EFI_STATUS Status; UINTN DmaNumberOfBytes; ASSERT (Genet->RxBufferMap[DescIndex].Mapping == NULL); ASSERT (Genet->RxBuffer != 0); DmaNumberOfBytes = GENET_MAX_PACKET_SIZE; Status = DmaMap (MapOperationBusMasterWrite, GENET_RX_BUFFER (Genet, DescIndex), &DmaNumberOfBytes, &Genet->RxBufferMap[DescIndex].PhysAddress, &Genet->RxBufferMap[DescIndex].Mapping); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Failed to map RX buffer: %r\n", __FUNCTION__, Status)); return Status; } GenetMmioWrite (Genet, GENET_RX_DESC_ADDRESS_LO (DescIndex), Genet->RxBufferMap[DescIndex].PhysAddress & 0xFFFFFFFF); GenetMmioWrite (Genet, GENET_RX_DESC_ADDRESS_HI (DescIndex), (Genet->RxBufferMap[DescIndex].PhysAddress >> 32) & 0xFFFFFFFF); GenetMmioWrite (Genet, GENET_RX_DESC_STATUS (DescIndex), 0); return EFI_SUCCESS; } /** Given an RX buffer descriptor index, undo the DmaMap operation on the buffer. @param Genet[in] Pointer to GENET_PRIVATE_DATA. @param DescIndex[in] Index of RX buffer descriptor. **/ VOID GenetDmaUnmapRxDescriptor ( IN GENET_PRIVATE_DATA * Genet, IN UINT8 DescIndex ) { if (Genet->RxBufferMap[DescIndex].Mapping != NULL) { DmaUnmap (Genet->RxBufferMap[DescIndex].Mapping); Genet->RxBufferMap[DescIndex].Mapping = NULL; } } /** Free DMA buffers for RX, undoing GenetDmaAlloc. @param Genet[in] Pointer to GENET_PRIVATE_DATA. @param DescIndex[in] Index of RX buffer descriptor. **/ VOID GenetDmaFree ( IN GENET_PRIVATE_DATA *Genet ) { UINTN Idx; for (Idx = 0; Idx < GENET_DMA_DESC_COUNT; Idx++) { GenetDmaUnmapRxDescriptor (Genet, Idx); } gBS->FreePages (Genet->RxBuffer, EFI_SIZE_TO_PAGES (GENET_MAX_PACKET_SIZE * GENET_DMA_DESC_COUNT)); } /** Queue TX transmission, given a buffer to transmit and a TX descriptor index. @param Genet[in] Pointer to GENET_PRIVATE_DATA. @param DescIndex[in] TX descriptor index. @param PhysAddr[in] Buffer to transmit. @param NumberOfBytes[in] Buffer length. **/ VOID GenetDmaTriggerTx ( IN GENET_PRIVATE_DATA * Genet, IN UINT8 DescIndex, IN EFI_PHYSICAL_ADDRESS PhysAddr, IN UINTN NumberOfBytes ) { UINT32 DescStatus; DescStatus = GENET_TX_DESC_STATUS_SOP | GENET_TX_DESC_STATUS_EOP | GENET_TX_DESC_STATUS_CRC | GENET_TX_DESC_STATUS_QTAG | SHIFTIN (NumberOfBytes, GENET_TX_DESC_STATUS_BUFLEN); GenetMmioWrite (Genet, GENET_TX_DESC_ADDRESS_LO (DescIndex), PhysAddr & 0xFFFFFFFF); GenetMmioWrite (Genet, GENET_TX_DESC_ADDRESS_HI (DescIndex), (PhysAddr >> 32) & 0xFFFFFFFF); GenetMmioWrite (Genet, GENET_TX_DESC_STATUS (DescIndex), DescStatus); GenetMmioWrite (Genet, GENET_TX_DMA_PROD_INDEX (GENET_DMA_DEFAULT_QUEUE), Genet->TxProdIndex); } /** Simulate a "TX interrupt", return the next (completed) TX buffer to recycle. @param Genet[in] Pointer to GENET_PRIVATE_DATA. @param TxBuf[out] Location to store pointer to next TX buffer to recycle. **/ VOID GenetTxIntr ( IN GENET_PRIVATE_DATA *Genet, OUT VOID **TxBuf ) { UINT32 Total; Total = GenetTxPending (Genet); if (Genet->TxQueued > 0 && Total > 0) { DmaUnmap (Genet->TxBufferMap[Genet->TxNext]); *TxBuf = Genet->TxBuffer[Genet->TxNext]; Genet->TxQueued--; Genet->TxNext = (Genet->TxNext + 1) % GENET_DMA_DESC_COUNT; Genet->TxConsIndex = (Genet->TxConsIndex + 1) & 0xFFFF; } else { *TxBuf = NULL; } } UINT32 GenetRxPending ( IN GENET_PRIVATE_DATA *Genet ) { UINT32 ProdIndex; UINT32 ConsIndex; ConsIndex = GenetMmioRead (Genet, GENET_RX_DMA_CONS_INDEX (GENET_DMA_DEFAULT_QUEUE)) & 0xFFFF; ASSERT (ConsIndex == Genet->RxConsIndex); ProdIndex = GenetMmioRead (Genet, GENET_RX_DMA_PROD_INDEX (GENET_DMA_DEFAULT_QUEUE)) & 0xFFFF; return (ProdIndex - Genet->RxConsIndex) & 0xFFFF; } UINT32 GenetTxPending ( IN GENET_PRIVATE_DATA *Genet ) { UINT32 ConsIndex; ConsIndex = GenetMmioRead (Genet, GENET_TX_DMA_CONS_INDEX (GENET_DMA_DEFAULT_QUEUE)) & 0xFFFF; return (ConsIndex - Genet->TxConsIndex) & 0xFFFF; } VOID GenetRxComplete ( IN GENET_PRIVATE_DATA *Genet ) { Genet->RxConsIndex = (Genet->RxConsIndex + 1) & 0xFFFF; GenetMmioWrite (Genet, GENET_RX_DMA_CONS_INDEX (GENET_DMA_DEFAULT_QUEUE), Genet->RxConsIndex); } /** Simulate an "RX interrupt", returning the index of a completed RX buffer and corresponding frame length. @param Genet[in] Pointer to GENET_PRIVATE_DATA. @param DescIndex[out] Location to store completed RX buffer index. @param FrameLength[out] Location to store frame length. @retval EFI_SUCCESS Data received. @retval EFI_NOT_READY No RX buffers ready as no data received. **/ EFI_STATUS GenetRxIntr ( IN GENET_PRIVATE_DATA *Genet, OUT UINT8 *DescIndex, OUT UINTN *FrameLength ) { EFI_STATUS Status; UINT32 Total; UINT32 DescStatus; Total = GenetRxPending (Genet); if (Total > 0) { *DescIndex = Genet->RxConsIndex % GENET_DMA_DESC_COUNT; DescStatus = GenetMmioRead (Genet, GENET_RX_DESC_STATUS (*DescIndex)); *FrameLength = SHIFTOUT (DescStatus, GENET_RX_DESC_STATUS_BUFLEN); Status = EFI_SUCCESS; } else { Status = EFI_NOT_READY; } return Status; }