public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
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
> 
> 
> 
> 

  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