From: "Leif Lindholm" <leif@nuviainc.com>
To: devel@edk2.groups.io, ard.biesheuvel@arm.com
Cc: philmd@redhat.com
Subject: Re: [edk2-devel] [PATCH edk2-platforms v2 3/7] Silicon/Broadcom/BcmGenetDxe: Add GENET driver
Date: Tue, 12 May 2020 15:31:59 +0100 [thread overview]
Message-ID: <20200512143159.GG21486@vanye> (raw)
In-Reply-To: <20200512075512.12645-4-ard.biesheuvel@arm.com>
On Tue, May 12, 2020 at 09:55:08 +0200, Ard Biesheuvel wrote:
> Add support for the Broadcom GENET v5 ethernet controller
> for the Raspberry Pi 4 (BCM2711)
>
> Co-authored-by: Jared McNeill <jmcneill@invisible.ca>
> Co-authored-by: Andrei Warkentin <awarkentin@vmware.com>
> Co-authored-by: Samer El-Haj-Mahmoud <samer.el-haj-mahmoud@arm.com>
> Co-authored-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
> ---
> Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf | 46 +-
> Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.h | 106 +++
> Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.h | 364 +++++++++
> Silicon/Broadcom/Drivers/Net/BcmGenetDxe/ComponentName.c | 198 +++++
> Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c | 408 ++++++++++
> Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.c | 405 ++++++++++
> Silicon/Broadcom/Drivers/Net/BcmGenetDxe/Genet.c | 114 ---
> Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c | 816 +++++++++++++++++++
> Silicon/Broadcom/Drivers/Net/BcmGenetDxe/SimpleNetwork.c | 834 ++++++++++++++++++++
> 9 files changed, 3164 insertions(+), 127 deletions(-)
>
> diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf
> index 9e9301608f24..3e98983c6b07 100644
> --- a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf
> +++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf
> @@ -1,40 +1,60 @@
> ## @file
> +# Component description file for Broadcom GENET driver.
> #
> +# Copyright (c) 2020, Jared McNeill All rights reserved.<BR>
> # Copyright (c) 2020, Jeremy Linton All rights reserved.<BR>
> +# Copyright (c) 2020, ARM Limited. All rights reserved.<BR>
> #
> # SPDX-License-Identifier: BSD-2-Clause-Patent
> #
> ##
>
> [Defines]
> - INF_VERSION = 0x0001001A
> + INF_VERSION = 1.27
> BASE_NAME = BcmGenetDxe
> FILE_GUID = e2b1eaf3-50b7-4ae1-b79e-ec8020cb57ac
> - MODULE_TYPE = DXE_DRIVER
> - VERSION_STRING = 0.1
> + MODULE_TYPE = UEFI_DRIVER
> + VERSION_STRING = 1.0
> ENTRY_POINT = GenetEntryPoint
> + UNLOAD_IMAGE = GenetUnload
>
> [Sources]
> - Genet.c
> + ComponentName.c
> + DriverBinding.c
> + GenericPhy.c
> + GenericPhy.h
> + GenetUtil.c
> + GenetUtil.h
> + 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/GenericPhy.h b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.h
> new file mode 100644
> index 000000000000..58b52722b4e3
> --- /dev/null
> +++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.h
> @@ -0,0 +1,106 @@
> +/** @file
> +
> + Copyright (c) 2020 Jared McNeill. All rights reserved.
> + Copyright (c) 2020 Andrey Warkentin <andrey.warkentin@gmail.com>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef GENERICPHY_H__
> +#define GENERICPHY_H__
> +
> +#define GENERIC_PHY_BMCR 0x00
> +#define GENERIC_PHY_BMCR_RESET BIT15
> +#define GENERIC_PHY_BMCR_ANE BIT12
> +#define GENERIC_PHY_BMCR_RESTART_AN BIT9
> +#define GENERIC_PHY_BMSR 0x01
> +#define GENERIC_PHY_BMSR_ANEG_COMPLETE BIT5
> +#define GENERIC_PHY_BMSR_LINK_STATUS BIT2
> +#define GENERIC_PHY_PHYIDR1 0x02
> +#define GENERIC_PHY_PHYIDR2 0x03
> +#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
> +#define GENERIC_PHY_ANLPAR 0x05
> +#define GENERIC_PHY_GBCR 0x09
> +#define GENERIC_PHY_GBCR_1000BASET_FDX BIT9
> +#define GENERIC_PHY_GBCR_1000BASET BIT8
> +#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/GenetUtil.h b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.h
> new file mode 100644
> index 000000000000..5ae2e0bad273
> --- /dev/null
> +++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.h
> @@ -0,0 +1,364 @@
> +/** @file
> +
> + Copyright (c) 2020 Jared McNeill <jmcneill@invisible.ca>
> + Copyright (c) 2020, ARM Limited. All rights reserved.
> + Copyright (c) 2020 Andrey Warkentin <andrey.warkentin@gmail.com>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef GENET_UTIL_H__
> +#define GENET_UTIL_H__
> +
> +#include <Uefi.h>
> +
> +#include <Protocol/DriverSupportedEfiVersion.h>
> +#include <Protocol/BcmGenetPlatformDevice.h>
> +#include <Protocol/SimpleNetwork.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/NetLib.h>
> +#include <Library/UefiLib.h>
Could we make sure this file includes only those headers it needs for
itself? (As per https://edk2-docs.gitbook.io/edk-ii-c-coding-standards-specification/5_source_files/53_include_files#5-3-4-include-files-may-include-only-those-headers-that-it-directly-depends-upon)
> +
> +#include "GenericPhy.h"
> +
> +/*
> + * 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')
Swedish person has slight giggle, stays silent, moves on.
> +#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/ComponentName.c b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/ComponentName.c
> new file mode 100644
> index 000000000000..b4b8896593f3
> --- /dev/null
> +++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/ComponentName.c
> @@ -0,0 +1,198 @@
> +/** @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 "GenetUtil.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..57f2fb17cb17
> --- /dev/null
> +++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c
> @@ -0,0 +1,408 @@
> +/** @file
> + Device driver for the Broadcom GENET controller
> +
> + Copyright (c) 2020 Jared McNeill. All rights reserved.
> + Copyright (c) 2020, ARM Limited. All rights reserved.
> + Copyright (c) 2020 Andrey Warkentin <andrey.warkentin@gmail.com>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Library/DebugLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +
> +#include <Protocol/BcmGenetPlatformDevice.h>
> +
> +#include "GenetUtil.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..ff67602c92ff
> --- /dev/null
> +++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.c
> @@ -0,0 +1,405 @@
> +/** @file
> +
> + Copyright (c) 2020 Jared McNeill. All rights reserved.
> + Copyright (c) 2020 Andrey Warkentin <andrey.warkentin@gmail.com>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Uefi.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +
> +#include "GenericPhy.h"
> +
> +#define PHY_RESET_TIMEOUT 500
> +
> +/**
> + Perform a PHY register read.
> +
> + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
> + @param PhyAddr[in] PHY address.
> + @param Reg[in] PHY register.
> + @param Data[out] Pointer to register data read.
> +
> + @retval EFI_SUCCESS Data read successfully.
> + @retval EFI_DEVICE_ERROR Failed to read data.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +GenericPhyRead (
> + IN GENERIC_PHY_PRIVATE_DATA *Phy,
> + IN UINT8 PhyAddr,
> + IN UINT8 Reg,
> + OUT UINT16 *Data
> + )
> +{
> + return Phy->Read (Phy->PrivateData, PhyAddr, Reg, Data);
> +}
> +
> +/**
> + Perform a PHY register write.
> +
> + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
> + @param PhyAddr[in] PHY address.
> + @param Reg[in] PHY register.
> + @param Data[in] Pointer to register data to write.
> +
> + @retval EFI_SUCCESS Data written successfully.
> + @retval EFI_DEVICE_ERROR Failed to write data.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +GenericPhyWrite (
> + IN GENERIC_PHY_PRIVATE_DATA *Phy,
> + IN UINT8 PhyAddr,
> + IN UINT8 Reg,
> + IN UINT16 Data
> + )
> +{
> + return Phy->Write (Phy->PrivateData, PhyAddr, Reg, Data);
> +}
> +
> +/**
> + Process a PHY link speed change (e.g. with MAC layer).
> +
> + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
> + @param Speed[in] Speed setting.
> + @param Duplex[in] Duplex setting.
> +
> +**/
> +STATIC
> +VOID
> +GenericPhyConfigure (
> + IN GENERIC_PHY_PRIVATE_DATA *Phy,
> + IN GENERIC_PHY_SPEED Speed,
> + IN GENERIC_PHY_DUPLEX Duplex
> + )
> +{
> + Phy->Configure (Phy->PrivateData, Speed, Duplex);
> +}
> +
> +/**
> + Detect address for the first PHY seen, probing all possible addresses.
> +
> + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
> +
> + @retval EFI_SUCCESS Found a PHY and programmed Phy->PhyAddr
> + @retval EFI_DEVICE_ERROR Error reading/writing a PHY register.
> + @retval EFI_NOT_FOUND No PHY detected.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +GenericPhyDetect (
> + IN GENERIC_PHY_PRIVATE_DATA *Phy
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 PhyAddr;
> + UINT16 Id1, Id2;
> +
> + for (PhyAddr = 0; PhyAddr < 32; PhyAddr++) {
> + Status = GenericPhyRead (Phy, PhyAddr, GENERIC_PHY_PHYIDR1, &Id1);
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> + Status = GenericPhyRead (Phy, PhyAddr, GENERIC_PHY_PHYIDR2, &Id2);
> + if (EFI_ERROR (Status)) {
> + continue;
> + }
> + if (Id1 != 0xFFFF && Id2 != 0xFFFF) {
> + Phy->PhyAddr = PhyAddr;
> + DEBUG ((DEBUG_INFO,
> + "%a: PHY detected at address 0x%02X (PHYIDR1=0x%04X, PHYIDR2=0x%04X)\n",
> + __FUNCTION__, PhyAddr, Id1, Id2));
> + return EFI_SUCCESS;
> + }
> + }
> +
> + return EFI_NOT_FOUND;
> +}
> +
> +/**
> + Start link auto-negotiation on a PHY.
> +
> + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
> +
> + @retval EFI_SUCCESS Auto-netogiation started.
> + @retval EFI_DEVICE_ERROR PHY register read/write error.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +GenericPhyAutoNegotiate (
> + IN GENERIC_PHY_PRIVATE_DATA *Phy
> + )
> +{
> + EFI_STATUS Status;
> + UINT16 Anar, Gbcr, Bmcr;
This file contains a fair amount of definitely-not-camelcase variables
that apppear to refer to register names. Is there any chance of having
those register names added to a proper glossary as part of this file's
comment header?
> +
> + Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_ANAR, &Anar);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + Anar |= GENERIC_PHY_ANAR_100BASETX_FDX |
> + GENERIC_PHY_ANAR_100BASETX |
> + GENERIC_PHY_ANAR_10BASET_FDX |
> + GENERIC_PHY_ANAR_10BASET;
> + Status = GenericPhyWrite (Phy, Phy->PhyAddr, GENERIC_PHY_ANAR, Anar);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_GBCR, &Gbcr);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + Gbcr |= GENERIC_PHY_GBCR_1000BASET_FDX |
> + GENERIC_PHY_GBCR_1000BASET;
> + Status = GenericPhyWrite (Phy, Phy->PhyAddr, GENERIC_PHY_GBCR, Gbcr);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_BMCR, &Bmcr);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + Bmcr |= GENERIC_PHY_BMCR_ANE |
> + GENERIC_PHY_BMCR_RESTART_AN;
> + return GenericPhyWrite (Phy, Phy->PhyAddr, GENERIC_PHY_BMCR, Bmcr);
> +}
> +
> +/**
> + Initialize the first PHY detected, performing a reset and enabling
> + auto-negotiation.
> +
> + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
> +
> + @retval EFI_SUCCESS Auto-negotiation started.
> + @retval EFI_DEVICE_ERROR PHY register read/write error.
> + @retval EFI_TIMEOUT PHY reset time-out.
> + @retval EFI_NOT_FOUND No PHY detected.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GenericPhyInit (
> + IN GENERIC_PHY_PRIVATE_DATA *Phy
> + )
> +{
> + EFI_STATUS Status;
> +
> + ASSERT (Phy->Read != NULL);
> + ASSERT (Phy->Write != NULL);
> + ASSERT (Phy->Configure != NULL);
> +
> + Status = GenericPhyDetect (Phy);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = GenericPhyReset (Phy);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + return GenericPhyAutoNegotiate (Phy);
> +}
> +
> +/**
> + Perform a PHY reset.
> +
> + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
> +
> + @retval EFI_SUCCESS Auto-negotiation started.
> + @retval EFI_DEVICE_ERROR PHY register read/write error.
> + @retval EFI_TIMEOUT PHY reset time-out.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GenericPhyReset (
> + IN GENERIC_PHY_PRIVATE_DATA *Phy
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Retry;
> + UINT16 Data;
> +
> + // Start reset sequence
> + Status = GenericPhyWrite (Phy, Phy->PhyAddr, GENERIC_PHY_BMCR,
> + GENERIC_PHY_BMCR_RESET);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // Wait up to 500ms for it to complete
> + for (Retry = PHY_RESET_TIMEOUT; Retry > 0; Retry--) {
> + Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_BMCR, &Data);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + if ((Data & GENERIC_PHY_BMCR_RESET) == 0) {
> + break;
> + }
> + gBS->Stall (1000);
> + }
> + if (Retry == 0) {
> + return EFI_TIMEOUT;
> + }
> +
> + if (Phy->ResetAction != NULL) {
> + Phy->ResetAction (Phy->PrivateData);
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Probe link status.
> +
> + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
> +
> + @retval EFI_SUCCESS Link is up and auto-negotiation is complete.
> + @retval EFI_DEVICE_ERROR PHY register read/write error,
> +
> +**/
> +STATIC
> +EFI_STATUS
> +GenericPhyGetLinkStatus (
> + IN GENERIC_PHY_PRIVATE_DATA *Phy
> + )
> +{
> + EFI_STATUS Status;
> + UINT16 Bmsr;
> +
> + Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_BMSR, &Bmsr);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if ((Bmsr & GENERIC_PHY_BMSR_LINK_STATUS) == 0) {
> + return EFI_TIMEOUT;
> + }
> +
> + if ((Bmsr & GENERIC_PHY_BMSR_ANEG_COMPLETE) == 0) {
> + return EFI_TIMEOUT;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Return PHY link configuration.
> +
> + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
> + @param Speed[out] Pointer to store link speed.
> + @param Duplex[out] Pointer to store link duplex setting.
> +
> + @retval EFI_SUCCESS Link configuration settings read.
> + @retval EFI_DEVICE_ERROR PHY register read/write error,
> +
> +**/
> +STATIC
> +EFI_STATUS
> +GenericPhyGetConfig (
> + IN GENERIC_PHY_PRIVATE_DATA *Phy,
> + OUT GENERIC_PHY_SPEED *Speed,
> + OUT GENERIC_PHY_DUPLEX *Duplex
> + )
> +{
> + EFI_STATUS Status;
> + UINT16 Gbcr, Gbsr, Anlpar, Anar;
> + UINT16 Gb, An;
> +
> + Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_GBCR, &Gbcr);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_GBSR, &Gbsr);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_ANLPAR, &Anlpar);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + Status = GenericPhyRead (Phy, Phy->PhyAddr, GENERIC_PHY_ANAR, &Anar);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Gb = (Gbsr >> 2) & Gbcr;
> + An = Anlpar & Anar;
> +
> + if ((Gb & (GENERIC_PHY_GBCR_1000BASET_FDX |
> + GENERIC_PHY_GBCR_1000BASET)) != 0) {
> + *Speed = PHY_SPEED_1000;
> + *Duplex = (Gb & GENERIC_PHY_GBCR_1000BASET_FDX) ? PHY_DUPLEX_FULL
> + : PHY_DUPLEX_HALF;
> + } else if ((An & (GENERIC_PHY_ANAR_100BASETX_FDX |
> + GENERIC_PHY_ANAR_100BASETX)) != 0) {
> + *Speed = PHY_SPEED_100;
> + *Duplex = (An & GENERIC_PHY_ANAR_100BASETX_FDX) ? PHY_DUPLEX_FULL
> + : PHY_DUPLEX_HALF;
> + } else {
> + *Speed = PHY_SPEED_10;
> + *Duplex = (An & GENERIC_PHY_ANAR_10BASET_FDX) ? PHY_DUPLEX_FULL
> + : PHY_DUPLEX_HALF;
> + }
> +
> + DEBUG ((DEBUG_INFO, "%a: Link speed %d Mbps, %a-duplex\n",
> + __FUNCTION__, *Speed, *Duplex == PHY_DUPLEX_FULL ? "full" : "half"));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Update link status, propagating PHY link state into the MAC layer.
> +
> + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA.
> +
> + @retval EFI_SUCCESS Link is up.
> + @retval EFI_DEVICE_ERROR PHY register read/write error.
> + @retval EFI_NOT_READY Link is down.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GenericPhyUpdateConfig (
> + IN GENERIC_PHY_PRIVATE_DATA *Phy
> + )
> +{
> + EFI_STATUS Status;
> + GENERIC_PHY_SPEED Speed;
> + GENERIC_PHY_DUPLEX Duplex;
> + BOOLEAN LinkUp;
> +
> + Status = GenericPhyGetLinkStatus (Phy);
> + LinkUp = EFI_ERROR (Status) ? FALSE : TRUE;
> +
> + if (Phy->LinkUp != LinkUp) {
> + if (LinkUp) {
> + DEBUG ((DEBUG_VERBOSE, "%a: Link is up\n", __FUNCTION__));
> +
> + Status = GenericPhyGetConfig (Phy, &Speed, &Duplex);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + GenericPhyConfigure (Phy, Speed, Duplex);
> + } else {
> + DEBUG ((DEBUG_VERBOSE, "%a: Link is down\n", __FUNCTION__));
> + }
> + }
> +
> + Phy->LinkUp = LinkUp;
> +
> + return LinkUp ? EFI_SUCCESS : EFI_NOT_READY;
> +}
> diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/Genet.c b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/Genet.c
> deleted file mode 100644
> index d40ce8b07a9d..000000000000
> --- a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/Genet.c
> +++ /dev/null
> @@ -1,114 +0,0 @@
> -/** @file
> -
> - Copyright (c) 2020, Jeremy Linton All rights reserved.<BR>
> -
> - SPDX-License-Identifier: BSD-2-Clause-Patent
> -
> - This driver acts like a stub to set the Broadcom
> - Genet MAC address, until the actual network driver
> - is in place.
> -
> -**/
> -
> -#include <Library/ArmLib.h>
> -#include <Library/DebugLib.h>
> -#include <Library/IoLib.h>
> -#include <Library/PcdLib.h>
> -#include <Library/UefiBootServicesTableLib.h>
> -#include <Library/UefiLib.h>
> -
> -#include <Net/Genet.h>
> -#include <PiDxe.h>
> -
> -STATIC
> -VOID
> -RMWRegister (
> - UINT32 Offset,
> - UINT32 Mask,
> - UINT32 In
> - )
> -{
> - EFI_PHYSICAL_ADDRESS Addr;
> - UINT32 Data;
> - UINT32 Shift;
> -
> - Addr = GENET_BASE_ADDRESS + Offset;
> - Data = 0;
> - Shift = 1;
> - if (In) {
> - while (!(Mask & Shift))
> - Shift <<= 1;
> - Data = (MmioRead32 (Addr) & ~Mask) | ((In * Shift) & Mask);
> - } else {
> - Data = MmioRead32 (Addr) & ~Mask;
> - }
> -
> - MmioWrite32 (Addr, Data);
> -
> - ArmDataMemoryBarrier ();
> -}
> -
> -STATIC
> -VOID
> -WdRegister (
> - UINT32 Offset,
> - UINT32 In
> - )
> -{
> - EFI_PHYSICAL_ADDRESS Base = GENET_BASE_ADDRESS;
> -
> - MmioWrite32 (Base + Offset, In);
> -
> - ArmDataMemoryBarrier ();
> -}
> -
> -STATIC
> -VOID
> -SetMacAddress (
> - UINT8* MacAddr
> -)
> -{
> - // Bring the UMAC out of reset
> - RMWRegister (GENET_SYS_RBUF_FLUSH_CTRL, 0x2, 1);
> - gBS->Stall (10);
> - RMWRegister (GENET_SYS_RBUF_FLUSH_CTRL, 0x2, 0);
> -
> - // Update the MAC
> - DEBUG ((DEBUG_INFO, "Using MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
> - MacAddr[0], MacAddr[1], MacAddr[2], MacAddr[3], MacAddr[4], MacAddr[5]));
> -
> - WdRegister (GENET_UMAC_MAC0, (MacAddr[0] << 24) | (MacAddr[1] << 16) |
> - (MacAddr[2] << 8) | MacAddr[3]);
> - WdRegister (GENET_UMAC_MAC1, (MacAddr[4] << 8) | MacAddr[5]);
> -
> -}
> -
> -/**
> - The entry point of Genet UEFI Driver.
> -
> - @param ImageHandle The image handle of the UEFI Driver.
> - @param SystemTable A pointer to the EFI System Table.
> -
> - @retval EFI_SUCCESS The Driver or UEFI Driver exited normally.
> - @retval EFI_INCOMPATIBLE_VERSION _gUefiDriverRevision is greater than
> - SystemTable->Hdr.Revision.
> -
> -**/
> -EFI_STATUS
> -EFIAPI
> -GenetEntryPoint (
> - IN EFI_HANDLE ImageHandle,
> - IN EFI_SYSTEM_TABLE *SystemTable
> - )
> -{
> - UINT64 MacAddr;
> -
> - // Read the MAC address
> - MacAddr = PcdGet64 (PcdBcmGenetMacAddress);
> -
> - if (MacAddr != 0) {
> - SetMacAddress ((UINT8*)&MacAddr);
> - }
> -
> - return EFI_SUCCESS;
> -}
> diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c
> new file mode 100644
> index 000000000000..119691dbeb49
> --- /dev/null
> +++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c
> @@ -0,0 +1,816 @@
> +/** @file
> +
> + Copyright (c) 2020 Jared McNeill. All rights reserved.
> + Copyright (c) 2020 Andrey Warkentin <andrey.warkentin@gmail.com>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include "GenetUtil.h"
> +
> +#include <Library/DmaLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/UefiBootServicesTableLib.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))
Can we get rid of leading __ in macros?
Ideally, these macros would be in GenetUtil.h.
/
Leif
> +
> +#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..b2cae687b3d4
> --- /dev/null
> +++ b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/SimpleNetwork.c
> @@ -0,0 +1,834 @@
> +/** @file
> + Provides the Simple Network functions.
> +
> + Copyright (c) 2020 Jared McNeill. All rights reserved.
> + Copyright (c) 2020 Andrey Warkentin <andrey.warkentin@gmail.com>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "GenetUtil.h"
> +
> +#include <Library/DmaLib.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
>
>
>
>
next prev parent reply other threads:[~2020-05-12 14:32 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-05-12 7:55 [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4 Ard Biesheuvel
2020-05-12 7:55 ` [PATCH edk2-platforms v2 1/7] Platform/RaspberryPi4: set DMA translation for BCM Genet driver Ard Biesheuvel
2020-05-12 7:55 ` [PATCH edk2-platforms v2 2/7] Silicon/Broadcom: Add BcmGenetPlatformDevice protocol Ard Biesheuvel
2020-05-12 7:55 ` [PATCH edk2-platforms v2 3/7] Silicon/Broadcom/BcmGenetDxe: Add GENET driver Ard Biesheuvel
2020-05-12 14:31 ` Leif Lindholm [this message]
2020-05-12 7:55 ` [PATCH edk2-platforms v2 4/7] Platform/RaspberryPi4: Clean up PCDs out of the " Ard Biesheuvel
2020-05-12 7:55 ` [PATCH edk2-platforms v2 5/7] Platform/RaspberryPi4: Register GENET platform device protocol Ard Biesheuvel
2020-05-12 14:34 ` Leif Lindholm
2020-05-12 7:55 ` [PATCH edk2-platforms v2 6/7] Platform/RaspberryPi4: Remove PlatformPcdLib Ard Biesheuvel
2020-05-12 7:55 ` [PATCH edk2-platforms v2 7/7] Platform/RaspberryPi4: remove ASIX 88772b driver Ard Biesheuvel
2020-05-12 8:26 ` [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4 Ard Biesheuvel
2020-05-12 14:28 ` Ard Biesheuvel
2020-05-12 14:35 ` Leif Lindholm
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200512143159.GG21486@vanye \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox