* [PATCH edk2-platforms v3 3/8] Silicon/Broadcom/BcmGenetDxe: Add GENET driver
2020-05-12 16:41 [PATCH edk2-platforms v3 0/8] Add Broadcom GENET driver for RPi4 Ard Biesheuvel
2020-05-12 16:41 ` [PATCH edk2-platforms v3 1/8] Platform/RaspberryPi4: set DMA translation for BCM Genet driver Ard Biesheuvel
2020-05-12 16:41 ` [PATCH edk2-platforms v3 2/8] Silicon/Broadcom: Add BcmGenetPlatformDevice protocol Ard Biesheuvel
@ 2020-05-12 16:41 ` Ard Biesheuvel
2020-05-12 16:41 ` [PATCH edk2-platforms v3 4/8] Platform/RaspberryPi4: Clean up PCDs out of the " Ard Biesheuvel
` (5 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Ard Biesheuvel @ 2020-05-12 16:41 UTC (permalink / raw)
To: devel; +Cc: leif, philmd, Ard Biesheuvel
Add support for the Broadcom GENET v5 ethernet controller
for the Raspberry Pi 4 (BCM2711)
Co-authored-by: Jared McNeill <jmcneill@invisible.ca>
Co-authored-by: Andrei Warkentin <awarkentin@vmware.com>
Co-authored-by: Samer El-Haj-Mahmoud <samer.el-haj-mahmoud@arm.com>
Co-authored-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
---
Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf | 46 +-
Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.h | 363 +++++++++
Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.h | 133 ++++
Silicon/Broadcom/Drivers/Net/BcmGenetDxe/ComponentName.c | 202 +++++
Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c | 408 ++++++++++
Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.c | 404 ++++++++++
Silicon/Broadcom/Drivers/Net/BcmGenetDxe/Genet.c | 114 ---
Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c | 814 +++++++++++++++++++
Silicon/Broadcom/Drivers/Net/BcmGenetDxe/SimpleNetwork.c | 838 ++++++++++++++++++++
9 files changed, 3195 insertions(+), 127 deletions(-)
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf
index 9e9301608f24..28f3e66ebaf0 100644
--- a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf
+++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf
@@ -1,40 +1,60 @@
## @file
+# Component description file for Broadcom GENET driver.
#
+# Copyright (c) 2020, Jared McNeill All rights reserved.<BR>
# Copyright (c) 2020, Jeremy Linton All rights reserved.<BR>
+# Copyright (c) 2020, ARM Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[Defines]
- INF_VERSION = 0x0001001A
+ INF_VERSION = 1.27
BASE_NAME = BcmGenetDxe
FILE_GUID = e2b1eaf3-50b7-4ae1-b79e-ec8020cb57ac
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 0.1
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
ENTRY_POINT = GenetEntryPoint
+ UNLOAD_IMAGE = GenetUnload
[Sources]
- Genet.c
+ BcmGenetDxe.h
+ ComponentName.c
+ DriverBinding.c
+ GenericPhy.c
+ GenericPhy.h
+ GenetUtil.c
+ SimpleNetwork.c
[Packages]
- ArmPkg/ArmPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
+ NetworkPkg/NetworkPkg.dec
Silicon/Broadcom/Drivers/Net/BcmNet.dec
[LibraryClasses]
- ArmLib
BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ DmaLib
IoLib
+ MemoryAllocationLib
+ NetLib
+ UefiBootServicesTableLib
UefiDriverEntryPoint
UefiLib
+[Protocols]
+ gBcmGenetPlatformDeviceProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiSimpleNetworkProtocolGuid ## BY_START
+
+[Guids]
+ gEfiEventExitBootServicesGuid
+
[FixedPcd]
- gBcmNetTokenSpaceGuid.PcdBcmGenetRegistersAddress
-
-[Pcd]
- gBcmNetTokenSpaceGuid.PcdBcmGenetMacAddress
-
-[Depex]
- TRUE
+ gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset
+ gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.h b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.h
new file mode 100644
index 000000000000..0af9d5209cf2
--- /dev/null
+++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.h
@@ -0,0 +1,363 @@
+/** @file
+
+ Copyright (c) 2020 Jared McNeill <jmcneill@invisible.ca>
+ Copyright (c) 2020, ARM Limited. All rights reserved.
+ Copyright (c) 2020 Andrey Warkentin <andrey.warkentin@gmail.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef BCM_GENET_DXE_H__
+#define BCM_GENET_DXE_H__
+
+#include <Uefi.h>
+#include <Library/UefiLib.h>
+#include <Protocol/BcmGenetPlatformDevice.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/SimpleNetwork.h>
+
+#include "GenericPhy.h"
+
+#define LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ (__mask))
+#define SHIFTOUT(__x, __mask) (((__x) & (__mask)) / LOWEST_SET_BIT (__mask))
+#define SHIFTIN(__x, __mask) ((__x) * LOWEST_SET_BIT (__mask))
+
+/*
+ * Aux control shadow register, bits 0-2 select function (0x00 to
+ * 0x07).
+ */
+#define BRGPHY_MII_AUXCTL 0x18 /* AUX control */
+#define BRGPHY_AUXCTL_SHADOW_MISC 0x07
+#define BRGPHY_AUXCTL_MISC_DATA_MASK 0x7ff8
+#define BRGPHY_AUXCTL_MISC_READ_SHIFT 12
+#define BRGPHY_AUXCTL_MISC_WRITE_EN 0x8000
+#define BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN 0x0200
+
+/*
+ * Shadow register 0x1C, bit 15 is write enable,
+ * bits 14-10 select function (0x00 to 0x1F).
+ */
+#define BRGPHY_MII_SHADOW_1C 0x1C
+#define BRGPHY_SHADOW_1C_WRITE_EN 0x8000
+#define BRGPHY_SHADOW_1C_SELECT_MASK 0x7C00
+#define BRGPHY_SHADOW_1C_DATA_MASK 0x03FF
+
+/* Shadow 0x1C Clock Alignment Control Register (select value 0x03) */
+#define BRGPHY_SHADOW_1C_CLK_CTRL (0x03 << 10)
+#define BRGPHY_SHADOW_1C_GTXCLK_EN 0x0200
+
+#define MAX_ETHERNET_PKT_SIZE 1500
+
+#define GENET_VERSION 0x0a
+#define GENET_MAX_PACKET_SIZE 1536
+
+#define GENET_SYS_REV_CTRL 0x000
+#define SYS_REV_MAJOR (BIT27|BIT26|BIT25|BIT24)
+#define SYS_REV_MINOR (BIT19|BIT18|BIT17|BIT16)
+#define GENET_SYS_PORT_CTRL 0x004
+#define GENET_SYS_PORT_MODE_EXT_GPHY 3
+#define GENET_SYS_RBUF_FLUSH_CTRL 0x008
+#define GENET_SYS_RBUF_FLUSH_RESET BIT1
+#define GENET_SYS_TBUF_FLUSH_CTRL 0x00c
+#define GENET_EXT_RGMII_OOB_CTRL 0x08c
+#define GENET_EXT_RGMII_OOB_ID_MODE_DISABLE BIT16
+#define GENET_EXT_RGMII_OOB_RGMII_MODE_EN BIT6
+#define GENET_EXT_RGMII_OOB_OOB_DISABLE BIT5
+#define GENET_EXT_RGMII_OOB_RGMII_LINK BIT4
+#define GENET_INTRL2_CPU_STAT 0x200
+#define GENET_INTRL2_CPU_CLEAR 0x208
+#define GENET_INTRL2_CPU_STAT_MASK 0x20c
+#define GENET_INTRL2_CPU_SET_MASK 0x210
+#define GENET_INTRL2_CPU_CLEAR_MASK 0x214
+#define GENET_IRQ_MDIO_ERROR BIT24
+#define GENET_IRQ_MDIO_DONE BIT23
+#define GENET_IRQ_TXDMA_DONE BIT16
+#define GENET_IRQ_RXDMA_DONE BIT13
+#define GENET_RBUF_CTRL 0x300
+#define GENET_RBUF_BAD_DIS BIT2
+#define GENET_RBUF_ALIGN_2B BIT1
+#define GENET_RBUF_64B_EN BIT0
+#define GENET_RBUF_TBUF_SIZE_CTRL 0x3b4
+#define GENET_UMAC_CMD 0x808
+#define GENET_UMAC_CMD_LCL_LOOP_EN BIT15
+#define GENET_UMAC_CMD_SW_RESET BIT13
+#define GENET_UMAC_CMD_HD_EN BIT10
+#define GENET_UMAC_CMD_PROMISC BIT4
+#define GENET_UMAC_CMD_SPEED (BIT3|BIT2)
+#define GENET_UMAC_CMD_SPEED_10 0
+#define GENET_UMAC_CMD_SPEED_100 1
+#define GENET_UMAC_CMD_SPEED_1000 2
+#define GENET_UMAC_CMD_RXEN BIT1
+#define GENET_UMAC_CMD_TXEN BIT0
+#define GENET_UMAC_MAC0 0x80c
+#define GENET_UMAC_MAC1 0x810
+#define GENET_UMAC_MAX_FRAME_LEN 0x814
+#define GENET_UMAC_TX_FLUSH 0xb34
+#define GENET_UMAC_MIB_CTRL 0xd80
+#define GENET_UMAC_MIB_RESET_TX BIT2
+#define GENET_UMAC_MIB_RESET_RUNT BIT1
+#define GENET_UMAC_MIB_RESET_RX BIT0
+#define GENET_MDIO_CMD 0xe14
+#define GENET_MDIO_START_BUSY BIT29
+#define GENET_MDIO_READ BIT27
+#define GENET_MDIO_WRITE BIT26
+#define GENET_MDIO_PMD (BIT25|BIT24|BIT23|BIT22|BIT21)
+#define GENET_MDIO_REG (BIT20|BIT19|BIT18|BIT17|BIT16)
+#define GENET_UMAC_MDF_CTRL 0xe50
+#define GENET_UMAC_MDF_ADDR0(n) (0xe54 + (n) * 0x8)
+#define GENET_UMAC_MDF_ADDR1(n) (0xe58 + (n) * 0x8)
+#define GENET_MAX_MDF_FILTER 17
+
+#define GENET_DMA_DESC_COUNT 256
+#define GENET_DMA_DESC_SIZE 12
+#define GENET_DMA_DEFAULT_QUEUE 16
+
+#define GENET_DMA_RING_SIZE 0x40
+#define GENET_DMA_RINGS_SIZE (GENET_DMA_RING_SIZE * (GENET_DMA_DEFAULT_QUEUE + 1))
+
+#define GENET_RX_BASE 0x2000
+#define GENET_TX_BASE 0x4000
+
+#define GENET_RX_DMA_RINGBASE(qid) (GENET_RX_BASE + 0xc00 + GENET_DMA_RING_SIZE * (qid))
+#define GENET_RX_DMA_WRITE_PTR_LO(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x00)
+#define GENET_RX_DMA_WRITE_PTR_HI(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x04)
+#define GENET_RX_DMA_PROD_INDEX(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x08)
+#define GENET_RX_DMA_CONS_INDEX(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x0c)
+#define GENET_RX_DMA_RING_BUF_SIZE(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x10)
+#define GENET_RX_DMA_RING_BUF_SIZE_DESC_COUNT 0xffff0000
+#define GENET_RX_DMA_RING_BUF_SIZE_BUF_LENGTH 0x0000ffff
+#define GENET_RX_DMA_START_ADDR_LO(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x14)
+#define GENET_RX_DMA_START_ADDR_HI(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x18)
+#define GENET_RX_DMA_END_ADDR_LO(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x1c)
+#define GENET_RX_DMA_END_ADDR_HI(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x20)
+#define GENET_RX_DMA_XON_XOFF_THRES(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x28)
+#define GENET_RX_DMA_XON_XOFF_THRES_LO 0xffff0000
+#define GENET_RX_DMA_XON_XOFF_THRES_HI 0x0000ffff
+#define GENET_RX_DMA_READ_PTR_LO(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x2c)
+#define GENET_RX_DMA_READ_PTR_HI(qid) (GENET_RX_DMA_RINGBASE(qid) + 0x30)
+
+#define GENET_TX_DMA_RINGBASE(qid) (GENET_TX_BASE + 0xc00 + GENET_DMA_RING_SIZE * (qid))
+#define GENET_TX_DMA_READ_PTR_LO(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x00)
+#define GENET_TX_DMA_READ_PTR_HI(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x04)
+#define GENET_TX_DMA_CONS_INDEX(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x08)
+#define GENET_TX_DMA_PROD_INDEX(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x0c)
+#define GENET_TX_DMA_RING_BUF_SIZE(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x10)
+#define GENET_TX_DMA_RING_BUF_SIZE_DESC_COUNT 0xffff0000
+#define GENET_TX_DMA_RING_BUF_SIZE_BUF_LENGTH 0x0000ffff
+#define GENET_TX_DMA_START_ADDR_LO(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x14)
+#define GENET_TX_DMA_START_ADDR_HI(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x18)
+#define GENET_TX_DMA_END_ADDR_LO(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x1c)
+#define GENET_TX_DMA_END_ADDR_HI(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x20)
+#define GENET_TX_DMA_MBUF_DONE_THRES(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x24)
+#define GENET_TX_DMA_FLOW_PERIOD(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x28)
+#define GENET_TX_DMA_WRITE_PTR_LO(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x2c)
+#define GENET_TX_DMA_WRITE_PTR_HI(qid) (GENET_TX_DMA_RINGBASE(qid) + 0x30)
+
+#define GENET_RX_DESC_STATUS(idx) (GENET_RX_BASE + GENET_DMA_DESC_SIZE * (idx) + 0x00)
+#define GENET_RX_DESC_STATUS_BUFLEN (BIT27|BIT26|BIT25|BIT24|BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)
+#define GENET_RX_DESC_STATUS_OWN BIT15
+#define GENET_RX_DESC_STATUS_EOP BIT14
+#define GENET_RX_DESC_STATUS_SOP BIT13
+#define GENET_RX_DESC_STATUS_RX_ERROR BIT2
+#define GENET_RX_DESC_ADDRESS_LO(idx) (GENET_RX_BASE + GENET_DMA_DESC_SIZE * (idx) + 0x04)
+#define GENET_RX_DESC_ADDRESS_HI(idx) (GENET_RX_BASE + GENET_DMA_DESC_SIZE * (idx) + 0x08)
+
+#define GENET_TX_DESC_STATUS(idx) (GENET_TX_BASE + GENET_DMA_DESC_SIZE * (idx) + 0x00)
+#define GENET_TX_DESC_STATUS_BUFLEN (BIT27|BIT26|BIT25|BIT24|BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)
+#define GENET_TX_DESC_STATUS_OWN BIT15
+#define GENET_TX_DESC_STATUS_EOP BIT14
+#define GENET_TX_DESC_STATUS_SOP BIT13
+#define GENET_TX_DESC_STATUS_QTAG (BIT12|BIT11|BIT10|BIT9|BIT8|BIT7)
+#define GENET_TX_DESC_STATUS_CRC BIT6
+#define GENET_TX_DESC_ADDRESS_LO(idx) (GENET_TX_BASE + GENET_DMA_DESC_SIZE * (idx) + 0x04)
+#define GENET_TX_DESC_ADDRESS_HI(idx) (GENET_TX_BASE + GENET_DMA_DESC_SIZE * (idx) + 0x08)
+
+#define GENET_RX_DMA_RING_CFG (GENET_RX_BASE + 0x1040 + 0x00)
+#define GENET_RX_DMA_CTRL (GENET_RX_BASE + 0x1040 + 0x04)
+#define GENET_RX_DMA_CTRL_RBUF_EN(qid) (BIT1 << (qid))
+#define GENET_RX_DMA_CTRL_EN BIT0
+#define GENET_RX_SCB_BURST_SIZE (GENET_RX_BASE + 0x1040 + 0x0c)
+
+#define GENET_TX_DMA_RING_CFG (GENET_TX_BASE + 0x1040 + 0x00)
+#define GENET_TX_DMA_CTRL (GENET_TX_BASE + 0x1040 + 0x04)
+#define GENET_TX_DMA_CTRL_RBUF_EN(qid) (BIT1 << (qid))
+#define GENET_TX_DMA_CTRL_EN BIT0
+#define GENET_TX_SCB_BURST_SIZE (GENET_TX_BASE + 0x1040 + 0x0c)
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS PhysAddress;
+ VOID * Mapping;
+} GENET_MAP_INFO;
+
+typedef enum {
+ GENET_PHY_MODE_MII,
+ GENET_PHY_MODE_RGMII,
+ GENET_PHY_MODE_RGMII_RXID,
+ GENET_PHY_MODE_RGMII_TXID,
+ GENET_PHY_MODE_RGMII_ID,
+} GENET_PHY_MODE;
+
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE ControllerHandle;
+
+ EFI_LOCK Lock;
+ EFI_EVENT ExitBootServicesEvent;
+
+ EFI_SIMPLE_NETWORK_PROTOCOL Snp;
+ EFI_SIMPLE_NETWORK_MODE SnpMode;
+
+ BCM_GENET_PLATFORM_DEVICE_PROTOCOL *Dev;
+
+ GENERIC_PHY_PRIVATE_DATA Phy;
+
+ UINT8 *TxBuffer[GENET_DMA_DESC_COUNT];
+ VOID *TxBufferMap[GENET_DMA_DESC_COUNT];
+ UINT8 TxQueued;
+ UINT16 TxNext;
+ UINT16 TxConsIndex;
+ UINT16 TxProdIndex;
+
+ EFI_PHYSICAL_ADDRESS RxBuffer;
+ GENET_MAP_INFO RxBufferMap[GENET_DMA_DESC_COUNT];
+ UINT16 RxConsIndex;
+ UINT16 RxProdIndex;
+
+ GENET_PHY_MODE PhyMode;
+
+ UINTN RegBase;
+} GENET_PRIVATE_DATA;
+
+extern EFI_COMPONENT_NAME_PROTOCOL gGenetComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gGenetComponentName2;
+
+extern CONST EFI_SIMPLE_NETWORK_PROTOCOL gGenetSimpleNetworkTemplate;
+
+#define GENET_DRIVER_SIGNATURE SIGNATURE_32('G', 'N', 'E', 'T')
+#define GENET_PRIVATE_DATA_FROM_SNP_THIS(a) CR(a, GENET_PRIVATE_DATA, Snp, GENET_DRIVER_SIGNATURE)
+
+#define GENET_RX_BUFFER(g, idx) ((UINT8 *)(UINTN)(g)->RxBuffer + GENET_MAX_PACKET_SIZE * (idx))
+
+EFI_STATUS
+EFIAPI
+GenetPhyRead (
+ IN VOID *Priv,
+ IN UINT8 PhyAddr,
+ IN UINT8 Reg,
+ OUT UINT16 *Data
+ );
+
+EFI_STATUS
+EFIAPI
+GenetPhyWrite (
+ IN VOID *Priv,
+ IN UINT8 PhyAddr,
+ IN UINT8 Reg,
+ IN UINT16 Data
+ );
+
+EFI_STATUS
+EFIAPI
+GenetPhyResetAction (
+ IN VOID *Priv
+ );
+
+VOID
+EFIAPI
+GenetPhyConfigure (
+ IN VOID *Priv,
+ IN GENERIC_PHY_SPEED Speed,
+ IN GENERIC_PHY_DUPLEX Duplex
+ );
+
+VOID
+GenetReset (
+ IN GENET_PRIVATE_DATA *Genet
+ );
+
+VOID
+EFIAPI
+GenetSetMacAddress (
+ IN GENET_PRIVATE_DATA *Genet,
+ IN EFI_MAC_ADDRESS *MacAddr
+ );
+
+VOID
+GenetSetPhyMode (
+ IN GENET_PRIVATE_DATA *Genet,
+ IN GENET_PHY_MODE PhyMode
+ );
+
+VOID
+GenetEnableTxRx (
+ IN GENET_PRIVATE_DATA *Genet
+ );
+
+VOID
+GenetDisableTxRx (
+ IN GENET_PRIVATE_DATA *Genet
+ );
+
+VOID
+GenetSetPromisc (
+ IN GENET_PRIVATE_DATA *Genet,
+ IN BOOLEAN Enable
+ );
+
+VOID
+GenetEnableBroadcastFilter (
+ IN GENET_PRIVATE_DATA *Genet,
+ IN BOOLEAN Enable
+ );
+
+VOID
+GenetDmaInitRings (
+ IN GENET_PRIVATE_DATA *Genet
+ );
+
+EFI_STATUS
+GenetDmaAlloc (
+ IN GENET_PRIVATE_DATA *Genet
+ );
+
+VOID
+GenetDmaFree (
+ IN GENET_PRIVATE_DATA *Genet
+ );
+
+VOID
+GenetDmaTriggerTx (
+ IN GENET_PRIVATE_DATA *Genet,
+ IN UINT8 DescIndex,
+ IN EFI_PHYSICAL_ADDRESS PhysAddr,
+ IN UINTN NumberOfBytes
+ );
+
+EFI_STATUS
+GenetDmaMapRxDescriptor (
+ IN GENET_PRIVATE_DATA *Genet,
+ IN UINT8 DescIndex
+ );
+
+VOID
+GenetDmaUnmapRxDescriptor (
+ IN GENET_PRIVATE_DATA *Genet,
+ IN UINT8 DescIndex
+ );
+
+VOID
+GenetTxIntr (
+ IN GENET_PRIVATE_DATA *Genet,
+ OUT VOID **TxBuf
+ );
+
+EFI_STATUS
+GenetRxIntr (
+ IN GENET_PRIVATE_DATA *Genet,
+ OUT UINT8 *DescIndex,
+ OUT UINTN *FrameLength
+ );
+
+#endif /* GENET_UTIL_H__ */
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.h b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.h
new file mode 100644
index 000000000000..a6c70aa97502
--- /dev/null
+++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.h
@@ -0,0 +1,133 @@
+/** @file
+
+ Copyright (c) 2020 Jared McNeill. All rights reserved.
+ Copyright (c) 2020 Andrey Warkentin <andrey.warkentin@gmail.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef GENERICPHY_H__
+#define GENERICPHY_H__
+
+//
+// Basic Control Register
+//
+#define GENERIC_PHY_BMCR 0x00
+#define GENERIC_PHY_BMCR_RESET BIT15
+#define GENERIC_PHY_BMCR_ANE BIT12
+#define GENERIC_PHY_BMCR_RESTART_AN BIT9
+
+//
+// Basic Status Register
+//
+#define GENERIC_PHY_BMSR 0x01
+#define GENERIC_PHY_BMSR_ANEG_COMPLETE BIT5
+#define GENERIC_PHY_BMSR_LINK_STATUS BIT2
+
+//
+// PHY Identifier I & II
+//
+#define GENERIC_PHY_PHYIDR1 0x02
+#define GENERIC_PHY_PHYIDR2 0x03
+
+//
+// Auto-Negotiation Advertisement Register
+//
+#define GENERIC_PHY_ANAR 0x04
+#define GENERIC_PHY_ANAR_100BASETX_FDX BIT8
+#define GENERIC_PHY_ANAR_100BASETX BIT7
+#define GENERIC_PHY_ANAR_10BASET_FDX BIT6
+#define GENERIC_PHY_ANAR_10BASET BIT5
+
+//
+// Auto-Negotiation Link Partner Ability Register
+//
+#define GENERIC_PHY_ANLPAR 0x05
+
+//
+// 1000Base-T Control Register
+//
+#define GENERIC_PHY_GBCR 0x09
+#define GENERIC_PHY_GBCR_1000BASET_FDX BIT9
+#define GENERIC_PHY_GBCR_1000BASET BIT8
+
+//
+// 1000Base-T Status Register
+//
+#define GENERIC_PHY_GBSR 0x0A
+
+typedef enum {
+ PHY_SPEED_NONE = 0,
+ PHY_SPEED_10 = 10,
+ PHY_SPEED_100 = 100,
+ PHY_SPEED_1000 = 1000
+} GENERIC_PHY_SPEED;
+
+typedef enum {
+ PHY_DUPLEX_HALF,
+ PHY_DUPLEX_FULL
+} GENERIC_PHY_DUPLEX;
+
+typedef
+EFI_STATUS
+(EFIAPI *GENERIC_PHY_READ) (
+ IN VOID *Priv,
+ IN UINT8 PhyAddr,
+ IN UINT8 Reg,
+ OUT UINT16 * Data
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *GENERIC_PHY_WRITE) (
+ IN VOID *Priv,
+ IN UINT8 PhyAddr,
+ IN UINT8 Reg,
+ IN UINT16 Data
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *GENERIC_PHY_RESET_ACTION) (
+ IN VOID *Priv
+ );
+
+typedef
+VOID
+(EFIAPI *GENERIC_PHY_CONFIGURE) (
+ IN VOID *Priv,
+ IN GENERIC_PHY_SPEED Speed,
+ IN GENERIC_PHY_DUPLEX Duplex
+ );
+
+typedef struct {
+ GENERIC_PHY_READ Read;
+ GENERIC_PHY_WRITE Write;
+ GENERIC_PHY_RESET_ACTION ResetAction;
+ GENERIC_PHY_CONFIGURE Configure;
+ VOID *PrivateData;
+
+ UINT8 PhyAddr;
+ BOOLEAN LinkUp;
+} GENERIC_PHY_PRIVATE_DATA;
+
+EFI_STATUS
+EFIAPI
+GenericPhyInit (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy
+ );
+
+EFI_STATUS
+EFIAPI
+GenericPhyUpdateConfig (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy
+ );
+
+EFI_STATUS
+EFIAPI
+GenericPhyReset (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy
+ );
+
+#endif // GENERICPHY_H__
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/ComponentName.c b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/ComponentName.c
new file mode 100644
index 000000000000..860e30b4da6b
--- /dev/null
+++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/ComponentName.c
@@ -0,0 +1,202 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for GENET UEFI driver.
+
+ Copyright (c) 2020 Jared McNeill. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Library/UefiLib.h>
+#include <Protocol/ComponentName2.h>
+
+#include "BcmGenetDxe.h"
+
+STATIC EFI_UNICODE_STRING_TABLE mGenetDriverNameTable[] = {
+ {
+ "eng;en",
+ L"Broadcom GENET Ethernet Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+STATIC EFI_UNICODE_STRING_TABLE mGenetDeviceNameTable[] = {
+ {
+ "eng;en",
+ L"Broadcom GENET Ethernet"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (Language,
+ This->SupportedLanguages,
+ mGenetDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gGenetComponentName2)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return LookupUnicodeString2 (Language,
+ This->SupportedLanguages,
+ mGenetDeviceNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gGenetComponentName2)
+ );
+}
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME_PROTOCOL gGenetComponentName = {
+ (EFI_COMPONENT_NAME_GET_DRIVER_NAME) GenetComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) GenetComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME2_PROTOCOL gGenetComponentName2 = {
+ GenetComponentNameGetDriverName,
+ GenetComponentNameGetControllerName,
+ "en"
+};
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c
new file mode 100644
index 000000000000..f37da3b65511
--- /dev/null
+++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c
@@ -0,0 +1,408 @@
+/** @file
+ Device driver for the Broadcom GENET controller
+
+ Copyright (c) 2020 Jared McNeill. All rights reserved.
+ Copyright (c) 2020, ARM Limited. All rights reserved.
+ Copyright (c) 2020 Andrey Warkentin <andrey.warkentin@gmail.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NetLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/BcmGenetPlatformDevice.h>
+
+#include "BcmGenetDxe.h"
+
+/**
+ Tests to see if this driver supports a given controller.
+
+ @param This[in] A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param ControllerHandle[in] The handle of the controller to test.
+ @param RemainingDevicePath[in] The remaining device path.
+ (Ignored - this is not a bus driver.)
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle is
+ already being managed by the driver specified
+ by This.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle is
+ not supported by the driver specified by This.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ BCM_GENET_PLATFORM_DEVICE_PROTOCOL *Dev;
+ EFI_STATUS Status;
+
+ //
+ // Connect to the non-discoverable device
+ //
+ Status = gBS->OpenProtocol (ControllerHandle,
+ &gBcmGenetPlatformDeviceProtocolGuid,
+ (VOID **)&Dev,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Clean up.
+ //
+ gBS->CloseProtocol (ControllerHandle,
+ &gBcmGenetPlatformDeviceProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Callback function to shut down the network device at ExitBootServices
+
+ @param Event Pointer to this event
+ @param Context Event handler private data
+
+**/
+STATIC
+VOID
+EFIAPI
+GenetNotifyExitBootServices (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ GenetDisableTxRx ((GENET_PRIVATE_DATA *)Context);
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle The handle of the device to start. This
+ handle must support a protocol interface that
+ supplies an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath The remaining portion of the device path.
+ (Ignored - this is not a bus driver.)
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a
+ device error.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ GENET_PRIVATE_DATA *Genet;
+ EFI_STATUS Status;
+
+ // Allocate Resources
+ Genet = AllocateZeroPool (sizeof (GENET_PRIVATE_DATA));
+ if (Genet == NULL) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Couldn't allocate private data\n", __FUNCTION__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gBS->OpenProtocol (ControllerHandle,
+ &gBcmGenetPlatformDeviceProtocolGuid,
+ (VOID **)&Genet->Dev,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Couldn't open protocol: %r\n", __FUNCTION__, Status));
+ goto FreeDevice;
+ }
+
+ Status = GenetDmaAlloc (Genet);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Couldn't allocate DMA buffers: %r\n", __FUNCTION__, Status));
+ goto FreeDevice;
+ }
+
+ Genet->Signature = GENET_DRIVER_SIGNATURE;
+ Genet->RegBase = Genet->Dev->BaseAddress;
+ Genet->Phy.PrivateData = Genet;
+ Genet->Phy.Read = GenetPhyRead;
+ Genet->Phy.Write = GenetPhyWrite;
+ Genet->Phy.Configure = GenetPhyConfigure;
+ Genet->Phy.ResetAction = GenetPhyResetAction;
+ Genet->PhyMode = GENET_PHY_MODE_RGMII_RXID;
+
+ EfiInitializeLock (&Genet->Lock, TPL_CALLBACK);
+ CopyMem (&Genet->Snp, &gGenetSimpleNetworkTemplate, sizeof Genet->Snp);
+
+ Genet->Snp.Mode = &Genet->SnpMode;
+ Genet->SnpMode.State = EfiSimpleNetworkStopped;
+ Genet->SnpMode.HwAddressSize = NET_ETHER_ADDR_LEN;
+ Genet->SnpMode.MediaHeaderSize = sizeof (ETHER_HEAD);
+ Genet->SnpMode.MaxPacketSize = MAX_ETHERNET_PKT_SIZE;
+ Genet->SnpMode.NvRamSize = 0;
+ Genet->SnpMode.NvRamAccessSize = 0;
+ Genet->SnpMode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
+ Genet->SnpMode.ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+ Genet->SnpMode.MaxMCastFilterCount = 0;
+ Genet->SnpMode.MCastFilterCount = 0;
+ Genet->SnpMode.IfType = NET_IFTYPE_ETHERNET;
+ Genet->SnpMode.MacAddressChangeable = TRUE;
+ Genet->SnpMode.MultipleTxSupported = FALSE;
+ Genet->SnpMode.MediaPresentSupported = TRUE;
+ Genet->SnpMode.MediaPresent = FALSE;
+
+ SetMem (&Genet->SnpMode.BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xff);
+
+ CopyMem (&Genet->SnpMode.PermanentAddress, &Genet->Dev->MacAddress,
+ sizeof(EFI_MAC_ADDRESS));
+ CopyMem (&Genet->SnpMode.CurrentAddress, &Genet->Dev->MacAddress,
+ sizeof(EFI_MAC_ADDRESS));
+
+ Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+ GenetNotifyExitBootServices, Genet,
+ &gEfiEventExitBootServicesGuid,
+ &Genet->ExitBootServicesEvent);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "GenetDriverBindingStart: failed to register for ExitBootServices event - %r\n",
+ Status));
+ goto FreeDevice;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (&ControllerHandle,
+ &gEfiSimpleNetworkProtocolGuid, &Genet->Snp,
+ NULL);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Couldn't install protocol interfaces: %r\n", __FUNCTION__, Status));
+ gBS->CloseProtocol (ControllerHandle,
+ &gBcmGenetPlatformDeviceProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle);
+ goto FreeEvent;
+ }
+
+ Genet->ControllerHandle = ControllerHandle;
+ return EFI_SUCCESS;
+
+FreeEvent:
+ gBS->CloseEvent (Genet->ExitBootServicesEvent);
+FreeDevice:
+ DEBUG ((DEBUG_WARN, "%a: Returning %r\n", __FUNCTION__, Status));
+ FreePool (Genet);
+ return Status;
+}
+
+
+/**
+ Stops a device controller or a bus controller.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle
+ must support a bus specific I/O protocol for the
+ driver to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in
+ ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be
+ NULL if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device
+ error.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;
+ GENET_PRIVATE_DATA *Genet;
+ EFI_STATUS Status;
+
+ Status = gBS->HandleProtocol (ControllerHandle,
+ &gEfiSimpleNetworkProtocolGuid,
+ (VOID **)&SnpProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Genet = GENET_PRIVATE_DATA_FROM_SNP_THIS (SnpProtocol);
+
+ ASSERT (Genet->ControllerHandle == ControllerHandle);
+
+ Status = gBS->UninstallProtocolInterface (ControllerHandle,
+ &gEfiSimpleNetworkProtocolGuid,
+ &Genet->Snp
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->CloseEvent (Genet->ExitBootServicesEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ GenetDmaFree (Genet);
+
+ Status = gBS->CloseProtocol (ControllerHandle,
+ &gBcmGenetPlatformDeviceProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FreePool (Genet);
+
+ return EFI_SUCCESS;
+}
+
+STATIC EFI_DRIVER_BINDING_PROTOCOL mGenetDriverBinding = {
+ GenetDriverBindingSupported,
+ GenetDriverBindingStart,
+ GenetDriverBindingStop,
+ GENET_VERSION,
+ NULL,
+ NULL
+};
+
+/**
+ The entry point of GENET UEFI Driver.
+
+ @param ImageHandle The image handle of the UEFI Driver.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The Driver or UEFI Driver exited normally.
+ @retval EFI_INCOMPATIBLE_VERSION _gUefiDriverRevision is greater than
+ SystemTable->Hdr.Revision.
+
+**/
+EFI_STATUS
+EFIAPI
+GenetEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &mGenetDriverBinding,
+ ImageHandle,
+ &gGenetComponentName,
+ &gGenetComponentName2
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INIT | DEBUG_INFO, "Installed GENET UEFI driver!\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unload function of GENET UEFI Driver.
+
+ @param ImageHandle The allocated handle for the EFI image
+
+ @retval EFI_SUCCESS The driver was unloaded successfully
+ @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+GenetUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+
+ //
+ // Retrieve all BcmGenetPlatformDevice handles in the handle database
+ //
+ Status = gBS->LocateHandleBuffer (ByProtocol,
+ &gBcmGenetPlatformDeviceProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Disconnect the driver from the handles in the handle database
+ //
+ for (Index = 0; Index < HandleCount && !EFI_ERROR (Status); Index++) {
+ Status = gBS->DisconnectController (HandleBuffer[Index],
+ gImageHandle,
+ NULL);
+ }
+
+ //
+ // Free the handle array
+ //
+ gBS->FreePool (HandleBuffer);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "%a: failed to disconnect all controllers - %r\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+
+ //
+ // Uninstall protocols installed by the driver in its entrypoint
+ //
+ Status = EfiLibUninstallDriverBindingComponentName2 (
+ &mGenetDriverBinding,
+ &gGenetComponentName,
+ &gGenetComponentName2
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.c b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.c
new file mode 100644
index 000000000000..9e5d30fafd38
--- /dev/null
+++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.c
@@ -0,0 +1,404 @@
+/** @file
+
+ Copyright (c) 2020 Jared McNeill. All rights reserved.
+ Copyright (c) 2020 Andrey Warkentin <andrey.warkentin@gmail.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "GenericPhy.h"
+
+#define PHY_RESET_TIMEOUT 500
+
+/**
+ Perform a PHY register read.
+
+ @param Phy[in] Pointer to GENERIC_PHY_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.
+
+**/
+STATIC
+EFI_STATUS
+GenericPhyRead (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy,
+ IN UINT8 PhyAddr,
+ IN UINT8 Reg,
+ OUT UINT16 *Data
+ )
+{
+ return Phy->Read (Phy->PrivateData, PhyAddr, Reg, Data);
+}
+
+/**
+ Perform a PHY register write.
+
+ @param Phy[in] Pointer to GENERIC_PHY_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.
+
+**/
+STATIC
+EFI_STATUS
+GenericPhyWrite (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy,
+ IN UINT8 PhyAddr,
+ IN UINT8 Reg,
+ IN UINT16 Data
+ )
+{
+ return Phy->Write (Phy->PrivateData, PhyAddr, Reg, Data);
+}
+
+/**
+ Process a PHY link speed change (e.g. with MAC layer).
+
+ @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
+ @param Speed[in] Speed setting.
+ @param Duplex[in] Duplex setting.
+
+**/
+STATIC
+VOID
+GenericPhyConfigure (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy,
+ IN GENERIC_PHY_SPEED Speed,
+ IN GENERIC_PHY_DUPLEX Duplex
+ )
+{
+ Phy->Configure (Phy->PrivateData, Speed, Duplex);
+}
+
+/**
+ Detect address for the first PHY seen, probing all possible addresses.
+
+ @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS Found a PHY and programmed Phy->PhyAddr
+ @retval EFI_DEVICE_ERROR Error reading/writing a PHY register.
+ @retval EFI_NOT_FOUND No PHY detected.
+
+**/
+STATIC
+EFI_STATUS
+GenericPhyDetect (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy
+ )
+{
+ EFI_STATUS Status;
+ UINT8 PhyAddr;
+ UINT16 Id1, Id2;
+
+ for (PhyAddr = 0; PhyAddr < 32; PhyAddr++) {
+ Status = GenericPhyRead (Phy, PhyAddr, GENERIC_PHY_PHYIDR1, &Id1);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ Status = GenericPhyRead (Phy, PhyAddr, GENERIC_PHY_PHYIDR2, &Id2);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ if (Id1 != 0xFFFF && Id2 != 0xFFFF) {
+ Phy->PhyAddr = PhyAddr;
+ DEBUG ((DEBUG_INFO,
+ "%a: PHY detected at address 0x%02X (PHYIDR1=0x%04X, PHYIDR2=0x%04X)\n",
+ __FUNCTION__, PhyAddr, Id1, Id2));
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Start link auto-negotiation on a PHY.
+
+ @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS Auto-netogiation started.
+ @retval EFI_DEVICE_ERROR PHY register read/write error.
+
+**/
+STATIC
+EFI_STATUS
+GenericPhyAutoNegotiate (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Anar, Gbcr, Bmcr;
+
+ Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_ANAR, &Anar);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Anar |= GENERIC_PHY_ANAR_100BASETX_FDX |
+ GENERIC_PHY_ANAR_100BASETX |
+ GENERIC_PHY_ANAR_10BASET_FDX |
+ GENERIC_PHY_ANAR_10BASET;
+ Status = GenericPhyWrite (Phy, Phy->PhyAddr, GENERIC_PHY_ANAR, Anar);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_GBCR, &Gbcr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Gbcr |= GENERIC_PHY_GBCR_1000BASET_FDX |
+ GENERIC_PHY_GBCR_1000BASET;
+ Status = GenericPhyWrite (Phy, Phy->PhyAddr, GENERIC_PHY_GBCR, Gbcr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_BMCR, &Bmcr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Bmcr |= GENERIC_PHY_BMCR_ANE |
+ GENERIC_PHY_BMCR_RESTART_AN;
+ return GenericPhyWrite (Phy, Phy->PhyAddr, GENERIC_PHY_BMCR, Bmcr);
+}
+
+/**
+ Initialize the first PHY detected, performing a reset and enabling
+ auto-negotiation.
+
+ @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS Auto-negotiation started.
+ @retval EFI_DEVICE_ERROR PHY register read/write error.
+ @retval EFI_TIMEOUT PHY reset time-out.
+ @retval EFI_NOT_FOUND No PHY detected.
+
+**/
+EFI_STATUS
+EFIAPI
+GenericPhyInit (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Phy->Read != NULL);
+ ASSERT (Phy->Write != NULL);
+ ASSERT (Phy->Configure != NULL);
+
+ Status = GenericPhyDetect (Phy);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GenericPhyReset (Phy);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return GenericPhyAutoNegotiate (Phy);
+}
+
+/**
+ Perform a PHY reset.
+
+ @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS Auto-negotiation started.
+ @retval EFI_DEVICE_ERROR PHY register read/write error.
+ @retval EFI_TIMEOUT PHY reset time-out.
+
+**/
+EFI_STATUS
+EFIAPI
+GenericPhyReset (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy
+ )
+{
+ EFI_STATUS Status;
+ UINTN Retry;
+ UINT16 Data;
+
+ // Start reset sequence
+ Status = GenericPhyWrite (Phy, Phy->PhyAddr, GENERIC_PHY_BMCR,
+ GENERIC_PHY_BMCR_RESET);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Wait up to 500ms for it to complete
+ for (Retry = PHY_RESET_TIMEOUT; Retry > 0; Retry--) {
+ Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_BMCR, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if ((Data & GENERIC_PHY_BMCR_RESET) == 0) {
+ break;
+ }
+ gBS->Stall (1000);
+ }
+ if (Retry == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ if (Phy->ResetAction != NULL) {
+ Phy->ResetAction (Phy->PrivateData);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Probe link status.
+
+ @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS Link is up and auto-negotiation is complete.
+ @retval EFI_DEVICE_ERROR PHY register read/write error,
+
+**/
+STATIC
+EFI_STATUS
+GenericPhyGetLinkStatus (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Bmsr;
+
+ Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_BMSR, &Bmsr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Bmsr & GENERIC_PHY_BMSR_LINK_STATUS) == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ if ((Bmsr & GENERIC_PHY_BMSR_ANEG_COMPLETE) == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return PHY link configuration.
+
+ @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
+ @param Speed[out] Pointer to store link speed.
+ @param Duplex[out] Pointer to store link duplex setting.
+
+ @retval EFI_SUCCESS Link configuration settings read.
+ @retval EFI_DEVICE_ERROR PHY register read/write error,
+
+**/
+STATIC
+EFI_STATUS
+GenericPhyGetConfig (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy,
+ OUT GENERIC_PHY_SPEED *Speed,
+ OUT GENERIC_PHY_DUPLEX *Duplex
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Gbcr, Gbsr, Anlpar, Anar;
+ UINT16 Gb, An;
+
+ Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_GBCR, &Gbcr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_GBSR, &Gbsr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_ANLPAR, &Anlpar);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_ANAR, &Anar);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Gb = (Gbsr >> 2) & Gbcr;
+ An = Anlpar & Anar;
+
+ if ((Gb & (GENERIC_PHY_GBCR_1000BASET_FDX |
+ GENERIC_PHY_GBCR_1000BASET)) != 0) {
+ *Speed = PHY_SPEED_1000;
+ *Duplex = (Gb & GENERIC_PHY_GBCR_1000BASET_FDX) ? PHY_DUPLEX_FULL
+ : PHY_DUPLEX_HALF;
+ } else if ((An & (GENERIC_PHY_ANAR_100BASETX_FDX |
+ GENERIC_PHY_ANAR_100BASETX)) != 0) {
+ *Speed = PHY_SPEED_100;
+ *Duplex = (An & GENERIC_PHY_ANAR_100BASETX_FDX) ? PHY_DUPLEX_FULL
+ : PHY_DUPLEX_HALF;
+ } else {
+ *Speed = PHY_SPEED_10;
+ *Duplex = (An & GENERIC_PHY_ANAR_10BASET_FDX) ? PHY_DUPLEX_FULL
+ : PHY_DUPLEX_HALF;
+ }
+
+ DEBUG ((DEBUG_INFO, "%a: Link speed %d Mbps, %a-duplex\n",
+ __FUNCTION__, *Speed, *Duplex == PHY_DUPLEX_FULL ? "full" : "half"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update link status, propagating PHY link state into the MAC layer.
+
+ @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS Link is up.
+ @retval EFI_DEVICE_ERROR PHY register read/write error.
+ @retval EFI_NOT_READY Link is down.
+
+**/
+EFI_STATUS
+EFIAPI
+GenericPhyUpdateConfig (
+ IN GENERIC_PHY_PRIVATE_DATA *Phy
+ )
+{
+ EFI_STATUS Status;
+ GENERIC_PHY_SPEED Speed;
+ GENERIC_PHY_DUPLEX Duplex;
+ BOOLEAN LinkUp;
+
+ Status = GenericPhyGetLinkStatus (Phy);
+ LinkUp = EFI_ERROR (Status) ? FALSE : TRUE;
+
+ if (Phy->LinkUp != LinkUp) {
+ if (LinkUp) {
+ DEBUG ((DEBUG_VERBOSE, "%a: Link is up\n", __FUNCTION__));
+
+ Status = GenericPhyGetConfig (Phy, &Speed, &Duplex);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ GenericPhyConfigure (Phy, Speed, Duplex);
+ } else {
+ DEBUG ((DEBUG_VERBOSE, "%a: Link is down\n", __FUNCTION__));
+ }
+ }
+
+ Phy->LinkUp = LinkUp;
+
+ return LinkUp ? EFI_SUCCESS : EFI_NOT_READY;
+}
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/Genet.c b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/Genet.c
deleted file mode 100644
index d40ce8b07a9d..000000000000
--- a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/Genet.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/** @file
-
- Copyright (c) 2020, Jeremy Linton All rights reserved.<BR>
-
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
- This driver acts like a stub to set the Broadcom
- Genet MAC address, until the actual network driver
- is in place.
-
-**/
-
-#include <Library/ArmLib.h>
-#include <Library/DebugLib.h>
-#include <Library/IoLib.h>
-#include <Library/PcdLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiLib.h>
-
-#include <Net/Genet.h>
-#include <PiDxe.h>
-
-STATIC
-VOID
-RMWRegister (
- UINT32 Offset,
- UINT32 Mask,
- UINT32 In
- )
-{
- EFI_PHYSICAL_ADDRESS Addr;
- UINT32 Data;
- UINT32 Shift;
-
- Addr = GENET_BASE_ADDRESS + Offset;
- Data = 0;
- Shift = 1;
- if (In) {
- while (!(Mask & Shift))
- Shift <<= 1;
- Data = (MmioRead32 (Addr) & ~Mask) | ((In * Shift) & Mask);
- } else {
- Data = MmioRead32 (Addr) & ~Mask;
- }
-
- MmioWrite32 (Addr, Data);
-
- ArmDataMemoryBarrier ();
-}
-
-STATIC
-VOID
-WdRegister (
- UINT32 Offset,
- UINT32 In
- )
-{
- EFI_PHYSICAL_ADDRESS Base = GENET_BASE_ADDRESS;
-
- MmioWrite32 (Base + Offset, In);
-
- ArmDataMemoryBarrier ();
-}
-
-STATIC
-VOID
-SetMacAddress (
- UINT8* MacAddr
-)
-{
- // Bring the UMAC out of reset
- RMWRegister (GENET_SYS_RBUF_FLUSH_CTRL, 0x2, 1);
- gBS->Stall (10);
- RMWRegister (GENET_SYS_RBUF_FLUSH_CTRL, 0x2, 0);
-
- // Update the MAC
- DEBUG ((DEBUG_INFO, "Using MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
- MacAddr[0], MacAddr[1], MacAddr[2], MacAddr[3], MacAddr[4], MacAddr[5]));
-
- WdRegister (GENET_UMAC_MAC0, (MacAddr[0] << 24) | (MacAddr[1] << 16) |
- (MacAddr[2] << 8) | MacAddr[3]);
- WdRegister (GENET_UMAC_MAC1, (MacAddr[4] << 8) | MacAddr[5]);
-
-}
-
-/**
- The entry point of Genet UEFI Driver.
-
- @param ImageHandle The image handle of the UEFI Driver.
- @param SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The Driver or UEFI Driver exited normally.
- @retval EFI_INCOMPATIBLE_VERSION _gUefiDriverRevision is greater than
- SystemTable->Hdr.Revision.
-
-**/
-EFI_STATUS
-EFIAPI
-GenetEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- UINT64 MacAddr;
-
- // Read the MAC address
- MacAddr = PcdGet64 (PcdBcmGenetMacAddress);
-
- if (MacAddr != 0) {
- SetMacAddress ((UINT8*)&MacAddr);
- }
-
- return EFI_SUCCESS;
-}
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c
new file mode 100644
index 000000000000..4b0995e30ddf
--- /dev/null
+++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c
@@ -0,0 +1,814 @@
+/** @file
+
+ Copyright (c) 2020 Jared McNeill. All rights reserved.
+ Copyright (c) 2020 Andrey Warkentin <andrey.warkentin@gmail.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/DmaLib.h>
+#include <Library/IoLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#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);
+
+ 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),
+ (DescIndex + 1) & 0xFFFF);
+}
+
+/**
+ 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 ConsIndex, Total;
+
+ ConsIndex = GenetMmioRead (Genet,
+ GENET_TX_DMA_CONS_INDEX (GENET_DMA_DEFAULT_QUEUE)) & 0xFFFF;
+
+ Total = (ConsIndex - Genet->TxConsIndex) & 0xFFFF;
+ 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++;
+ } else {
+ *TxBuf = NULL;
+ }
+}
+
+/**
+ 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 ProdIndex, Total;
+ UINT32 DescStatus;
+
+ ProdIndex = GenetMmioRead (Genet,
+ GENET_RX_DMA_PROD_INDEX (GENET_DMA_DEFAULT_QUEUE)) & 0xFFFF;
+
+ Total = (ProdIndex - Genet->RxConsIndex) & 0xFFFF;
+ 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);
+
+ Genet->RxConsIndex = (Genet->RxConsIndex + 1) & 0xFFFF;
+ GenetMmioWrite (Genet, GENET_RX_DMA_CONS_INDEX (GENET_DMA_DEFAULT_QUEUE),
+ Genet->RxConsIndex);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_NOT_READY;
+ }
+
+ return Status;
+}
diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/SimpleNetwork.c b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/SimpleNetwork.c
new file mode 100644
index 000000000000..74677927bef7
--- /dev/null
+++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/SimpleNetwork.c
@@ -0,0 +1,838 @@
+/** @file
+ Provides the Simple Network functions.
+
+ Copyright (c) 2020 Jared McNeill. All rights reserved.
+ Copyright (c) 2020 Andrey Warkentin <andrey.warkentin@gmail.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DmaLib.h>
+#include <Library/NetLib.h>
+#include <Protocol/SimpleNetwork.h>
+
+#include "BcmGenetDxe.h"
+
+/**
+ Changes the state of a network interface from "stopped" to "started".
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was started.
+ @retval EFI_ALREADY_STARTED The network interface is already in the started state.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The network interface is not in the right (stopped) state.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkStart (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ GENET_PRIVATE_DATA *Genet;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Genet = GENET_PRIVATE_DATA_FROM_SNP_THIS (This);
+ if (Genet->SnpMode.State == EfiSimpleNetworkStarted) {
+ return EFI_ALREADY_STARTED;
+ } else if (Genet->SnpMode.State != EfiSimpleNetworkStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Genet->SnpMode.State = EfiSimpleNetworkStarted;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Changes the state of a network interface from "started" to "stopped".
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was stopped.
+ @retval EFI_NOT_STARTED The network interface is already in the stopped state.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The network interface is not in the right (started) state.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkStop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ GENET_PRIVATE_DATA *Genet;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Genet = GENET_PRIVATE_DATA_FROM_SNP_THIS (This);
+ if (Genet->SnpMode.State == EfiSimpleNetworkStopped) {
+ return EFI_NOT_STARTED;
+ } else if (Genet->SnpMode.State != EfiSimpleNetworkStarted) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ GenetDisableTxRx (Genet);
+
+ Genet->SnpMode.State = EfiSimpleNetworkStopped;
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets a network adapter and allocates the transmit and receive buffers
+ required by the network interface; optionally, also requests allocation
+ of additional transmit and receive buffers.
+
+ @param This The protocol instance pointer.
+ @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space
+ that the driver should allocate for the network interface.
+ Some network interfaces will not be able to use the extra
+ buffer, and the caller will not know if it is actually
+ being used.
+ @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space
+ that the driver should allocate for the network interface.
+ Some network interfaces will not be able to use the extra
+ buffer, and the caller will not know if it is actually
+ being used.
+
+ @retval EFI_SUCCESS The network interface was initialized.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and
+ receive buffers.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The network inteface is not in the right (started) state.
+ @retval EFI_DEVICE_ERROR PHY register read/write error.
+ @retval EFI_TIMEOUT PHY reset time-out.
+ @retval EFI_NOT_FOUND No PHY detected.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkInitialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize, OPTIONAL
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ )
+{
+ GENET_PRIVATE_DATA *Genet;
+ EFI_STATUS Status;
+ UINTN Idx;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Genet = GENET_PRIVATE_DATA_FROM_SNP_THIS (This);
+ if (Genet->SnpMode.State == EfiSimpleNetworkStopped) {
+ return EFI_NOT_STARTED;
+ } else if (Genet->SnpMode.State != EfiSimpleNetworkStarted) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ GenetReset (Genet);
+ GenetSetPhyMode (Genet, Genet->PhyMode);
+
+ Status = GenericPhyInit (&Genet->Phy);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ GenetSetMacAddress (Genet, &Genet->SnpMode.CurrentAddress);
+
+ GenetDmaInitRings (Genet);
+
+ // Map RX buffers
+ for (Idx = 0; Idx < GENET_DMA_DESC_COUNT; Idx++) {
+ Status = GenetDmaMapRxDescriptor (Genet, Idx);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ GenetEnableTxRx (Genet);
+
+ Genet->SnpMode.State = EfiSimpleNetworkInitialized;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets a network adapter and re-initializes it with the parameters that were
+ provided in the previous call to Initialize().
+
+ @param This The protocol instance pointer.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The network interface was reset.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The network inteface is not in the right (initialized) state.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkReset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ GENET_PRIVATE_DATA *Genet;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Genet = GENET_PRIVATE_DATA_FROM_SNP_THIS (This);
+ if (Genet->SnpMode.State == EfiSimpleNetworkStopped) {
+ return EFI_NOT_STARTED;
+ }
+ if (Genet->SnpMode.State != EfiSimpleNetworkInitialized) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = GenericPhyReset (&Genet->Phy);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets a network adapter and leaves it in a state that is safe for
+ another driver to initialize.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was shutdown.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The network inteface is not in the right (initialized) state.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkShutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ GENET_PRIVATE_DATA *Genet;
+ UINTN Idx;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Genet = GENET_PRIVATE_DATA_FROM_SNP_THIS (This);
+ if (Genet->SnpMode.State == EfiSimpleNetworkStopped) {
+ return EFI_NOT_STARTED;
+ }
+ if (Genet->SnpMode.State != EfiSimpleNetworkInitialized) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ GenetDisableTxRx (Genet);
+
+ for (Idx = 0; Idx < GENET_DMA_DESC_COUNT; Idx++) {
+ GenetDmaUnmapRxDescriptor (Genet, Idx);
+ }
+
+ Genet->SnpMode.State = EfiSimpleNetworkStarted;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Manages the receive filters of a network interface.
+
+ @param This The protocol instance pointer.
+ @param Enable A bit mask of receive filters to enable on the network interface.
+ @param Disable A bit mask of receive filters to disable on the network interface.
+ @param ResetMCastFilter Set to TRUE to reset the contents of the multicast receive
+ filters on the network interface to their default values.
+ @param McastFilterCnt Number of multicast HW MAC addresses in the new
+ MCastFilter list. This value must be less than or equal to
+ the MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE. This
+ field is optional if ResetMCastFilter is TRUE.
+ @param MCastFilter A pointer to a list of new multicast receive filter HW MAC
+ addresses. This list will replace any existing multicast
+ HW MAC address list. This field is optional if
+ ResetMCastFilter is TRUE.
+
+ @retval EFI_SUCCESS The multicast receive filter list was updated.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The network inteface is not in the right (initialized) state.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkReceiveFilters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt, OPTIONAL
+ IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
+ )
+{
+ GENET_PRIVATE_DATA *Genet;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Genet = GENET_PRIVATE_DATA_FROM_SNP_THIS (This);
+ if (((Enable | Disable) & ~Genet->SnpMode.ReceiveFilterMask) != 0 ||
+ (!ResetMCastFilter && MCastFilterCnt > Genet->SnpMode.MaxMCastFilterCount)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Genet->SnpMode.State == EfiSimpleNetworkStopped) {
+ return EFI_NOT_STARTED;
+ }
+ if (Genet->SnpMode.State != EfiSimpleNetworkInitialized) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ GenetEnableBroadcastFilter (Genet,
+ (Enable & ~Disable & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0);
+
+ GenetSetPromisc (Genet,
+ (Enable & ~Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Modifies or resets the current station address, if supported.
+
+ @param This The protocol instance pointer.
+ @param Reset Flag used to reset the station address to the network interfaces
+ permanent address.
+ @param New The new station address to be used for the network interface.
+
+ @retval EFI_SUCCESS The network interfaces station address was updated.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The network inteface is not in the right (initialized) state.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkStationAddress (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS *New OPTIONAL
+ )
+{
+ GENET_PRIVATE_DATA *Genet;
+
+ if (This == NULL || This->Mode == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Reset == TRUE && New == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Genet = GENET_PRIVATE_DATA_FROM_SNP_THIS (This);
+ if (Genet->SnpMode.State == EfiSimpleNetworkStopped) {
+ return EFI_NOT_STARTED;
+ }
+ if (Genet->SnpMode.State != EfiSimpleNetworkInitialized) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Reset) {
+ // Use permanent address
+ CopyMem (&This->Mode->CurrentAddress, &This->Mode->PermanentAddress,
+ sizeof (This->Mode->CurrentAddress));
+ } else {
+ // Use specified address
+ CopyMem (&This->Mode->CurrentAddress, New,
+ sizeof (This->Mode->CurrentAddress));
+ }
+
+ GenetSetMacAddress (Genet, &Genet->SnpMode.CurrentAddress);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets or collects the statistics on a network interface.
+
+ @param This Protocol instance pointer.
+ @param Reset Set to TRUE to reset the statistics for the network interface.
+ @param StatisticsSize On input the size, in bytes, of StatisticsTable. On
+ output the size, in bytes, of the resulting table of
+ statistics.
+ @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
+ contains the statistics.
+
+ @retval EFI_SUCCESS The statistics were collected from the network interface.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer
+ size needed to hold the statistics is returned in
+ StatisticsSize.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The network inteface is not in the right (initialized) state.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkStatistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize, OPTIONAL
+ OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Performs read and write operations on the NVRAM device attached to a
+ network interface.
+
+ @param This The protocol instance pointer.
+ @param ReadWrite TRUE for read operations, FALSE for write operations.
+ @param Offset Byte offset in the NVRAM device at which to start the read or
+ write operation. This must be a multiple of NvRamAccessSize and
+ less than NvRamSize.
+ @param BufferSize The number of bytes to read or write from the NVRAM device.
+ This must also be a multiple of NvramAccessSize.
+ @param Buffer A pointer to the data buffer.
+
+ @retval EFI_SUCCESS The NVRAM access was performed.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkNvData (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ReadWrite,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Reads the current interrupt status and recycled transmit buffer status from
+ a network interface.
+
+ @param This The protocol instance pointer.
+ @param InterruptStatus A pointer to the bit mask of the currently active interrupts
+ If this is NULL, the interrupt status will not be read from
+ the device. If this is not NULL, the interrupt status will
+ be read from the device. When the interrupt status is read,
+ it will also be cleared. Clearing the transmit interrupt
+ does not empty the recycled transmit buffer array.
+ @param TxBuf Recycled transmit buffer address. The network interface will
+ not transmit if its internal recycled transmit buffer array
+ is full. Reading the transmit buffer does not clear the
+ transmit interrupt. If this is NULL, then the transmit buffer
+ status will not be read. If there are no transmit buffers to
+ recycle and TxBuf is not NULL, * TxBuf will be set to NULL.
+
+ @retval EFI_SUCCESS The status of the network interface was retrieved.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The network inteface is not in the right (initialized) state.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkGetStatus (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINT32 *InterruptStatus, OPTIONAL
+ OUT VOID **TxBuf OPTIONAL
+ )
+{
+ GENET_PRIVATE_DATA *Genet;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Genet = GENET_PRIVATE_DATA_FROM_SNP_THIS (This);
+ if (Genet->SnpMode.State == EfiSimpleNetworkStopped) {
+ return EFI_NOT_STARTED;
+ }
+ if (Genet->SnpMode.State != EfiSimpleNetworkInitialized) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = GenericPhyUpdateConfig (&Genet->Phy);
+ if (EFI_ERROR (Status)) {
+ Genet->SnpMode.MediaPresent = FALSE;
+ } else {
+ Genet->SnpMode.MediaPresent = TRUE;
+
+ if (TxBuf != NULL) {
+ GenetTxIntr (Genet, TxBuf);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Places a packet in the transmit queue of a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header to be filled in by
+ the Transmit() function. If HeaderSize is non-zero, then it
+ must be equal to This->Mode->MediaHeaderSize and the DestAddr
+ and Protocol parameters must not be NULL.
+ @param BufferSize The size, in bytes, of the entire packet (media header and
+ data) to be transmitted through the network interface.
+ @param Buffer A pointer to the packet (media header followed by data) to be
+ transmitted. This parameter cannot be NULL. If HeaderSize is zero,
+ then the media header in Buffer must already be filled in by the
+ caller. If HeaderSize is non-zero, then the media header will be
+ filled in by the Transmit() function.
+ @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter
+ is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then
+ This->Mode->CurrentAddress is used for the source HW MAC address.
+ @param DestAddr The destination HW MAC address. If HeaderSize is zero, then this
+ parameter is ignored.
+ @param Protocol The type of header to build. If HeaderSize is zero, then this
+ parameter is ignored. See RFC 1700, section "Ether Types", for
+ examples.
+
+ @retval EFI_SUCCESS The packet was placed on the transmit queue.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The network inteface is not in the right (initialized) state.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkTransmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr, OPTIONAL
+ IN EFI_MAC_ADDRESS *DestAddr, OPTIONAL
+ IN UINT16 *Protocol OPTIONAL
+ )
+{
+ GENET_PRIVATE_DATA *Genet;
+ EFI_STATUS Status;
+ UINT8 *Frame = Buffer;
+ UINT8 Desc;
+ PHYSICAL_ADDRESS DmaDeviceAddress;
+ UINTN DmaNumberOfBytes;
+
+ if (This == NULL || Buffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Invalid parameter (missing handle or buffer)\n",
+ __FUNCTION__));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Genet = GENET_PRIVATE_DATA_FROM_SNP_THIS (This);
+ if (Genet->SnpMode.State == EfiSimpleNetworkStopped) {
+ return EFI_NOT_STARTED;
+ }
+ if (Genet->SnpMode.State != EfiSimpleNetworkInitialized) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (!Genet->SnpMode.MediaPresent) {
+ //
+ // Don't bother transmitting if there's no link.
+ //
+ return EFI_NOT_READY;
+ }
+
+ if (HeaderSize != 0) {
+ if (HeaderSize != Genet->SnpMode.MediaHeaderSize) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Invalid parameter (header size mismatch; HeaderSize 0x%X, SnpMode.MediaHeaderSize 0x%X))\n",
+ __FUNCTION__, HeaderSize, Genet->SnpMode.MediaHeaderSize));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (DestAddr == NULL || Protocol == NULL) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Invalid parameter (dest addr or protocol missing)\n",
+ __FUNCTION__));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (BufferSize < Genet->SnpMode.MediaHeaderSize) {
+ DEBUG ((DEBUG_ERROR, "%a: Buffer too small\n", __FUNCTION__));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ Status = EfiAcquireLockOrFail (&Genet->Lock);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Couldn't get lock: %r\n", __FUNCTION__, Status));
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (Genet->TxQueued == GENET_DMA_DESC_COUNT - 1) {
+ EfiReleaseLock (&Genet->Lock);
+
+ DEBUG ((DEBUG_ERROR, "%a: Queue full\n", __FUNCTION__));
+ return EFI_NOT_READY;
+ }
+
+ if (HeaderSize != 0) {
+ CopyMem (&Frame[0], &DestAddr->Addr[0], NET_ETHER_ADDR_LEN);
+ CopyMem (&Frame[6], &SrcAddr->Addr[0], NET_ETHER_ADDR_LEN);
+ Frame[12] = (*Protocol & 0xFF00) >> 8;
+ Frame[13] = *Protocol & 0xFF;
+ }
+
+ Desc = Genet->TxProdIndex % GENET_DMA_DESC_COUNT;
+
+ Genet->TxBuffer[Desc] = Frame;
+
+ DmaNumberOfBytes = BufferSize;
+ Status = DmaMap (MapOperationBusMasterRead,
+ (VOID *)(UINTN)Frame,
+ &DmaNumberOfBytes,
+ &DmaDeviceAddress,
+ &Genet->TxBufferMap[Desc]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: DmaMap failed: %r\n", __FUNCTION__, Status));
+ EfiReleaseLock (&Genet->Lock);
+ return Status;
+ }
+
+ GenetDmaTriggerTx (Genet, Desc, DmaDeviceAddress, DmaNumberOfBytes);
+
+ Genet->TxProdIndex = (Genet->TxProdIndex + 1) % 0xFFFF;
+ Genet->TxQueued++;
+
+ EfiReleaseLock (&Genet->Lock);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Receives a packet from a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header received on the network
+ interface. If this parameter is NULL, then the media header size
+ will not be returned.
+ @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
+ bytes, of the packet that was received on the network interface.
+ @param Buffer A pointer to the data buffer to receive both the media header and
+ the data.
+ @param SrcAddr The source HW MAC address. If this parameter is NULL, the
+ HW MAC source address will not be extracted from the media
+ header.
+ @param DestAddr The destination HW MAC address. If this parameter is NULL,
+ the HW MAC destination address will not be extracted from the
+ media header.
+ @param Protocol The media header type. If this parameter is NULL, then the
+ protocol will not be extracted from the media header. See
+ RFC 1700 section "Ether Types" for examples.
+
+ @retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has
+ been updated to the number of bytes received.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY No packets received.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The network inteface is not in the right (initialized) state.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkReceive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize, OPTIONAL
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr, OPTIONAL
+ OUT EFI_MAC_ADDRESS *DestAddr, OPTIONAL
+ OUT UINT16 *Protocol OPTIONAL
+ )
+{
+ GENET_PRIVATE_DATA *Genet;
+ EFI_STATUS Status;
+ UINT8 DescIndex;
+ UINT8 *Frame;
+ UINTN FrameLength;
+
+ if (This == NULL || Buffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Invalid parameter (missing handle or buffer)\n",
+ __FUNCTION__));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Genet = GENET_PRIVATE_DATA_FROM_SNP_THIS (This);
+ if (Genet->SnpMode.State == EfiSimpleNetworkStopped) {
+ return EFI_NOT_STARTED;
+ }
+ if (Genet->SnpMode.State != EfiSimpleNetworkInitialized) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = EfiAcquireLockOrFail (&Genet->Lock);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Couldn't get lock: %r\n", __FUNCTION__, Status));
+ return EFI_ACCESS_DENIED;
+ }
+
+ Status = GenetRxIntr (Genet, &DescIndex, &FrameLength);
+ if (EFI_ERROR (Status)) {
+ EfiReleaseLock (&Genet->Lock);
+ return Status;
+ }
+
+ ASSERT (Genet->RxBufferMap[DescIndex].Mapping != NULL);
+
+ GenetDmaUnmapRxDescriptor (Genet, DescIndex);
+
+ Frame = GENET_RX_BUFFER (Genet, DescIndex);
+
+ if (FrameLength > 2 + Genet->SnpMode.MediaHeaderSize) {
+ // Received frame has 2 bytes of padding at the start
+ Frame += 2;
+ FrameLength -= 2;
+
+ if (*BufferSize < FrameLength) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Buffer size (0x%X) is too small for frame (0x%X)\n",
+ __FUNCTION__, *BufferSize, FrameLength));
+ Status = GenetDmaMapRxDescriptor (Genet, DescIndex);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to remap RX descriptor!\n",
+ __FUNCTION__));
+ }
+ EfiReleaseLock (&Genet->Lock);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (DestAddr != NULL) {
+ CopyMem (&DestAddr->Addr[0], &Frame[0], NET_ETHER_ADDR_LEN);
+ }
+ if (SrcAddr != NULL) {
+ CopyMem (&SrcAddr->Addr[0], &Frame[6], NET_ETHER_ADDR_LEN);
+ }
+ if (Protocol != NULL) {
+ *Protocol = (UINT16) ((Frame[12] << 8) | Frame[13]);
+ }
+ if (HeaderSize != NULL) {
+ *HeaderSize = Genet->SnpMode.MediaHeaderSize;
+ }
+
+ CopyMem (Buffer, Frame, FrameLength);
+ *BufferSize = FrameLength;
+
+ Status = EFI_SUCCESS;
+ } else {
+ DEBUG ((DEBUG_ERROR, "%a: Short packet (FrameLength 0x%X)",
+ __FUNCTION__, FrameLength));
+ Status = EFI_NOT_READY;
+ }
+
+ Status = GenetDmaMapRxDescriptor (Genet, DescIndex);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to remap RX descriptor!\n", __FUNCTION__));
+ }
+
+ EfiReleaseLock (&Genet->Lock);
+ return Status;
+}
+
+/**
+ This function converts a multicast IP address to a multicast HW MAC address
+ for all packet transactions.
+
+ @param [in] SimpleNetwork Protocol instance pointer
+ @param [in] IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC2460].
+ Set to FALSE if the multicast IP address is IPv4 [RFC 791].
+ @param [in] IP The multicast IP address that is to be converted to a
+ multicast HW MAC address.
+ @param [in] MAC The multicast HW MAC address that is to be generated from IP.
+
+ @retval EFI_SUCCESS This operation was successful.
+ @retval EFI_NOT_STARTED The network interface was not started.
+ @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid
+ EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @retval EFI_DEVICE_ERROR The network inteface is not in the right (initialized) state.
+ @retval EFI_UNSUPPORTED The increased buffer size feature is not supported.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenetSimpleNetworkMCastIPtoMAC (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+///
+/// Simple Network Protocol instance
+///
+CONST EFI_SIMPLE_NETWORK_PROTOCOL gGenetSimpleNetworkTemplate = {
+ EFI_SIMPLE_NETWORK_PROTOCOL_REVISION, // Revision
+ GenetSimpleNetworkStart, // Start
+ GenetSimpleNetworkStop, // Stop
+ GenetSimpleNetworkInitialize, // Initialize
+ GenetSimpleNetworkReset, // Reset
+ GenetSimpleNetworkShutdown, // Shutdown
+ GenetSimpleNetworkReceiveFilters, // ReceiveFilters
+ GenetSimpleNetworkStationAddress, // StationAddress
+ GenetSimpleNetworkStatistics, // Statistics
+ GenetSimpleNetworkMCastIPtoMAC, // MCastIpToMac
+ GenetSimpleNetworkNvData, // NvData
+ GenetSimpleNetworkGetStatus, // GetStatus
+ GenetSimpleNetworkTransmit, // Transmit
+ GenetSimpleNetworkReceive, // Receive
+ NULL, // WaitForPacket
+ NULL // Mode
+};
--
2.17.1
^ permalink raw reply related [flat|nested] 11+ messages in thread