public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4
@ 2020-05-12  7:55 Ard Biesheuvel
  2020-05-12  7:55 ` [PATCH edk2-platforms v2 1/7] Platform/RaspberryPi4: set DMA translation for BCM Genet driver Ard Biesheuvel
                   ` (9 more replies)
  0 siblings, 10 replies; 13+ messages in thread
From: Ard Biesheuvel @ 2020-05-12  7:55 UTC (permalink / raw)
  To: devel
  Cc: leif, philmd, Ard Biesheuvel, Pete Batard, Jared McNeill,
	Andrei Warkentin, Samer El-Haj-Mahmoud, Jeremy Linton

This is a followup to Samer's v1 [0], and incorporates all the delta
changes posted for review over the past couple of days. This is a
roundup of all that work, and therefore supersedes it.

It provides an implementation of the SimpleNetworkProtocol for the
Raspberry Pi4's GENET network controller, in a way that adheres to the
UEFI driver model.

The original submission was provided by Jared, based on Jeremy's MAC
programming-only driver and the existing BSD driver for the GENET IP.
Cumulative changes and fixes as well as review feedback were provided
by all of the below.

https://github.com/ardbiesheuvel/edk2-platforms/tree/rpi4_genet_combi_v2

Cc: Pete Batard <pete@akeo.ie>
Cc: Jared McNeill <jmcneill@invisible.ca>
Cc: Andrei Warkentin <awarkentin@vmware.com>
Cc: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud@arm.com>
Cc: Jeremy Linton <jeremy.linton@arm.com>

Andrei Warkentin (1):
  Platform/RaspberryPi4: Remove PlatformPcdLib

Ard Biesheuvel (6):
  Platform/RaspberryPi4: set DMA translation for BCM Genet driver
  Silicon/Broadcom: Add BcmGenetPlatformDevice protocol
  Silicon/Broadcom/BcmGenetDxe: Add GENET driver
  Platform/RaspberryPi4: Clean up PCDs out of the GENET driver
  Platform/RaspberryPi4: Register GENET platform device protocol
  Platform/RaspberryPi4: remove ASIX 88772b driver

 Silicon/Broadcom/Bcm27xx/Bcm27xx.dec          |   2 +
 Silicon/Broadcom/Drivers/Net/BcmNet.dec       |   8 +-
 Platform/RaspberryPi/RPi4/RPi4.dsc            |   8 +-
 Platform/RaspberryPi/RPi4/RPi4.fdf            |   1 -
 .../RaspberryPi/AcpiTables/AcpiTables.inf     |   2 +-
 .../Drivers/ConfigDxe/ConfigDxe.inf           |  29 +-
 .../Library/PlatformPcdLib/PlatformPcdLib.inf |  43 -
 .../Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf   |  46 +-
 .../Include/IndustryStandard/Bcm2711.h        |   3 +
 .../Drivers/Net/BcmGenetDxe/GenericPhy.h      | 106 +++
 .../Drivers/Net/BcmGenetDxe/GenetUtil.h       | 364 ++++++++
 .../Broadcom/Drivers/Net/Include/Net/Genet.h  |  21 -
 .../Include/Protocol/BcmGenetPlatformDevice.h |  24 +
 .../RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c | 108 ++-
 .../Library/PlatformPcdLib/PlatformPcdLib.c   |  45 -
 .../Drivers/Net/BcmGenetDxe/ComponentName.c   | 198 +++++
 .../Drivers/Net/BcmGenetDxe/DriverBinding.c   | 408 +++++++++
 .../Drivers/Net/BcmGenetDxe/GenericPhy.c      | 405 +++++++++
 .../Broadcom/Drivers/Net/BcmGenetDxe/Genet.c  | 114 ---
 .../Drivers/Net/BcmGenetDxe/GenetUtil.c       | 816 +++++++++++++++++
 .../Drivers/Net/BcmGenetDxe/SimpleNetwork.c   | 834 ++++++++++++++++++
 Platform/RaspberryPi/AcpiTables/Dsdt.asl      |   2 +-
 22 files changed, 3319 insertions(+), 268 deletions(-)
 delete mode 100644 Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf
 create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.h
 create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.h
 delete mode 100644 Silicon/Broadcom/Drivers/Net/Include/Net/Genet.h
 create mode 100644 Silicon/Broadcom/Drivers/Net/Include/Protocol/BcmGenetPlatformDevice.h
 delete mode 100644 Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.c
 create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/ComponentName.c
 create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c
 create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.c
 delete mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/Genet.c
 create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c
 create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/SimpleNetwork.c

-- 
2.17.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH edk2-platforms v2 1/7] Platform/RaspberryPi4: set DMA translation for BCM Genet driver
  2020-05-12  7:55 [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4 Ard Biesheuvel
@ 2020-05-12  7:55 ` Ard Biesheuvel
  2020-05-12  7:55 ` [PATCH edk2-platforms v2 2/7] Silicon/Broadcom: Add BcmGenetPlatformDevice protocol Ard Biesheuvel
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Ard Biesheuvel @ 2020-05-12  7:55 UTC (permalink / raw)
  To: devel; +Cc: leif, philmd, Ard Biesheuvel

The driver for the Broadcom Genet network controller will shortly
be modified from a minimal MAC address programming driver to a true
SNP driver implementing full network functionality. Since this will
involve DMA, set the DmaLib parameters correctly in the platform.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
---
 Platform/RaspberryPi/RPi4/RPi4.dsc | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Platform/RaspberryPi/RPi4/RPi4.dsc b/Platform/RaspberryPi/RPi4/RPi4.dsc
index 455dd2c2ac3c..ccc9eb923436 100644
--- a/Platform/RaspberryPi/RPi4/RPi4.dsc
+++ b/Platform/RaspberryPi/RPi4/RPi4.dsc
@@ -685,6 +685,9 @@ [Components.common]
   Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf {
     <LibraryClasses>
       NULL|Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf
+    <PcdsFixedAtBuild>
+      gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset|0x00000000
+      gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit|0xffffffff
   }
 
   #
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH edk2-platforms v2 2/7] Silicon/Broadcom: Add BcmGenetPlatformDevice protocol
  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 ` Ard Biesheuvel
  2020-05-12  7:55 ` [PATCH edk2-platforms v2 3/7] Silicon/Broadcom/BcmGenetDxe: Add GENET driver Ard Biesheuvel
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Ard Biesheuvel @ 2020-05-12  7:55 UTC (permalink / raw)
  To: devel; +Cc: leif, philmd, Ard Biesheuvel

Add BcmGenetPlatformDevice definition for GENET. This protocol
will be used to register GENET platform device that is on a
non-discoverable bus.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
---
 Silicon/Broadcom/Drivers/Net/BcmNet.dec                                |  4 ++++
 Silicon/Broadcom/Drivers/Net/Include/Protocol/BcmGenetPlatformDevice.h | 24 ++++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/Silicon/Broadcom/Drivers/Net/BcmNet.dec b/Silicon/Broadcom/Drivers/Net/BcmNet.dec
index 4a55946e8f80..fda3caf0b4ef 100644
--- a/Silicon/Broadcom/Drivers/Net/BcmNet.dec
+++ b/Silicon/Broadcom/Drivers/Net/BcmNet.dec
@@ -1,6 +1,7 @@
 ## @file
 #
 #  Copyright (c) 2020, Pete Batard <pete@akeo.ie>
+#  Copyright (c) 2020, ARM Limited. All rights reserved.
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -18,6 +19,9 @@ [Includes]
 [Guids]
   gBcmNetTokenSpaceGuid = {0x12b97d70, 0x9149, 0x4c2f, {0x82, 0xd5, 0xad, 0xa9, 0x1e, 0x92, 0x75, 0xa1}}
 
+[Protocols]
+  gBcmGenetPlatformDeviceProtocolGuid = {0x5e485a22, 0x1bb0, 0x4e22, {0x85, 0x49, 0x41, 0xfc, 0xec, 0x85, 0xdf, 0xd3}}
+
 [PcdsFixedAtBuild]
   gBcmNetTokenSpaceGuid.PcdBcmGenetRegistersAddress|0x0|UINT64|0x00000001
 
diff --git a/Silicon/Broadcom/Drivers/Net/Include/Protocol/BcmGenetPlatformDevice.h b/Silicon/Broadcom/Drivers/Net/Include/Protocol/BcmGenetPlatformDevice.h
new file mode 100644
index 000000000000..3af4f4aec622
--- /dev/null
+++ b/Silicon/Broadcom/Drivers/Net/Include/Protocol/BcmGenetPlatformDevice.h
@@ -0,0 +1,24 @@
+/** @file
+
+  Copyright (c) 2020, ARM Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef BCM_GENET_PLATFORM_DEVICE_H
+#define BCM_GENET_PLATFORM_DEVICE_H
+
+#include <Uefi/UefiBaseType.h>
+
+#define BCM_GENET_PLATFORM_DEVICE_PROTOCOL_GUID \
+  {0x5e485a22, 0x1bb0, 0x4e22, {0x85, 0x49, 0x41, 0xfc, 0xec, 0x85, 0xdf, 0xd3}}
+
+typedef struct {
+  EFI_PHYSICAL_ADDRESS      BaseAddress;
+  EFI_MAC_ADDRESS           MacAddress;
+} BCM_GENET_PLATFORM_DEVICE_PROTOCOL;
+
+extern EFI_GUID gBcmGenetPlatformDeviceProtocolGuid;
+
+#endif
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH edk2-platforms v2 3/7] Silicon/Broadcom/BcmGenetDxe: Add GENET driver
  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 ` Ard Biesheuvel
  2020-05-12 14:31   ` [edk2-devel] " Leif Lindholm
  2020-05-12  7:55 ` [PATCH edk2-platforms v2 4/7] Platform/RaspberryPi4: Clean up PCDs out of the " Ard Biesheuvel
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 13+ messages in thread
From: Ard Biesheuvel @ 2020-05-12  7:55 UTC (permalink / raw)
  To: devel; +Cc: leif, philmd, Ard Biesheuvel

Add support for the Broadcom GENET v5 ethernet controller
for the Raspberry Pi 4 (BCM2711)

Co-authored-by: Jared McNeill <jmcneill@invisible.ca>
Co-authored-by: Andrei Warkentin <awarkentin@vmware.com>
Co-authored-by: Samer El-Haj-Mahmoud <samer.el-haj-mahmoud@arm.com>
Co-authored-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
---
 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf |  46 +-
 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/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>
+
+#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')
+#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;
+
+  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))
+
+#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


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH edk2-platforms v2 4/7] Platform/RaspberryPi4: Clean up PCDs out of the GENET driver
  2020-05-12  7:55 [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4 Ard Biesheuvel
                   ` (2 preceding siblings ...)
  2020-05-12  7:55 ` [PATCH edk2-platforms v2 3/7] Silicon/Broadcom/BcmGenetDxe: Add GENET driver Ard Biesheuvel
@ 2020-05-12  7:55 ` Ard Biesheuvel
  2020-05-12  7:55 ` [PATCH edk2-platforms v2 5/7] Platform/RaspberryPi4: Register GENET platform device protocol Ard Biesheuvel
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Ard Biesheuvel @ 2020-05-12  7:55 UTC (permalink / raw)
  To: devel; +Cc: leif, philmd, Ard Biesheuvel

Move PCDs from GENET driver to Raspberry Pi and Bcm27xx packages.
The Genet driver follows the UEFI driver model, so it should not have
PCDs defined that describe MMIO and MAC addresses of a single instance.
Also, move related definitions around, and update references accordingly.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
---
 Platform/RaspberryPi/RaspberryPi.dec                           |  3 +++
 Silicon/Broadcom/Bcm27xx/Bcm27xx.dec                           |  2 ++
 Silicon/Broadcom/Drivers/Net/BcmNet.dec                        |  6 ------
 Platform/RaspberryPi/RPi4/RPi4.dsc                             |  2 +-
 Platform/RaspberryPi/AcpiTables/AcpiTables.inf                 |  2 +-
 Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf |  5 +++--
 Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2711.h    |  3 +++
 Silicon/Broadcom/Drivers/Net/Include/Net/Genet.h               | 21 --------------------
 Platform/RaspberryPi/AcpiTables/Dsdt.asl                       |  2 +-
 9 files changed, 14 insertions(+), 32 deletions(-)

diff --git a/Platform/RaspberryPi/RaspberryPi.dec b/Platform/RaspberryPi/RaspberryPi.dec
index 1a3c44e0eb01..7a22621a6905 100644
--- a/Platform/RaspberryPi/RaspberryPi.dec
+++ b/Platform/RaspberryPi/RaspberryPi.dec
@@ -68,3 +68,6 @@ [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
   gRaspberryPiTokenSpaceGuid.PcdSystemTableMode|1|UINT32|0x0000001B
   gRaspberryPiTokenSpaceGuid.PcdRamMoreThan3GB|0|UINT32|0x00000019
   gRaspberryPiTokenSpaceGuid.PcdRamLimitTo3GB|0|UINT32|0x0000001A
+
+[PcdsDynamic]
+  gRaspberryPiTokenSpaceGuid.PcdBcmGenetMacAddress|0x0|UINT64|0x00000040
diff --git a/Silicon/Broadcom/Bcm27xx/Bcm27xx.dec b/Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
index cd6f86670d9f..2ace631f2450 100644
--- a/Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
+++ b/Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
@@ -24,3 +24,5 @@ [PcdsFixedAtBuild.common]
   gBcm27xxTokenSpaceGuid.PcdBcm27xxPciBusMmioAdr|0x0|UINT64|0x00000003
   gBcm27xxTokenSpaceGuid.PcdBcm27xxPciBusMmioLen|0x0|UINT32|0x00000004
   gBcm27xxTokenSpaceGuid.PcdBcm27xxPciCpuMmioAdr|0x0|UINT64|0x00000005
+
+  gBcm27xxTokenSpaceGuid.PcdBcmGenetRegistersAddress|0x0|UINT64|0x00000006
diff --git a/Silicon/Broadcom/Drivers/Net/BcmNet.dec b/Silicon/Broadcom/Drivers/Net/BcmNet.dec
index fda3caf0b4ef..4ddda6d3d6d0 100644
--- a/Silicon/Broadcom/Drivers/Net/BcmNet.dec
+++ b/Silicon/Broadcom/Drivers/Net/BcmNet.dec
@@ -21,9 +21,3 @@ [Guids]
 
 [Protocols]
   gBcmGenetPlatformDeviceProtocolGuid = {0x5e485a22, 0x1bb0, 0x4e22, {0x85, 0x49, 0x41, 0xfc, 0xec, 0x85, 0xdf, 0xd3}}
-
-[PcdsFixedAtBuild]
-  gBcmNetTokenSpaceGuid.PcdBcmGenetRegistersAddress|0x0|UINT64|0x00000001
-
-[PcdsDynamic]
-  gBcmNetTokenSpaceGuid.PcdBcmGenetMacAddress|0x0|UINT64|0x00000002
diff --git a/Platform/RaspberryPi/RPi4/RPi4.dsc b/Platform/RaspberryPi/RPi4/RPi4.dsc
index ccc9eb923436..0dca782c9058 100644
--- a/Platform/RaspberryPi/RPi4/RPi4.dsc
+++ b/Platform/RaspberryPi/RPi4/RPi4.dsc
@@ -405,8 +405,8 @@ [PcdsFixedAtBuild.common]
   #
   gRaspberryPiTokenSpaceGuid.PcdExtendedMemoryBase|0x40000000
   gBcm27xxTokenSpaceGuid.PcdBcm27xxRegistersAddress|0xfc000000
+  gBcm27xxTokenSpaceGuid.PcdBcmGenetRegistersAddress|0xfd580000
   gBcm283xTokenSpaceGuid.PcdBcm283xRegistersAddress|0xfe000000
-  gBcmNetTokenSpaceGuid.PcdBcmGenetRegistersAddress|0xfd580000
 
   # PCIe specific addresses
   gBcm27xxTokenSpaceGuid.PcdBcm27xxPciRegBase|0xfd500000
diff --git a/Platform/RaspberryPi/AcpiTables/AcpiTables.inf b/Platform/RaspberryPi/AcpiTables/AcpiTables.inf
index e6b7d791ab47..28d2afe19733 100644
--- a/Platform/RaspberryPi/AcpiTables/AcpiTables.inf
+++ b/Platform/RaspberryPi/AcpiTables/AcpiTables.inf
@@ -54,8 +54,8 @@ [FixedPcd]
   gArmTokenSpaceGuid.PcdGicDistributorBase
   gBcm27xxTokenSpaceGuid.PcdBcm27xxPciCpuMmioAdr
   gBcm27xxTokenSpaceGuid.PcdBcm27xxPciRegBase
+  gBcm27xxTokenSpaceGuid.PcdBcmGenetRegistersAddress
   gBcm283xTokenSpaceGuid.PcdBcm283xRegistersAddress
-  gBcmNetTokenSpaceGuid.PcdBcmGenetRegistersAddress
   gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
   gEmbeddedTokenSpaceGuid.PcdInterruptBaseAddress
   gRaspberryPiTokenSpaceGuid.PcdGicInterruptInterfaceHBase
diff --git a/Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf b/Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf
index 2a207d2b3e54..c97453e4e7c1 100644
--- a/Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf
+++ b/Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf
@@ -23,6 +23,7 @@ [Packages]
   MdeModulePkg/MdeModulePkg.dec
   Platform/RaspberryPi/RaspberryPi.dec
   Silicon/Broadcom/Drivers/Net/BcmNet.dec
+  Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
 
 [LibraryClasses]
   DebugLib
@@ -34,10 +35,10 @@ [Protocols]
   gRaspberryPiFirmwareProtocolGuid              ## CONSUMES
 
 [Pcd]
-  gBcmNetTokenSpaceGuid.PcdBcmGenetMacAddress   ## SOMETIMES_PRODUCES
+  gRaspberryPiTokenSpaceGuid.PcdBcmGenetMacAddress   ## SOMETIMES_PRODUCES
 
 [FixedPcd]
-  gBcmNetTokenSpaceGuid.PcdBcmGenetRegistersAddress
+  gBcm27xxTokenSpaceGuid.PcdBcmGenetRegistersAddress
 
 [Depex]
   gRaspberryPiFirmwareProtocolGuid
diff --git a/Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2711.h b/Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2711.h
index a1609ce9b517..e9c81cafa11c 100644
--- a/Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2711.h
+++ b/Silicon/Broadcom/Bcm27xx/Include/IndustryStandard/Bcm2711.h
@@ -83,4 +83,7 @@
 #define BURST_SIZE_256                                      1
 #define BURST_SIZE_512                                      2
 
+#define GENET_BASE_ADDRESS         FixedPcdGet64 (PcdBcmGenetRegistersAddress)
+#define GENET_LENGTH               0x00010000
+
 #endif /* BCM2711_H__ */
diff --git a/Silicon/Broadcom/Drivers/Net/Include/Net/Genet.h b/Silicon/Broadcom/Drivers/Net/Include/Net/Genet.h
deleted file mode 100644
index f56fb2977422..000000000000
--- a/Silicon/Broadcom/Drivers/Net/Include/Net/Genet.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/** @file
-
-  Copyright (c) 2020, Pete Batard <pete@akeo.ie>
-
-  SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef BCM_GENET_H__
-#define BCM_GENET_H__
-
-#include <Library/PcdLib.h>
-
-#define GENET_BASE_ADDRESS         FixedPcdGet64 (PcdBcmGenetRegistersAddress)
-#define GENET_LENGTH               0x00010000
-
-#define GENET_SYS_RBUF_FLUSH_CTRL  0x0008
-#define GENET_UMAC_MAC0            0x080c
-#define GENET_UMAC_MAC1            0x0810
-
-#endif /* BCM_GENET_H__ */
diff --git a/Platform/RaspberryPi/AcpiTables/Dsdt.asl b/Platform/RaspberryPi/AcpiTables/Dsdt.asl
index 9358750f6a64..353af2d8762b 100644
--- a/Platform/RaspberryPi/AcpiTables/Dsdt.asl
+++ b/Platform/RaspberryPi/AcpiTables/Dsdt.asl
@@ -10,13 +10,13 @@
  *
  **/
 
+#include <IndustryStandard/Bcm2711.h>
 #include <IndustryStandard/Bcm2836.h>
 #include <IndustryStandard/Bcm2836Gpio.h>
 #include <IndustryStandard/Bcm2836Gpu.h>
 #include <IndustryStandard/Bcm2836Pwm.h>
 #include <IndustryStandard/Bcm2836Sdio.h>
 #include <IndustryStandard/Bcm2836SdHost.h>
-#include <Net/Genet.h>
 
 #include "AcpiTables.h"
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH edk2-platforms v2 5/7] Platform/RaspberryPi4: Register GENET platform device protocol
  2020-05-12  7:55 [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4 Ard Biesheuvel
                   ` (3 preceding siblings ...)
  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 ` 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
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 13+ messages in thread
From: Ard Biesheuvel @ 2020-05-12  7:55 UTC (permalink / raw)
  To: devel; +Cc: leif, philmd, Ard Biesheuvel

Register an event at EndOfDxe to instantiate the EFI device path protocol
with the GENET MAC address on a new handle, and install the
BcmGenetPlatformDeviceProtocol on that handle. This protocol is used to
pass platform information (GENET MAC address and register base address)
to the GENET driver, which will consume this in its implementation of the
UEFI driver model Supported/Start/Stop methods.

Co-authored-by: Samer El-Haj-Mahmoud <samer.el-haj-mahmoud@arm.com>
Co-authored-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
Co-authored-by: Andrei Warkentin <awarkentin@vmware.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
---
 Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf |  29 ++++--
 Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c   | 108 ++++++++++++++++++--
 2 files changed, 117 insertions(+), 20 deletions(-)

diff --git a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf
index e47f3af69199..f20f3bcc1243 100644
--- a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf
+++ b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf
@@ -1,6 +1,8 @@
 #/** @file
 #
-#  Copyright (c) 2019, ARM Limited. All rights reserved.
+#  Component description file for the RasbperryPi DXE platform config driver.
+#
+#  Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.
 #  Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -21,7 +23,6 @@ [Defines]
 #
 #  VALID_ARCHITECTURES           = AARCH64
 #
-
 [Sources]
   ConfigDxe.c
   ConfigDxeFormSetGuid.h
@@ -31,31 +32,36 @@ [Sources]
 [Packages]
   ArmPkg/ArmPkg.dec
   ArmPlatformPkg/ArmPlatformPkg.dec
-  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
   MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  NetworkPkg/NetworkPkg.dec
+  Platform/RaspberryPi/RaspberryPi.dec
   Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
   Silicon/Broadcom/Bcm283x/Bcm283x.dec
-  Platform/RaspberryPi/RaspberryPi.dec
-  EmbeddedPkg/EmbeddedPkg.dec
+  Silicon/Broadcom/Drivers/Net/BcmNet.dec
 
 [LibraryClasses]
+  AcpiLib
   BaseLib
   DebugLib
   DxeServicesTableLib
+  GpioLib
+  HiiLib
+  NetLib
   PcdLib
   UefiBootServicesTableLib
-  UefiRuntimeServicesTableLib
   UefiDriverEntryPoint
-  HiiLib
-  GpioLib
-  AcpiLib
+  UefiRuntimeServicesTableLib
 
 [Guids]
   gConfigDxeFormSetGuid
+  gEfiEndOfDxeEventGroupGuid
 
 [Protocols]
-  gRaspberryPiFirmwareProtocolGuid      ## CONSUMES
-  gRaspberryPiConfigAppliedProtocolGuid ## PRODUCES
+  gBcmGenetPlatformDeviceProtocolGuid             ## PRODUCES
+  gRaspberryPiFirmwareProtocolGuid                ## CONSUMES
+  gRaspberryPiConfigAppliedProtocolGuid           ## PRODUCES
 
 [FixedPcd]
   gRaspberryPiTokenSpaceGuid.PcdCpuLowSpeedMHz
@@ -64,6 +70,7 @@ [FixedPcd]
 
 [Pcd]
   gBcm27xxTokenSpaceGuid.PcdBcm27xxRegistersAddress
+  gBcm27xxTokenSpaceGuid.PcdBcmGenetRegistersAddress
   gBcm283xTokenSpaceGuid.PcdBcm283xRegistersAddress
   gRaspberryPiTokenSpaceGuid.PcdCpuClock
   gRaspberryPiTokenSpaceGuid.PcdCustomCpuClock
diff --git a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
index 00867879da20..47ca0a89a3d8 100644
--- a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
+++ b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
@@ -1,6 +1,6 @@
 /** @file
  *
- *  Copyright (c) 2019, ARM Limited. All rights reserved.
+ *  Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.
  *  Copyright (c) 2018 - 2019, Andrei Warkentin <andrey.warkentin@gmail.com>
  *
  *  SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -8,19 +8,21 @@
  **/
 
 #include <Uefi.h>
+#include <IndustryStandard/Bcm2711.h>
+#include <IndustryStandard/Bcm2836.h>
+#include <IndustryStandard/Bcm2836Gpio.h>
+#include <IndustryStandard/RpiMbox.h>
 #include <Library/AcpiLib.h>
-#include <Library/HiiLib.h>
 #include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
 #include <Library/DxeServicesTableLib.h>
+#include <Library/GpioLib.h>
+#include <Library/HiiLib.h>
 #include <Library/IoLib.h>
+#include <Library/NetLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiRuntimeServicesTableLib.h>
-#include <Library/DevicePathLib.h>
-#include <IndustryStandard/RpiMbox.h>
-#include <IndustryStandard/Bcm2711.h>
-#include <IndustryStandard/Bcm2836.h>
-#include <IndustryStandard/Bcm2836Gpio.h>
-#include <Library/GpioLib.h>
+#include <Protocol/BcmGenetPlatformDevice.h>
 #include <Protocol/RpiFirmware.h>
 #include <ConfigVars.h>
 #include "ConfigDxeFormSetGuid.h"
@@ -34,6 +36,8 @@ STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL *mFwProtocol;
 STATIC UINT32 mModelFamily = 0;
 STATIC UINT32 mModelInstalledMB = 0;
 
+STATIC EFI_MAC_ADDRESS  MacAddress;
+
 /*
  * The GUID inside Platform/RaspberryPi/RPi3/AcpiTables/AcpiTables.inf and
  * Platform/RaspberryPi/RPi4/AcpiTables/AcpiTables.inf _must_ match below.
@@ -47,6 +51,18 @@ typedef struct {
   EFI_DEVICE_PATH_PROTOCOL End;
 } HII_VENDOR_DEVICE_PATH;
 
+#pragma pack (1)
+typedef struct {
+  MAC_ADDR_DEVICE_PATH            MacAddrDP;
+  EFI_DEVICE_PATH_PROTOCOL        End;
+} GENET_DEVICE_PATH;
+
+typedef struct {
+  GENET_DEVICE_PATH                   DevicePath;
+  BCM_GENET_PLATFORM_DEVICE_PROTOCOL  PlatformDevice;
+} GENET_DEVICE;
+#pragma pack ()
+
 STATIC HII_VENDOR_DEVICE_PATH mVendorDevicePath = {
   {
     {
@@ -69,6 +85,65 @@ STATIC HII_VENDOR_DEVICE_PATH mVendorDevicePath = {
   }
 };
 
+STATIC GENET_DEVICE mGenetDevice = {
+  {
+    {
+      {
+        MESSAGING_DEVICE_PATH,
+        MSG_MAC_ADDR_DP,
+        {
+          (UINT8)(sizeof (MAC_ADDR_DEVICE_PATH)),
+          (UINT8)((sizeof (MAC_ADDR_DEVICE_PATH)) >> 8)
+        }
+      },
+      {{ 0 }},
+      NET_IFTYPE_ETHERNET
+    },
+    {
+      END_DEVICE_PATH_TYPE,
+      END_ENTIRE_DEVICE_PATH_SUBTYPE,
+      {
+        sizeof (EFI_DEVICE_PATH_PROTOCOL),
+        0
+      }
+    }
+  },
+  {
+    GENET_BASE_ADDRESS,
+    {{ 0 }}
+  }
+};
+
+
+STATIC
+VOID
+EFIAPI
+RegisterDevices (
+  EFI_EVENT           Event,
+  VOID                *Context
+  )
+{
+  EFI_HANDLE  Handle;
+  EFI_STATUS  Status;
+
+  if (mModelFamily == 4) {
+    DEBUG ((DEBUG_INFO, "GENET: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
+            MacAddress.Addr[0], MacAddress.Addr[1], MacAddress.Addr[2],
+            MacAddress.Addr[3], MacAddress.Addr[4], MacAddress.Addr[5]));
+
+    CopyMem (&mGenetDevice.DevicePath.MacAddrDP.MacAddress, MacAddress.Addr,
+      NET_ETHER_ADDR_LEN);
+    CopyMem (&mGenetDevice.PlatformDevice.MacAddress, MacAddress.Addr,
+      NET_ETHER_ADDR_LEN);
+
+    Handle = NULL;
+    Status = gBS->InstallMultipleProtocolInterfaces (&Handle,
+                    &gEfiDevicePathProtocolGuid,          &mGenetDevice.DevicePath,
+                    &gBcmGenetPlatformDeviceProtocolGuid, &mGenetDevice.PlatformDevice,
+                    NULL);
+    ASSERT_EFI_ERROR (Status);
+  }
+}
 
 STATIC EFI_STATUS
 InstallHiiPages (
@@ -242,6 +317,16 @@ SetupVariables (
     PcdSet32 (PcdDisplayEnableSShot, PcdGet32 (PcdDisplayEnableSShot));
   }
 
+  if (mModelFamily == 4) {
+    //
+    // Get the MAC address from the firmware.
+    //
+    Status = mFwProtocol->GetMacAddress (MacAddress.Addr);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_WARN, "%a: failed to retrieve MAC address\n", __FUNCTION__));
+    }
+  }
+
   return EFI_SUCCESS;
 }
 
@@ -448,7 +533,8 @@ ConfigInitialize (
   IN EFI_SYSTEM_TABLE *SystemTable
   )
 {
-  EFI_STATUS Status;
+  EFI_STATUS                      Status;
+  EFI_EVENT                       EndOfDxeEvent;
 
   Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid,
                   NULL, (VOID**)&mFwProtocol);
@@ -494,5 +580,9 @@ ConfigInitialize (
      ASSERT_EFI_ERROR (Status);
   }
 
+  Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, RegisterDevices,
+                  NULL, &gEfiEndOfDxeEventGroupGuid, &EndOfDxeEvent);
+  ASSERT_EFI_ERROR (Status);
+
   return EFI_SUCCESS;
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH edk2-platforms v2 6/7] Platform/RaspberryPi4: Remove PlatformPcdLib
  2020-05-12  7:55 [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4 Ard Biesheuvel
                   ` (4 preceding siblings ...)
  2020-05-12  7:55 ` [PATCH edk2-platforms v2 5/7] Platform/RaspberryPi4: Register GENET platform device protocol Ard Biesheuvel
@ 2020-05-12  7:55 ` Ard Biesheuvel
  2020-05-12  7:55 ` [PATCH edk2-platforms v2 7/7] Platform/RaspberryPi4: remove ASIX 88772b driver Ard Biesheuvel
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Ard Biesheuvel @ 2020-05-12  7:55 UTC (permalink / raw)
  To: devel; +Cc: leif, philmd, Andrei Warkentin, Ard Biesheuvel

From: Andrei Warkentin <awarkentin@vmware.com>

Remove the PlatformPcdLib. It is completely unnecessary. Originally,
this was meant for the GENET driver, but now that ConfigDxe registers
the platform device, the library is superfluous.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
---
 Platform/RaspberryPi/RaspberryPi.dec                           |  3 --
 Platform/RaspberryPi/RPi4/RPi4.dsc                             |  2 -
 Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf | 44 -------------------
 Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.c   | 45 --------------------
 4 files changed, 94 deletions(-)

diff --git a/Platform/RaspberryPi/RaspberryPi.dec b/Platform/RaspberryPi/RaspberryPi.dec
index 7a22621a6905..1a3c44e0eb01 100644
--- a/Platform/RaspberryPi/RaspberryPi.dec
+++ b/Platform/RaspberryPi/RaspberryPi.dec
@@ -68,6 +68,3 @@ [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
   gRaspberryPiTokenSpaceGuid.PcdSystemTableMode|1|UINT32|0x0000001B
   gRaspberryPiTokenSpaceGuid.PcdRamMoreThan3GB|0|UINT32|0x00000019
   gRaspberryPiTokenSpaceGuid.PcdRamLimitTo3GB|0|UINT32|0x0000001A
-
-[PcdsDynamic]
-  gRaspberryPiTokenSpaceGuid.PcdBcmGenetMacAddress|0x0|UINT64|0x00000040
diff --git a/Platform/RaspberryPi/RPi4/RPi4.dsc b/Platform/RaspberryPi/RPi4/RPi4.dsc
index 0dca782c9058..5910082deb04 100644
--- a/Platform/RaspberryPi/RPi4/RPi4.dsc
+++ b/Platform/RaspberryPi/RPi4/RPi4.dsc
@@ -683,8 +683,6 @@ [Components.common]
   #
 !include NetworkPkg/Network.dsc.inc
   Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf {
-    <LibraryClasses>
-      NULL|Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf
     <PcdsFixedAtBuild>
       gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset|0x00000000
       gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit|0xffffffff
diff --git a/Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf b/Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf
deleted file mode 100644
index c97453e4e7c1..000000000000
--- a/Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf
+++ /dev/null
@@ -1,44 +0,0 @@
-#/** @file
-#
-#  Copyright (c) 2020, Pete Batard <pete@akeo.ie>
-#
-#  SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#**/
-
-[Defines]
-  INF_VERSION                    = 0x0001001A
-  BASE_NAME                      = PlatformPcdLib
-  FILE_GUID                      = 3B8409D7-D3C7-4006-823B-BFB184435363
-  MODULE_TYPE                    = DXE_DRIVER
-  VERSION_STRING                 = 1.0
-  LIBRARY_CLASS                  = NULL|DXE_DRIVER UEFI_APPLICATION
-  CONSTRUCTOR                    = PlatformPcdLibConstructor
-
-[Sources]
-  PlatformPcdLib.c
-
-[Packages]
-  MdePkg/MdePkg.dec
-  MdeModulePkg/MdeModulePkg.dec
-  Platform/RaspberryPi/RaspberryPi.dec
-  Silicon/Broadcom/Drivers/Net/BcmNet.dec
-  Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
-
-[LibraryClasses]
-  DebugLib
-  PcdLib
-  UefiLib
-  PrintLib
-
-[Protocols]
-  gRaspberryPiFirmwareProtocolGuid              ## CONSUMES
-
-[Pcd]
-  gRaspberryPiTokenSpaceGuid.PcdBcmGenetMacAddress   ## SOMETIMES_PRODUCES
-
-[FixedPcd]
-  gBcm27xxTokenSpaceGuid.PcdBcmGenetRegistersAddress
-
-[Depex]
-  gRaspberryPiFirmwareProtocolGuid
diff --git a/Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.c b/Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.c
deleted file mode 100644
index e78518c81374..000000000000
--- a/Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/** @file
- *
- *  Copyright (c) 2020, Pete Batard <pete@akeo.ie>
- *
- *  SPDX-License-Identifier: BSD-2-Clause-Patent
- *
- **/
-
-#include <Library/DebugLib.h>
-#include <Library/PcdLib.h>
-#include <Library/PrintLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiLib.h>
-#include <Library/UefiRuntimeServicesTableLib.h>
-#include <Protocol/RpiFirmware.h>
-
-EFI_STATUS
-EFIAPI
-PlatformPcdLibConstructor (
-  IN EFI_HANDLE ImageHandle,
-  IN EFI_SYSTEM_TABLE *SystemTable
-  )
-{
-  EFI_STATUS                       Status;
-  UINT64                           MacAddr;
-  RASPBERRY_PI_FIRMWARE_PROTOCOL   *mFwProtocol;
-
-  if (PcdGet64 (PcdBcmGenetMacAddress) == 0) {
-    Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid, NULL,
-                    (VOID**)&mFwProtocol);
-    ASSERT_EFI_ERROR(Status);
-
-    //
-    // Get the MAC address from the firmware
-    //
-    Status = mFwProtocol->GetMacAddress ((UINT8*) &MacAddr);
-    if (EFI_ERROR (Status)) {
-      DEBUG ((DEBUG_WARN, "%a: failed to retrieve MAC address\n", __FUNCTION__));
-    } else {
-      PcdSet64S (PcdBcmGenetMacAddress, MacAddr);
-    }
-  }
-
-  return EFI_SUCCESS;
-}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH edk2-platforms v2 7/7] Platform/RaspberryPi4: remove ASIX 88772b driver
  2020-05-12  7:55 [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4 Ard Biesheuvel
                   ` (5 preceding siblings ...)
  2020-05-12  7:55 ` [PATCH edk2-platforms v2 6/7] Platform/RaspberryPi4: Remove PlatformPcdLib Ard Biesheuvel
@ 2020-05-12  7:55 ` Ard Biesheuvel
  2020-05-12  8:26 ` [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4 Ard Biesheuvel
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Ard Biesheuvel @ 2020-05-12  7:55 UTC (permalink / raw)
  To: devel; +Cc: leif, philmd, Ard Biesheuvel

The Raspberry Pi4 has gigabit ethernet builtin, for which we now
have a UEFI driver. So no need for the ASIX 88772b driver.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
Reviewed-by: Andrei Warkentin <andrey.warkentin@gmail.com>
Reviewed-by: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud@arm.com>
---
 Platform/RaspberryPi/RPi4/RPi4.dsc | 1 -
 Platform/RaspberryPi/RPi4/RPi4.fdf | 1 -
 2 files changed, 2 deletions(-)

diff --git a/Platform/RaspberryPi/RPi4/RPi4.dsc b/Platform/RaspberryPi/RPi4/RPi4.dsc
index 5910082deb04..cbff9d9946e2 100644
--- a/Platform/RaspberryPi/RPi4/RPi4.dsc
+++ b/Platform/RaspberryPi/RPi4/RPi4.dsc
@@ -669,7 +669,6 @@ [Components.common]
   MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
   MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
   MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
-  Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf
 
   #
   # SD/MMC support
diff --git a/Platform/RaspberryPi/RPi4/RPi4.fdf b/Platform/RaspberryPi/RPi4/RPi4.fdf
index b1f7aa2387df..1e13909a57ba 100644
--- a/Platform/RaspberryPi/RPi4/RPi4.fdf
+++ b/Platform/RaspberryPi/RPi4/RPi4.fdf
@@ -293,7 +293,6 @@ [FV.FvMain]
   INF MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
   INF MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
   INF MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
-  INF Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf
 
   #
   # SD/MMC support
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4
  2020-05-12  7:55 [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4 Ard Biesheuvel
                   ` (6 preceding siblings ...)
  2020-05-12  7:55 ` [PATCH edk2-platforms v2 7/7] Platform/RaspberryPi4: remove ASIX 88772b driver Ard Biesheuvel
@ 2020-05-12  8:26 ` Ard Biesheuvel
  2020-05-12 14:28 ` Ard Biesheuvel
  2020-05-12 14:35 ` Leif Lindholm
  9 siblings, 0 replies; 13+ messages in thread
From: Ard Biesheuvel @ 2020-05-12  8:26 UTC (permalink / raw)
  To: devel
  Cc: leif, philmd, Pete Batard, Jared McNeill, Andrei Warkentin,
	Samer El-Haj-Mahmoud, Jeremy Linton

On 5/12/20 9:55 AM, Ard Biesheuvel wrote:
> This is a followup to Samer's v1 [0], and incorporates all the delta
> changes posted for review over the past couple of days. This is a
> roundup of all that work, and therefore supersedes it.
> 
> It provides an implementation of the SimpleNetworkProtocol for the
> Raspberry Pi4's GENET network controller, in a way that adheres to the
> UEFI driver model.
> 
> The original submission was provided by Jared, based on Jeremy's MAC
> programming-only driver and the existing BSD driver for the GENET IP.
> Cumulative changes and fixes as well as review feedback were provided
> by all of the below.
> 
> https://github.com/ardbiesheuvel/edk2-platforms/tree/rpi4_genet_combi_v2
> 
> Cc: Pete Batard <pete@akeo.ie>
> Cc: Jared McNeill <jmcneill@invisible.ca>
> Cc: Andrei Warkentin <awarkentin@vmware.com>
> Cc: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud@arm.com>
> Cc: Jeremy Linton <jeremy.linton@arm.com>
> 

[0] https://edk2.groups.io/g/devel/message/58903

> Andrei Warkentin (1):
>    Platform/RaspberryPi4: Remove PlatformPcdLib
> 
> Ard Biesheuvel (6):
>    Platform/RaspberryPi4: set DMA translation for BCM Genet driver
>    Silicon/Broadcom: Add BcmGenetPlatformDevice protocol
>    Silicon/Broadcom/BcmGenetDxe: Add GENET driver
>    Platform/RaspberryPi4: Clean up PCDs out of the GENET driver
>    Platform/RaspberryPi4: Register GENET platform device protocol
>    Platform/RaspberryPi4: remove ASIX 88772b driver
> 
>   Silicon/Broadcom/Bcm27xx/Bcm27xx.dec          |   2 +
>   Silicon/Broadcom/Drivers/Net/BcmNet.dec       |   8 +-
>   Platform/RaspberryPi/RPi4/RPi4.dsc            |   8 +-
>   Platform/RaspberryPi/RPi4/RPi4.fdf            |   1 -
>   .../RaspberryPi/AcpiTables/AcpiTables.inf     |   2 +-
>   .../Drivers/ConfigDxe/ConfigDxe.inf           |  29 +-
>   .../Library/PlatformPcdLib/PlatformPcdLib.inf |  43 -
>   .../Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf   |  46 +-
>   .../Include/IndustryStandard/Bcm2711.h        |   3 +
>   .../Drivers/Net/BcmGenetDxe/GenericPhy.h      | 106 +++
>   .../Drivers/Net/BcmGenetDxe/GenetUtil.h       | 364 ++++++++
>   .../Broadcom/Drivers/Net/Include/Net/Genet.h  |  21 -
>   .../Include/Protocol/BcmGenetPlatformDevice.h |  24 +
>   .../RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c | 108 ++-
>   .../Library/PlatformPcdLib/PlatformPcdLib.c   |  45 -
>   .../Drivers/Net/BcmGenetDxe/ComponentName.c   | 198 +++++
>   .../Drivers/Net/BcmGenetDxe/DriverBinding.c   | 408 +++++++++
>   .../Drivers/Net/BcmGenetDxe/GenericPhy.c      | 405 +++++++++
>   .../Broadcom/Drivers/Net/BcmGenetDxe/Genet.c  | 114 ---
>   .../Drivers/Net/BcmGenetDxe/GenetUtil.c       | 816 +++++++++++++++++
>   .../Drivers/Net/BcmGenetDxe/SimpleNetwork.c   | 834 ++++++++++++++++++
>   Platform/RaspberryPi/AcpiTables/Dsdt.asl      |   2 +-
>   22 files changed, 3319 insertions(+), 268 deletions(-)
>   delete mode 100644 Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf
>   create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.h
>   create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.h
>   delete mode 100644 Silicon/Broadcom/Drivers/Net/Include/Net/Genet.h
>   create mode 100644 Silicon/Broadcom/Drivers/Net/Include/Protocol/BcmGenetPlatformDevice.h
>   delete mode 100644 Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.c
>   create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/ComponentName.c
>   create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c
>   create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.c
>   delete mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/Genet.c
>   create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c
>   create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/SimpleNetwork.c
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4
  2020-05-12  7:55 [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4 Ard Biesheuvel
                   ` (7 preceding siblings ...)
  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
  9 siblings, 0 replies; 13+ messages in thread
From: Ard Biesheuvel @ 2020-05-12 14:28 UTC (permalink / raw)
  To: devel
  Cc: leif, philmd, Pete Batard, Jared McNeill, Andrei Warkentin,
	Samer El-Haj-Mahmoud, Jeremy Linton

On 5/12/20 9:55 AM, Ard Biesheuvel wrote:
> This is a followup to Samer's v1 [0], and incorporates all the delta
> changes posted for review over the past couple of days. This is a
> roundup of all that work, and therefore supersedes it.
> 
> It provides an implementation of the SimpleNetworkProtocol for the
> Raspberry Pi4's GENET network controller, in a way that adheres to the
> UEFI driver model.
> 
> The original submission was provided by Jared, based on Jeremy's MAC
> programming-only driver and the existing BSD driver for the GENET IP.
> Cumulative changes and fixes as well as review feedback were provided
> by all of the below.
> 
> https://github.com/ardbiesheuvel/edk2-platforms/tree/rpi4_genet_combi_v2
> 

FYI in an off list discussion, Leif pointed out the the practice of 
having one 'master' .h file including everything, which is included by 
the .c files is not acceptable practice, even though it is widespread in 
EDK2.

I pushed a delta patch to the branch above that fixes this, but I will 
wait for other feedback before sending it out, or sending out a v3, 
whichever is more appropriate.



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [edk2-devel] [PATCH edk2-platforms v2 3/7] Silicon/Broadcom/BcmGenetDxe: Add GENET driver
  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
  0 siblings, 0 replies; 13+ messages in thread
From: Leif Lindholm @ 2020-05-12 14:31 UTC (permalink / raw)
  To: devel, ard.biesheuvel; +Cc: philmd

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
> 
> 
> 
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH edk2-platforms v2 5/7] Platform/RaspberryPi4: Register GENET platform device protocol
  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
  0 siblings, 0 replies; 13+ messages in thread
From: Leif Lindholm @ 2020-05-12 14:34 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: devel, philmd

On Tue, May 12, 2020 at 09:55:10 +0200, Ard Biesheuvel wrote:
> Register an event at EndOfDxe to instantiate the EFI device path protocol
> with the GENET MAC address on a new handle, and install the
> BcmGenetPlatformDeviceProtocol on that handle. This protocol is used to
> pass platform information (GENET MAC address and register base address)
> to the GENET driver, which will consume this in its implementation of the
> UEFI driver model Supported/Start/Stop methods.
> 
> Co-authored-by: Samer El-Haj-Mahmoud <samer.el-haj-mahmoud@arm.com>
> Co-authored-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
> Co-authored-by: Andrei Warkentin <awarkentin@vmware.com>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
> ---
>  Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf |  29 ++++--
>  Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c   | 108 ++++++++++++++++++--
>  2 files changed, 117 insertions(+), 20 deletions(-)
> 
> diff --git a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf
> index e47f3af69199..f20f3bcc1243 100644
> --- a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf
> +++ b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf
> @@ -1,6 +1,8 @@
>  #/** @file
>  #
> -#  Copyright (c) 2019, ARM Limited. All rights reserved.
> +#  Component description file for the RasbperryPi DXE platform config driver.
> +#
> +#  Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.
>  #  Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
>  #
>  #  SPDX-License-Identifier: BSD-2-Clause-Patent
> @@ -21,7 +23,6 @@ [Defines]
>  #
>  #  VALID_ARCHITECTURES           = AARCH64
>  #
> -
>  [Sources]
>    ConfigDxe.c
>    ConfigDxeFormSetGuid.h
> @@ -31,31 +32,36 @@ [Sources]
>  [Packages]
>    ArmPkg/ArmPkg.dec
>    ArmPlatformPkg/ArmPlatformPkg.dec
> -  MdePkg/MdePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
>    MdeModulePkg/MdeModulePkg.dec
> +  MdePkg/MdePkg.dec
> +  NetworkPkg/NetworkPkg.dec
> +  Platform/RaspberryPi/RaspberryPi.dec
>    Silicon/Broadcom/Bcm27xx/Bcm27xx.dec
>    Silicon/Broadcom/Bcm283x/Bcm283x.dec
> -  Platform/RaspberryPi/RaspberryPi.dec
> -  EmbeddedPkg/EmbeddedPkg.dec
> +  Silicon/Broadcom/Drivers/Net/BcmNet.dec
>  
>  [LibraryClasses]
> +  AcpiLib
>    BaseLib
>    DebugLib
>    DxeServicesTableLib
> +  GpioLib
> +  HiiLib
> +  NetLib
>    PcdLib
>    UefiBootServicesTableLib
> -  UefiRuntimeServicesTableLib
>    UefiDriverEntryPoint
> -  HiiLib
> -  GpioLib
> -  AcpiLib
> +  UefiRuntimeServicesTableLib

The cleanup is good, but could we separate functional and
non-functional changes into separate patches?

>  
>  [Guids]
>    gConfigDxeFormSetGuid
> +  gEfiEndOfDxeEventGroupGuid
>  
>  [Protocols]
> -  gRaspberryPiFirmwareProtocolGuid      ## CONSUMES
> -  gRaspberryPiConfigAppliedProtocolGuid ## PRODUCES
> +  gBcmGenetPlatformDeviceProtocolGuid             ## PRODUCES
> +  gRaspberryPiFirmwareProtocolGuid                ## CONSUMES
> +  gRaspberryPiConfigAppliedProtocolGuid           ## PRODUCES
>  
>  [FixedPcd]
>    gRaspberryPiTokenSpaceGuid.PcdCpuLowSpeedMHz
> @@ -64,6 +70,7 @@ [FixedPcd]
>  
>  [Pcd]
>    gBcm27xxTokenSpaceGuid.PcdBcm27xxRegistersAddress
> +  gBcm27xxTokenSpaceGuid.PcdBcmGenetRegistersAddress
>    gBcm283xTokenSpaceGuid.PcdBcm283xRegistersAddress
>    gRaspberryPiTokenSpaceGuid.PcdCpuClock
>    gRaspberryPiTokenSpaceGuid.PcdCustomCpuClock
> diff --git a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
> index 00867879da20..47ca0a89a3d8 100644
> --- a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
> +++ b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
> @@ -1,6 +1,6 @@
>  /** @file
>   *
> - *  Copyright (c) 2019, ARM Limited. All rights reserved.
> + *  Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.
>   *  Copyright (c) 2018 - 2019, Andrei Warkentin <andrey.warkentin@gmail.com>
>   *
>   *  SPDX-License-Identifier: BSD-2-Clause-Patent
> @@ -8,19 +8,21 @@
>   **/
>  
>  #include <Uefi.h>
> +#include <IndustryStandard/Bcm2711.h>
> +#include <IndustryStandard/Bcm2836.h>
> +#include <IndustryStandard/Bcm2836Gpio.h>
> +#include <IndustryStandard/RpiMbox.h>
>  #include <Library/AcpiLib.h>
> -#include <Library/HiiLib.h>
>  #include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
>  #include <Library/DxeServicesTableLib.h>
> +#include <Library/GpioLib.h>
> +#include <Library/HiiLib.h>
>  #include <Library/IoLib.h>
> +#include <Library/NetLib.h>
>  #include <Library/UefiBootServicesTableLib.h>
>  #include <Library/UefiRuntimeServicesTableLib.h>
> -#include <Library/DevicePathLib.h>
> -#include <IndustryStandard/RpiMbox.h>
> -#include <IndustryStandard/Bcm2711.h>
> -#include <IndustryStandard/Bcm2836.h>
> -#include <IndustryStandard/Bcm2836Gpio.h>
> -#include <Library/GpioLib.h>
> +#include <Protocol/BcmGenetPlatformDevice.h>
>  #include <Protocol/RpiFirmware.h>
>  #include <ConfigVars.h>
>  #include "ConfigDxeFormSetGuid.h"
> @@ -34,6 +36,8 @@ STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL *mFwProtocol;
>  STATIC UINT32 mModelFamily = 0;
>  STATIC UINT32 mModelInstalledMB = 0;
>  
> +STATIC EFI_MAC_ADDRESS  MacAddress;

m-prefix on global variable?

/
    Leif

> +
>  /*
>   * The GUID inside Platform/RaspberryPi/RPi3/AcpiTables/AcpiTables.inf and
>   * Platform/RaspberryPi/RPi4/AcpiTables/AcpiTables.inf _must_ match below.
> @@ -47,6 +51,18 @@ typedef struct {
>    EFI_DEVICE_PATH_PROTOCOL End;
>  } HII_VENDOR_DEVICE_PATH;
>  
> +#pragma pack (1)
> +typedef struct {
> +  MAC_ADDR_DEVICE_PATH            MacAddrDP;
> +  EFI_DEVICE_PATH_PROTOCOL        End;
> +} GENET_DEVICE_PATH;
> +
> +typedef struct {
> +  GENET_DEVICE_PATH                   DevicePath;
> +  BCM_GENET_PLATFORM_DEVICE_PROTOCOL  PlatformDevice;
> +} GENET_DEVICE;
> +#pragma pack ()
> +
>  STATIC HII_VENDOR_DEVICE_PATH mVendorDevicePath = {
>    {
>      {
> @@ -69,6 +85,65 @@ STATIC HII_VENDOR_DEVICE_PATH mVendorDevicePath = {
>    }
>  };
>  
> +STATIC GENET_DEVICE mGenetDevice = {
> +  {
> +    {
> +      {
> +        MESSAGING_DEVICE_PATH,
> +        MSG_MAC_ADDR_DP,
> +        {
> +          (UINT8)(sizeof (MAC_ADDR_DEVICE_PATH)),
> +          (UINT8)((sizeof (MAC_ADDR_DEVICE_PATH)) >> 8)
> +        }
> +      },
> +      {{ 0 }},
> +      NET_IFTYPE_ETHERNET
> +    },
> +    {
> +      END_DEVICE_PATH_TYPE,
> +      END_ENTIRE_DEVICE_PATH_SUBTYPE,
> +      {
> +        sizeof (EFI_DEVICE_PATH_PROTOCOL),
> +        0
> +      }
> +    }
> +  },
> +  {
> +    GENET_BASE_ADDRESS,
> +    {{ 0 }}
> +  }
> +};
> +
> +
> +STATIC
> +VOID
> +EFIAPI
> +RegisterDevices (
> +  EFI_EVENT           Event,
> +  VOID                *Context
> +  )
> +{
> +  EFI_HANDLE  Handle;
> +  EFI_STATUS  Status;
> +
> +  if (mModelFamily == 4) {
> +    DEBUG ((DEBUG_INFO, "GENET: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
> +            MacAddress.Addr[0], MacAddress.Addr[1], MacAddress.Addr[2],
> +            MacAddress.Addr[3], MacAddress.Addr[4], MacAddress.Addr[5]));
> +
> +    CopyMem (&mGenetDevice.DevicePath.MacAddrDP.MacAddress, MacAddress.Addr,
> +      NET_ETHER_ADDR_LEN);
> +    CopyMem (&mGenetDevice.PlatformDevice.MacAddress, MacAddress.Addr,
> +      NET_ETHER_ADDR_LEN);
> +
> +    Handle = NULL;
> +    Status = gBS->InstallMultipleProtocolInterfaces (&Handle,
> +                    &gEfiDevicePathProtocolGuid,          &mGenetDevice.DevicePath,
> +                    &gBcmGenetPlatformDeviceProtocolGuid, &mGenetDevice.PlatformDevice,
> +                    NULL);
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +}
>  
>  STATIC EFI_STATUS
>  InstallHiiPages (
> @@ -242,6 +317,16 @@ SetupVariables (
>      PcdSet32 (PcdDisplayEnableSShot, PcdGet32 (PcdDisplayEnableSShot));
>    }
>  
> +  if (mModelFamily == 4) {
> +    //
> +    // Get the MAC address from the firmware.
> +    //
> +    Status = mFwProtocol->GetMacAddress (MacAddress.Addr);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_WARN, "%a: failed to retrieve MAC address\n", __FUNCTION__));
> +    }
> +  }
> +
>    return EFI_SUCCESS;
>  }
>  
> @@ -448,7 +533,8 @@ ConfigInitialize (
>    IN EFI_SYSTEM_TABLE *SystemTable
>    )
>  {
> -  EFI_STATUS Status;
> +  EFI_STATUS                      Status;
> +  EFI_EVENT                       EndOfDxeEvent;
>  
>    Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid,
>                    NULL, (VOID**)&mFwProtocol);
> @@ -494,5 +580,9 @@ ConfigInitialize (
>       ASSERT_EFI_ERROR (Status);
>    }
>  
> +  Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, RegisterDevices,
> +                  NULL, &gEfiEndOfDxeEventGroupGuid, &EndOfDxeEvent);
> +  ASSERT_EFI_ERROR (Status);
> +
>    return EFI_SUCCESS;
>  }
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4
  2020-05-12  7:55 [PATCH edk2-platforms v2 0/7] Add Broadcom GENET driver for RPi4 Ard Biesheuvel
                   ` (8 preceding siblings ...)
  2020-05-12 14:28 ` Ard Biesheuvel
@ 2020-05-12 14:35 ` Leif Lindholm
  9 siblings, 0 replies; 13+ messages in thread
From: Leif Lindholm @ 2020-05-12 14:35 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: devel, philmd, Pete Batard, Jared McNeill, Andrei Warkentin,
	Samer El-Haj-Mahmoud, Jeremy Linton

On Tue, May 12, 2020 at 09:55:05 +0200, Ard Biesheuvel wrote:
> This is a followup to Samer's v1 [0], and incorporates all the delta
> changes posted for review over the past couple of days. This is a
> roundup of all that work, and therefore supersedes it.
> 
> It provides an implementation of the SimpleNetworkProtocol for the
> Raspberry Pi4's GENET network controller, in a way that adheres to the
> UEFI driver model.
> 
> The original submission was provided by Jared, based on Jeremy's MAC
> programming-only driver and the existing BSD driver for the GENET IP.
> Cumulative changes and fixes as well as review feedback were provided
> by all of the below.
> 
> https://github.com/ardbiesheuvel/edk2-platforms/tree/rpi4_genet_combi_v2
> 
> Cc: Pete Batard <pete@akeo.ie>
> Cc: Jared McNeill <jmcneill@invisible.ca>
> Cc: Andrei Warkentin <awarkentin@vmware.com>
> Cc: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud@arm.com>
> Cc: Jeremy Linton <jeremy.linton@arm.com>

For 1-2,4,6-7/7:
Reviewed-by: Leif Lindholm <leif@nuviainc.com>

> Andrei Warkentin (1):
>   Platform/RaspberryPi4: Remove PlatformPcdLib
> 
> Ard Biesheuvel (6):
>   Platform/RaspberryPi4: set DMA translation for BCM Genet driver
>   Silicon/Broadcom: Add BcmGenetPlatformDevice protocol
>   Silicon/Broadcom/BcmGenetDxe: Add GENET driver
>   Platform/RaspberryPi4: Clean up PCDs out of the GENET driver
>   Platform/RaspberryPi4: Register GENET platform device protocol
>   Platform/RaspberryPi4: remove ASIX 88772b driver
> 
>  Silicon/Broadcom/Bcm27xx/Bcm27xx.dec          |   2 +
>  Silicon/Broadcom/Drivers/Net/BcmNet.dec       |   8 +-
>  Platform/RaspberryPi/RPi4/RPi4.dsc            |   8 +-
>  Platform/RaspberryPi/RPi4/RPi4.fdf            |   1 -
>  .../RaspberryPi/AcpiTables/AcpiTables.inf     |   2 +-
>  .../Drivers/ConfigDxe/ConfigDxe.inf           |  29 +-
>  .../Library/PlatformPcdLib/PlatformPcdLib.inf |  43 -
>  .../Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf   |  46 +-
>  .../Include/IndustryStandard/Bcm2711.h        |   3 +
>  .../Drivers/Net/BcmGenetDxe/GenericPhy.h      | 106 +++
>  .../Drivers/Net/BcmGenetDxe/GenetUtil.h       | 364 ++++++++
>  .../Broadcom/Drivers/Net/Include/Net/Genet.h  |  21 -
>  .../Include/Protocol/BcmGenetPlatformDevice.h |  24 +
>  .../RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c | 108 ++-
>  .../Library/PlatformPcdLib/PlatformPcdLib.c   |  45 -
>  .../Drivers/Net/BcmGenetDxe/ComponentName.c   | 198 +++++
>  .../Drivers/Net/BcmGenetDxe/DriverBinding.c   | 408 +++++++++
>  .../Drivers/Net/BcmGenetDxe/GenericPhy.c      | 405 +++++++++
>  .../Broadcom/Drivers/Net/BcmGenetDxe/Genet.c  | 114 ---
>  .../Drivers/Net/BcmGenetDxe/GenetUtil.c       | 816 +++++++++++++++++
>  .../Drivers/Net/BcmGenetDxe/SimpleNetwork.c   | 834 ++++++++++++++++++
>  Platform/RaspberryPi/AcpiTables/Dsdt.asl      |   2 +-
>  22 files changed, 3319 insertions(+), 268 deletions(-)
>  delete mode 100644 Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.inf
>  create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.h
>  create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.h
>  delete mode 100644 Silicon/Broadcom/Drivers/Net/Include/Net/Genet.h
>  create mode 100644 Silicon/Broadcom/Drivers/Net/Include/Protocol/BcmGenetPlatformDevice.h
>  delete mode 100644 Platform/RaspberryPi/Library/PlatformPcdLib/PlatformPcdLib.c
>  create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/ComponentName.c
>  create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/DriverBinding.c
>  create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenericPhy.c
>  delete mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/Genet.c
>  create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c
>  create mode 100644 Silicon/Broadcom/Drivers/Net/BcmGenetDxe/SimpleNetwork.c
> 
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2020-05-12 14:35 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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   ` [edk2-devel] " Leif Lindholm
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox