From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web12.9831.1589301696056873078 for ; Tue, 12 May 2020 09:41:36 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: ard.biesheuvel@arm.com) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id B57E11FB; Tue, 12 May 2020 09:41:35 -0700 (PDT) Received: from e123331-lin.nice.arm.com (unknown [10.37.8.255]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 4FB433F305; Tue, 12 May 2020 09:41:34 -0700 (PDT) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: leif@nuviainc.com, philmd@redhat.com, Ard Biesheuvel Subject: [PATCH edk2-platforms v3 3/8] Silicon/Broadcom/BcmGenetDxe: Add GENET driver Date: Tue, 12 May 2020 18:41:20 +0200 Message-Id: <20200512164125.28139-4-ard.biesheuvel@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200512164125.28139-1-ard.biesheuvel@arm.com> References: <20200512164125.28139-1-ard.biesheuvel@arm.com> Add support for the Broadcom GENET v5 ethernet controller for the Raspberry Pi 4 (BCM2711) Co-authored-by: Jared McNeill Co-authored-by: Andrei Warkentin Co-authored-by: Samer El-Haj-Mahmoud Co-authored-by: Ard Biesheuvel Signed-off-by: Ard Biesheuvel --- 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.
# Copyright (c) 2020, Jeremy Linton All rights reserved.
+# Copyright (c) 2020, ARM Limited. All rights reserved.
# # 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 + Copyright (c) 2020, ARM Limited. All rights reserved. + Copyright (c) 2020 Andrey Warkentin + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef BCM_GENET_DXE_H__ +#define BCM_GENET_DXE_H__ + +#include +#include +#include +#include +#include +#include + +#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 + + 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 +#include +#include + +#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 + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include + +#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.
- - 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 -#include -#include -#include -#include -#include - -#include -#include - -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 + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include + +#include "BcmGenetDxe.h" + +#define GENET_PHY_RETRY 1000 + +STATIC CONST +EFI_PHYSICAL_ADDRESS mDmaAddressLimit = FixedPcdGet64 (PcdDmaDeviceLimit) - + FixedPcdGet64 (PcdDmaDeviceOffset); + +/** + Read a memory-mapped device CSR. + + @param Genet[in] Pointer to GENERIC_PHY_PRIVATE_DATA instance. + @param Offset[in] Register offset. + + @retval Value + +**/ +STATIC +UINT32 +GenetMmioRead ( + IN GENET_PRIVATE_DATA *Genet, + IN UINT32 Offset + ) +{ + ASSERT ((Offset & 3) == 0); + + return MmioRead32 (Genet->RegBase + Offset); +} + +/** + Write a memory-mapped device CSR. + + @param Genet[in] Pointer to GENERIC_PHY_PRIVATE_DATA instance. + @param Offset[in] Register offset. + @param Data[in] Data to write. + + @retval Value + +**/ +STATIC +VOID +GenetMmioWrite ( + IN GENET_PRIVATE_DATA *Genet, + IN UINT32 Offset, + IN UINT32 Data + ) +{ + ASSERT ((Offset & 3) == 0); + + MemoryFence (); + MmioWrite32 (Genet->RegBase + Offset, Data); +} + +/** + Perform a GENET PHY register read. + + @param Priv[in] Pointer to GENET_PRIVATE_DATA. + @param PhyAddr[in] PHY address. + @param Reg[in] PHY register. + @param Data[out] Pointer to register data read. + + @retval EFI_SUCCESS Data read successfully. + @retval EFI_DEVICE_ERROR Failed to read data. + +**/ +EFI_STATUS +EFIAPI +GenetPhyRead ( + IN VOID *Priv, + IN UINT8 PhyAddr, + IN UINT8 Reg, + OUT UINT16 *Data + ) +{ + GENET_PRIVATE_DATA *Genet; + UINTN Retry; + UINT32 Value; + + Genet = Priv; + Value = GENET_MDIO_READ | + GENET_MDIO_START_BUSY | + SHIFTIN (PhyAddr, GENET_MDIO_PMD) | + SHIFTIN (Reg, GENET_MDIO_REG); + GenetMmioWrite (Genet, GENET_MDIO_CMD, Value); + + for (Retry = GENET_PHY_RETRY; Retry > 0; Retry--) { + Value = GenetMmioRead (Genet, GENET_MDIO_CMD); + if ((Value & GENET_MDIO_START_BUSY) == 0) { + *Data = Value & 0xffff; + break; + } + gBS->Stall (10); + } + + if (Retry == 0) { + DEBUG ((DEBUG_ERROR, + "%a: Timeout reading PhyAddr %d, Reg %d\n", __FUNCTION__, PhyAddr, Reg)); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Perform a GENET PHY register write. + + @param Priv[in] Pointer to GENET_PRIVATE_DATA. + @param PhyAddr[in] PHY address. + @param Reg[in] PHY register. + @param Data[in] Pointer to register data to write. + + @retval EFI_SUCCESS Data written successfully. + @retval EFI_DEVICE_ERROR Failed to write data. + +**/ +EFI_STATUS +EFIAPI +GenetPhyWrite ( + IN VOID *Priv, + IN UINT8 PhyAddr, + IN UINT8 Reg, + IN UINT16 Data + ) +{ + GENET_PRIVATE_DATA *Genet; + UINTN Retry; + UINT32 Value; + + Genet = Priv; + Value = GENET_MDIO_WRITE | + GENET_MDIO_START_BUSY | + SHIFTIN (PhyAddr, GENET_MDIO_PMD) | + SHIFTIN (Reg, GENET_MDIO_REG); + GenetMmioWrite (Genet, GENET_MDIO_CMD, Value | Data); + + for (Retry = GENET_PHY_RETRY; Retry > 0; Retry--) { + Value = GenetMmioRead (Genet, GENET_MDIO_CMD); + if ((Value & GENET_MDIO_START_BUSY) == 0) { + break; + } + gBS->Stall (10); + } + + if (Retry == 0) { + DEBUG ((DEBUG_ERROR, + "%a: Timeout writing PhyAddr %d, Reg %d\n", __FUNCTION__, PhyAddr, Reg)); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Process a PHY link speed change (e.g. with MAC layer). + + @param Priv[in] Pointer to GENET_PRIVATE_DATA. + @param Speed[in] Speed setting. + @param Duplex[in] Duplex setting. + +**/ +VOID +EFIAPI +GenetPhyConfigure ( + IN VOID *Priv, + IN GENERIC_PHY_SPEED Speed, + IN GENERIC_PHY_DUPLEX Duplex + ) +{ + GENET_PRIVATE_DATA *Genet; + UINT32 Value; + + Genet = Priv; + Value = GenetMmioRead (Genet, GENET_EXT_RGMII_OOB_CTRL); + Value &= ~GENET_EXT_RGMII_OOB_OOB_DISABLE; + Value |= GENET_EXT_RGMII_OOB_RGMII_LINK; + Value |= GENET_EXT_RGMII_OOB_RGMII_MODE_EN; + if (Genet->PhyMode == GENET_PHY_MODE_RGMII) { + Value |= GENET_EXT_RGMII_OOB_ID_MODE_DISABLE; + } else { + Value &= ~GENET_EXT_RGMII_OOB_ID_MODE_DISABLE; + } + GenetMmioWrite (Genet, GENET_EXT_RGMII_OOB_CTRL, Value); + + Value = GenetMmioRead (Genet, GENET_UMAC_CMD); + Value &= ~GENET_UMAC_CMD_SPEED; + switch (Speed) { + case PHY_SPEED_1000: + Value |= SHIFTIN (GENET_UMAC_CMD_SPEED_1000, GENET_UMAC_CMD_SPEED); + break; + case PHY_SPEED_100: + Value |= SHIFTIN (GENET_UMAC_CMD_SPEED_100, GENET_UMAC_CMD_SPEED); + break; + default: + Value |= SHIFTIN (GENET_UMAC_CMD_SPEED_10, GENET_UMAC_CMD_SPEED); + break; + } + if (Duplex == PHY_DUPLEX_FULL) { + Value &= ~GENET_UMAC_CMD_HD_EN; + } else { + Value |= GENET_UMAC_CMD_HD_EN; + } + GenetMmioWrite (Genet, GENET_UMAC_CMD, Value); +} + +/** + Extra action to run after a PHY reset. This adds the appropriate clock + delay based on the PHY mode. + + @param Priv[in] Pointer to GENET_PRIVATE_DATA. + +**/ +EFI_STATUS +EFIAPI +GenetPhyResetAction ( + IN VOID *Priv + ) +{ + GENET_PRIVATE_DATA *Genet; + UINT16 Value; + EFI_STATUS Status; + + Genet = Priv; + Status = GenetPhyWrite (Priv, Genet->Phy.PhyAddr, BRGPHY_MII_AUXCTL, + BRGPHY_AUXCTL_SHADOW_MISC | + (BRGPHY_AUXCTL_SHADOW_MISC << BRGPHY_AUXCTL_MISC_READ_SHIFT)); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GenetPhyRead (Priv, Genet->Phy.PhyAddr, BRGPHY_MII_AUXCTL, &Value); + if (EFI_ERROR (Status)) { + return Status; + } + + Value &= BRGPHY_AUXCTL_MISC_DATA_MASK; + + if (Genet->PhyMode == GENET_PHY_MODE_RGMII_RXID || + Genet->PhyMode == GENET_PHY_MODE_RGMII_ID) { + Value |= BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN; + } else { + Value &= ~BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN; + } + + Status = GenetPhyWrite (Priv, Genet->Phy.PhyAddr, BRGPHY_MII_AUXCTL, + BRGPHY_AUXCTL_MISC_WRITE_EN | BRGPHY_AUXCTL_SHADOW_MISC | Value); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GenetPhyWrite (Priv, Genet->Phy.PhyAddr, BRGPHY_MII_SHADOW_1C, + BRGPHY_SHADOW_1C_CLK_CTRL); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GenetPhyRead (Priv, Genet->Phy.PhyAddr, BRGPHY_MII_SHADOW_1C, &Value); + if (EFI_ERROR (Status)) { + return Status; + } + + Value &= BRGPHY_SHADOW_1C_DATA_MASK; + + if (Genet->PhyMode == GENET_PHY_MODE_RGMII_TXID || + Genet->PhyMode == GENET_PHY_MODE_RGMII_ID) { + Value |= BRGPHY_SHADOW_1C_GTXCLK_EN; + } else { + Value &= ~BRGPHY_SHADOW_1C_GTXCLK_EN; + } + + Status = GenetPhyWrite (Priv, Genet->Phy.PhyAddr, BRGPHY_MII_SHADOW_1C, + BRGPHY_SHADOW_1C_WRITE_EN | BRGPHY_SHADOW_1C_CLK_CTRL | Value); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + Reset GENET. + + @param Genet[in] Pointer to GENET_PRIVATE_DATA. + +**/ +VOID +GenetReset ( + IN GENET_PRIVATE_DATA *Genet + ) +{ + UINT32 Value; + + Value = GenetMmioRead (Genet, GENET_SYS_RBUF_FLUSH_CTRL); + Value |= GENET_SYS_RBUF_FLUSH_RESET; + GenetMmioWrite (Genet, GENET_SYS_RBUF_FLUSH_CTRL, Value); + gBS->Stall (10); + + Value &= ~GENET_SYS_RBUF_FLUSH_RESET; + GenetMmioWrite (Genet, GENET_SYS_RBUF_FLUSH_CTRL, Value); + gBS->Stall (10); + + GenetMmioWrite (Genet, GENET_SYS_RBUF_FLUSH_CTRL, 0); + gBS->Stall (10); + + GenetMmioWrite (Genet, GENET_UMAC_CMD, 0); + GenetMmioWrite (Genet, GENET_UMAC_CMD, + GENET_UMAC_CMD_LCL_LOOP_EN | GENET_UMAC_CMD_SW_RESET); + gBS->Stall (10); + GenetMmioWrite (Genet, GENET_UMAC_CMD, 0); + + GenetMmioWrite (Genet, GENET_UMAC_MIB_CTRL, + GENET_UMAC_MIB_RESET_RUNT | GENET_UMAC_MIB_RESET_RX | GENET_UMAC_MIB_RESET_TX); + GenetMmioWrite (Genet, GENET_UMAC_MIB_CTRL, 0); + + GenetMmioWrite (Genet, GENET_UMAC_MAX_FRAME_LEN, GENET_MAX_PACKET_SIZE); + + Value = GenetMmioRead (Genet, GENET_RBUF_CTRL); + Value |= GENET_RBUF_ALIGN_2B; + GenetMmioWrite (Genet, GENET_RBUF_CTRL, Value); + + GenetMmioWrite (Genet, GENET_RBUF_TBUF_SIZE_CTRL, 1); +} + +/** + Set the station address. + + @param Genet[in] Pointer to GENET_PRIVATE_DATA. + @param MacAddr[in] MAC address to set. + +**/ +VOID +EFIAPI +GenetSetMacAddress ( + IN GENET_PRIVATE_DATA *Genet, + IN EFI_MAC_ADDRESS *MacAddr + ) +{ + UINT32 Value; + + Value = MacAddr->Addr[3] | + MacAddr->Addr[2] << 8 | + MacAddr->Addr[1] << 16 | + MacAddr->Addr[0] << 24; + GenetMmioWrite (Genet, GENET_UMAC_MAC0, Value); + Value = MacAddr->Addr[5] | + MacAddr->Addr[4] << 8; + GenetMmioWrite (Genet, GENET_UMAC_MAC1, Value); +} + +/** + Set a PHY mode. + + @param Genet[in] Pointer to GENET_PRIVATE_DATA. + @param PhyMode[in] Mode to set. + +**/ +VOID +GenetSetPhyMode ( + IN GENET_PRIVATE_DATA *Genet, + IN GENET_PHY_MODE PhyMode + ) +{ + UINT32 Value; + + switch (PhyMode) { + case GENET_PHY_MODE_RGMII: + case GENET_PHY_MODE_RGMII_RXID: + case GENET_PHY_MODE_RGMII_TXID: + case GENET_PHY_MODE_RGMII_ID: + Value = GENET_SYS_PORT_MODE_EXT_GPHY; + break; + default: + Value = 0; + break; + } + GenetMmioWrite (Genet, GENET_SYS_PORT_CTRL, Value); +} + +/** + Enable TX/RX. + + @param Genet[in] Pointer to GENET_PRIVATE_DATA. + +**/ +VOID +GenetEnableTxRx ( + IN GENET_PRIVATE_DATA *Genet + ) +{ + UINT32 Value; + + // Start TX DMA on default queue + Value = GenetMmioRead (Genet, GENET_TX_DMA_CTRL); + Value |= GENET_TX_DMA_CTRL_EN | + GENET_TX_DMA_CTRL_RBUF_EN (GENET_DMA_DEFAULT_QUEUE); + GenetMmioWrite (Genet, GENET_TX_DMA_CTRL, Value); + + // Start RX DMA on default queue + Value = GenetMmioRead (Genet, GENET_RX_DMA_CTRL); + Value |= GENET_RX_DMA_CTRL_EN | + GENET_RX_DMA_CTRL_RBUF_EN (GENET_DMA_DEFAULT_QUEUE); + GenetMmioWrite (Genet, GENET_RX_DMA_CTRL, Value); + + // Enable transmitter and receiver + Value = GenetMmioRead (Genet, GENET_UMAC_CMD); + Value |= GENET_UMAC_CMD_TXEN | GENET_UMAC_CMD_RXEN; + GenetMmioWrite (Genet, GENET_UMAC_CMD, Value); + + // Enable interrupts + GenetMmioWrite (Genet, GENET_INTRL2_CPU_CLEAR_MASK, + GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE); +} + +/** + Disable TX/RX. + + @param Genet[in] Pointer to GENET_PRIVATE_DATA. + +**/ +VOID +GenetDisableTxRx ( + IN GENET_PRIVATE_DATA *Genet + ) +{ + UINT32 Value; + + // Disable interrupts + GenetMmioWrite (Genet, GENET_INTRL2_CPU_SET_MASK, 0xFFFFFFFF); + GenetMmioWrite (Genet, GENET_INTRL2_CPU_CLEAR, 0xFFFFFFFF); + + // Disable receiver + Value = GenetMmioRead (Genet, GENET_UMAC_CMD); + Value &= ~GENET_UMAC_CMD_RXEN; + GenetMmioWrite (Genet, GENET_UMAC_CMD, Value); + + // Stop RX DMA + Value = GenetMmioRead (Genet, GENET_RX_DMA_CTRL); + Value &= ~GENET_RX_DMA_CTRL_EN; + Value &= ~GENET_RX_DMA_CTRL_RBUF_EN (GENET_DMA_DEFAULT_QUEUE); + GenetMmioWrite (Genet, GENET_RX_DMA_CTRL, Value); + + // Stop TX DMA + Value = GenetMmioRead (Genet, GENET_TX_DMA_CTRL); + Value &= ~GENET_TX_DMA_CTRL_EN; + Value &= ~GENET_TX_DMA_CTRL_RBUF_EN (GENET_DMA_DEFAULT_QUEUE); + GenetMmioWrite (Genet, GENET_TX_DMA_CTRL, Value); + + // Flush data in the TX FIFO + GenetMmioWrite (Genet, GENET_UMAC_TX_FLUSH, 1); + gBS->Stall (10); + GenetMmioWrite (Genet, GENET_UMAC_TX_FLUSH, 0); + + // Disable transmitter + Value = GenetMmioRead (Genet, GENET_UMAC_CMD); + Value &= ~GENET_UMAC_CMD_TXEN; + GenetMmioWrite (Genet, GENET_UMAC_CMD, Value); +} + +/** + Change promiscuous mode state. + + @param Genet[in] Pointer to GENET_PRIVATE_DATA. + @param Enable[in] Promiscuous mode state. + +**/ +VOID +GenetSetPromisc ( + IN GENET_PRIVATE_DATA *Genet, + IN BOOLEAN Enable + ) +{ + UINT32 Value; + + Value = GenetMmioRead (Genet, GENET_UMAC_CMD); + if (Enable) { + Value |= GENET_UMAC_CMD_PROMISC; + } else { + Value &= ~GENET_UMAC_CMD_PROMISC; + } + GenetMmioWrite (Genet, GENET_UMAC_CMD, Value); +} + +/** + Enable the MAC filter for the Ethernet broadcast address + + @param Genet[in] Pointer to GENET_PRIVATE_DATA. + @param Enable[in] Promiscuous mode state. + +**/ +VOID +GenetEnableBroadcastFilter ( + IN GENET_PRIVATE_DATA *Genet, + IN BOOLEAN Enable + ) +{ + CONST EFI_MAC_ADDRESS *MacAddr; + UINT32 Value; + + if (Enable) { + MacAddr = &Genet->SnpMode.CurrentAddress; + + GenetMmioWrite (Genet, GENET_UMAC_MDF_ADDR0 (0), + MacAddr->Addr[1] | MacAddr->Addr[0] << 8); + GenetMmioWrite (Genet, GENET_UMAC_MDF_ADDR1 (0), + MacAddr->Addr[5] | MacAddr->Addr[4] << 8 | + MacAddr->Addr[3] << 16 | MacAddr->Addr[2] << 24); + + GenetMmioWrite (Genet, GENET_UMAC_MDF_ADDR0 (1), 0xffff); + GenetMmioWrite (Genet, GENET_UMAC_MDF_ADDR1 (1), 0xffffffff); + + Value = BIT16 | BIT15; // enable filters 0 and 1 + } else { + Value = 0; + } + GenetMmioWrite (Genet, GENET_UMAC_MDF_CTRL, Value); +} + +/** + Configure DMA TX and RX queues, enabling them. + + @param Genet[in] Pointer to GENET_PRIVATE_DATA. + +**/ +VOID +GenetDmaInitRings ( + IN GENET_PRIVATE_DATA *Genet + ) +{ + UINT8 Qid; + + Qid = GENET_DMA_DEFAULT_QUEUE; + + Genet->TxQueued = 0; + Genet->TxNext = 0; + Genet->TxConsIndex = 0; + Genet->TxProdIndex = 0; + + Genet->RxConsIndex = 0; + Genet->RxProdIndex = 0; + + // Configure TX queue + GenetMmioWrite (Genet, GENET_TX_SCB_BURST_SIZE, 0x08); + GenetMmioWrite (Genet, GENET_TX_DMA_READ_PTR_LO (Qid), 0); + GenetMmioWrite (Genet, GENET_TX_DMA_READ_PTR_HI (Qid), 0); + GenetMmioWrite (Genet, GENET_TX_DMA_CONS_INDEX (Qid), 0); + GenetMmioWrite (Genet, GENET_TX_DMA_PROD_INDEX (Qid), 0); + GenetMmioWrite (Genet, GENET_TX_DMA_RING_BUF_SIZE (Qid), + SHIFTIN (GENET_DMA_DESC_COUNT, GENET_TX_DMA_RING_BUF_SIZE_DESC_COUNT) | + SHIFTIN (GENET_MAX_PACKET_SIZE, GENET_TX_DMA_RING_BUF_SIZE_BUF_LENGTH)); + GenetMmioWrite (Genet, GENET_TX_DMA_START_ADDR_LO (Qid), 0); + GenetMmioWrite (Genet, GENET_TX_DMA_START_ADDR_HI (Qid), 0); + GenetMmioWrite (Genet, GENET_TX_DMA_END_ADDR_LO (Qid), + GENET_DMA_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1); + GenetMmioWrite (Genet, GENET_TX_DMA_END_ADDR_HI (Qid), 0); + GenetMmioWrite (Genet, GENET_TX_DMA_MBUF_DONE_THRES (Qid), 1); + GenetMmioWrite (Genet, GENET_TX_DMA_FLOW_PERIOD (Qid), 0); + GenetMmioWrite (Genet, GENET_TX_DMA_WRITE_PTR_LO (Qid), 0); + GenetMmioWrite (Genet, GENET_TX_DMA_WRITE_PTR_HI (Qid), 0); + + // Enable TX queue + GenetMmioWrite (Genet, GENET_TX_DMA_RING_CFG, (1U << Qid)); + + // Configure RX queue + GenetMmioWrite (Genet, GENET_RX_SCB_BURST_SIZE, 0x08); + GenetMmioWrite (Genet, GENET_RX_DMA_WRITE_PTR_LO (Qid), 0); + GenetMmioWrite (Genet, GENET_RX_DMA_WRITE_PTR_HI (Qid), 0); + GenetMmioWrite (Genet, GENET_RX_DMA_PROD_INDEX (Qid), 0); + GenetMmioWrite (Genet, GENET_RX_DMA_CONS_INDEX (Qid), 0); + GenetMmioWrite (Genet, GENET_RX_DMA_RING_BUF_SIZE (Qid), + SHIFTIN (GENET_DMA_DESC_COUNT, GENET_RX_DMA_RING_BUF_SIZE_DESC_COUNT) | + SHIFTIN (GENET_MAX_PACKET_SIZE, GENET_RX_DMA_RING_BUF_SIZE_BUF_LENGTH)); + GenetMmioWrite (Genet, GENET_RX_DMA_START_ADDR_LO (Qid), 0); + GenetMmioWrite (Genet, GENET_RX_DMA_START_ADDR_HI (Qid), 0); + GenetMmioWrite (Genet, GENET_RX_DMA_END_ADDR_LO (Qid), + GENET_DMA_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1); + GenetMmioWrite (Genet, GENET_RX_DMA_END_ADDR_HI (Qid), 0); + GenetMmioWrite (Genet, GENET_RX_DMA_XON_XOFF_THRES (Qid), + SHIFTIN (5, GENET_RX_DMA_XON_XOFF_THRES_LO) | + SHIFTIN (GENET_DMA_DESC_COUNT >> 4, GENET_RX_DMA_XON_XOFF_THRES_HI)); + GenetMmioWrite (Genet, GENET_RX_DMA_READ_PTR_LO (Qid), 0); + GenetMmioWrite (Genet, GENET_RX_DMA_READ_PTR_HI (Qid), 0); + + // Enable RX queue + GenetMmioWrite (Genet, GENET_RX_DMA_RING_CFG, (1U << Qid)); +} + +/** + Allocate DMA buffers for RX. + + @param Genet[in] Pointer to GENET_PRIVATE_DATA. + + @retval EFI_SUCCESS DMA buffers allocated. + @retval EFI_OUT_OF_RESOURCES DMA buffers could not be allocated. +**/ +EFI_STATUS +GenetDmaAlloc ( + IN GENET_PRIVATE_DATA *Genet + ) +{ + EFI_STATUS Status; + + Genet->RxBuffer = mDmaAddressLimit; + Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, + EFI_SIZE_TO_PAGES (GENET_MAX_PACKET_SIZE * GENET_DMA_DESC_COUNT), + &Genet->RxBuffer); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: Failed to allocate RX buffer: %r\n", __FUNCTION__, Status)); + } + return Status; +} + +/** + Given an RX buffer descriptor index, program the IO address of the buffer into the hardware. + + @param Genet[in] Pointer to GENET_PRIVATE_DATA. + @param DescIndex[in] Index of RX buffer descriptor. + + @retval EFI_SUCCESS DMA buffers allocated. + @retval Others Programmatic errors, as buffers come from DmaAllocateBuffer, and thus + cannot fail DmaMap (for the expected NonCoherentDmaLib). +**/ +EFI_STATUS +GenetDmaMapRxDescriptor ( + IN GENET_PRIVATE_DATA * Genet, + IN UINT8 DescIndex + ) +{ + EFI_STATUS Status; + UINTN DmaNumberOfBytes; + + ASSERT (Genet->RxBufferMap[DescIndex].Mapping == NULL); + ASSERT (Genet->RxBuffer != 0); + + DmaNumberOfBytes = GENET_MAX_PACKET_SIZE; + Status = DmaMap (MapOperationBusMasterWrite, + GENET_RX_BUFFER (Genet, DescIndex), + &DmaNumberOfBytes, + &Genet->RxBufferMap[DescIndex].PhysAddress, + &Genet->RxBufferMap[DescIndex].Mapping); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to map RX buffer: %r\n", + __FUNCTION__, Status)); + return Status; + } + + GenetMmioWrite (Genet, GENET_RX_DESC_ADDRESS_LO (DescIndex), + Genet->RxBufferMap[DescIndex].PhysAddress & 0xFFFFFFFF); + GenetMmioWrite (Genet, GENET_RX_DESC_ADDRESS_HI (DescIndex), + (Genet->RxBufferMap[DescIndex].PhysAddress >> 32) & 0xFFFFFFFF); + + 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 + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#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