From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f42.google.com (mail-wr1-f42.google.com [209.85.221.42]) by mx.groups.io with SMTP id smtpd.web11.6945.1589293926160829616 for ; Tue, 12 May 2020 07:32:06 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@nuviainc-com.20150623.gappssmtp.com header.s=20150623 header.b=L+kxLjkT; spf=pass (domain: nuviainc.com, ip: 209.85.221.42, mailfrom: leif@nuviainc.com) Received: by mail-wr1-f42.google.com with SMTP id w7so15696184wre.13 for ; Tue, 12 May 2020 07:32:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nuviainc-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=o1Qh27qeyqI+0bhhwxjotV9KwS5u2yufagRn4On3KIo=; b=L+kxLjkTI3UJPXYpPwG6NapyNvNSjrH+L273pwYIKp4WGyjdSQLvv5qOj4SJx1uI+L O4zHoYfLFPl6Vd6q3AkODgTN0hFOYUikt/2FUsBBmBwhFkB6VD6933k+zffEaL41G7xp 12HunyEhqs45okMgz8A4/gp1EcqlwKOTpgRtkCyclwGU6YJFH6BF/NXcpjp9jdGyYWCZ DFQtbKg/wA9PeH9zhSCMN3QTVBhq3faJPqn+hF8H2RrxFvzDNeHnhA0D36UKEBfZuXCX IlIJ7+KAzFcSoax4WvgnePmtSRigQQfuJYvoTcb1g86I9it3ZILFLwvWy+FixnsC6mhL uypw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=o1Qh27qeyqI+0bhhwxjotV9KwS5u2yufagRn4On3KIo=; b=cSEUEw/apu/ilxnGxiZcjkHKD5mqNTgrYWsec7AMhJoK/cTa/ih0HxbASYX2MM0wgo Semvjn0c6YF1ZlrkfyNcgvjkQePWdBDNBOU7sbSpdJwkHvZzXyEekcetetOkJPEmJtt3 m5FqeIi5DsKnlKiAa5qiFX7ezC12snc5kVF5eekSWKp9aRbeaxNJr9Gt7giQ2JD6CROP bkLMVmcFkZSVup+ytwZ+MVGekhHhBlVsj0O89pCNMlBXqpu9XV+/sq4bFvqVBlM6bKYx agnInqTX8ubwJTnUT596VgK/ZSAmb8Qc4t8OQCxWi+UEUYS2BsMCw0KbeXgu7tw6mpA7 a3zw== X-Gm-Message-State: AGi0Puaw/I5HzeVzzCwJfBPwlwFu3KizyvnIEyXjIVZ3Q4Br4x0QNR/o HLiILFWGKwg2rctgDfIEIlvF0T52KWLmElFLFb6IYRTTXTpW1nTs1PMsHdHM57wUrglz4CVHpqz Ed9FEmgeI7naPDgAOgmF58VHm+hBQlkWkhKzTHjSOU8n6+wq+lWJTbV1dG98/R1Ae8A== X-Google-Smtp-Source: APiQypKtDnjKRd8YDbDm5/uB1dN6e0087vc0jdGHLAOoP/AWTAMLTuvi6dCQUghXoEjf/kmQcEEhsg== X-Received: by 2002:a5d:4006:: with SMTP id n6mr25903922wrp.27.1589293922261; Tue, 12 May 2020 07:32:02 -0700 (PDT) Return-Path: Received: from vanye ([2001:470:1f09:12f0:b26e:bfff:fea9:f1b8]) by smtp.gmail.com with ESMTPSA id 32sm9871566wrr.38.2020.05.12.07.32.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 May 2020 07:32:01 -0700 (PDT) Date: Tue, 12 May 2020 15:31:59 +0100 From: "Leif Lindholm" To: devel@edk2.groups.io, ard.biesheuvel@arm.com Cc: philmd@redhat.com Subject: Re: [edk2-devel] [PATCH edk2-platforms v2 3/7] Silicon/Broadcom/BcmGenetDxe: Add GENET driver Message-ID: <20200512143159.GG21486@vanye> References: <20200512075512.12645-1-ard.biesheuvel@arm.com> <20200512075512.12645-4-ard.biesheuvel@arm.com> MIME-Version: 1.0 In-Reply-To: <20200512075512.12645-4-ard.biesheuvel@arm.com> User-Agent: Mutt/1.10.1 (2018-07-13) Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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 > Co-authored-by: Andrei Warkentin > Co-authored-by: Samer El-Haj-Mahmoud > Co-authored-by: Ard Biesheuvel > Signed-off-by: Ard Biesheuvel > --- > Silicon/Broadcom/Drivers/Net/BcmGenetDxe/BcmGenetDxe.inf | 46 +- > Silicon/Broadcom/Drivers/Net/BcmGenetDxe/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.
> # Copyright (c) 2020, Jeremy Linton All rights reserved.
> +# Copyright (c) 2020, ARM Limited. All rights reserved.
> # > # SPDX-License-Identifier: BSD-2-Clause-Patent > # > ## > > [Defines] > - INF_VERSION = 0x0001001A > + INF_VERSION = 1.27 > BASE_NAME = BcmGenetDxe > FILE_GUID = e2b1eaf3-50b7-4ae1-b79e-ec8020cb57ac > - MODULE_TYPE = DXE_DRIVER > - VERSION_STRING = 0.1 > + MODULE_TYPE = UEFI_DRIVER > + VERSION_STRING = 1.0 > ENTRY_POINT = GenetEntryPoint > + UNLOAD_IMAGE = GenetUnload > > [Sources] > - Genet.c > + 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 > + > + 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 > + Copyright (c) 2020, ARM Limited. All rights reserved. > + Copyright (c) 2020 Andrey Warkentin > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef GENET_UTIL_H__ > +#define GENET_UTIL_H__ > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include 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 > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#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 > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > + > +#include > +#include > + > +#include "GenericPhy.h" > + > +#define PHY_RESET_TIMEOUT 500 > + > +/** > + Perform a PHY register read. > + > + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA. > + @param PhyAddr[in] PHY address. > + @param Reg[in] PHY register. > + @param Data[out] Pointer to register data read. > + > + @retval EFI_SUCCESS Data read successfully. > + @retval EFI_DEVICE_ERROR Failed to read data. > + > +**/ > +STATIC > +EFI_STATUS > +GenericPhyRead ( > + IN GENERIC_PHY_PRIVATE_DATA *Phy, > + IN UINT8 PhyAddr, > + IN UINT8 Reg, > + OUT UINT16 *Data > + ) > +{ > + return Phy->Read (Phy->PrivateData, PhyAddr, Reg, Data); > +} > + > +/** > + Perform a PHY register write. > + > + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA. > + @param PhyAddr[in] PHY address. > + @param Reg[in] PHY register. > + @param Data[in] Pointer to register data to write. > + > + @retval EFI_SUCCESS Data written successfully. > + @retval EFI_DEVICE_ERROR Failed to write data. > + > +**/ > +STATIC > +EFI_STATUS > +GenericPhyWrite ( > + IN GENERIC_PHY_PRIVATE_DATA *Phy, > + IN UINT8 PhyAddr, > + IN UINT8 Reg, > + IN UINT16 Data > + ) > +{ > + return Phy->Write (Phy->PrivateData, PhyAddr, Reg, Data); > +} > + > +/** > + Process a PHY link speed change (e.g. with MAC layer). > + > + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA. > + @param Speed[in] Speed setting. > + @param Duplex[in] Duplex setting. > + > +**/ > +STATIC > +VOID > +GenericPhyConfigure ( > + IN GENERIC_PHY_PRIVATE_DATA *Phy, > + IN GENERIC_PHY_SPEED Speed, > + IN GENERIC_PHY_DUPLEX Duplex > + ) > +{ > + Phy->Configure (Phy->PrivateData, Speed, Duplex); > +} > + > +/** > + Detect address for the first PHY seen, probing all possible addresses. > + > + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA. > + > + @retval EFI_SUCCESS Found a PHY and programmed Phy->PhyAddr > + @retval EFI_DEVICE_ERROR Error reading/writing a PHY register. > + @retval EFI_NOT_FOUND No PHY detected. > + > +**/ > +STATIC > +EFI_STATUS > +GenericPhyDetect ( > + IN GENERIC_PHY_PRIVATE_DATA *Phy > + ) > +{ > + EFI_STATUS Status; > + UINT8 PhyAddr; > + UINT16 Id1, Id2; > + > + for (PhyAddr = 0; PhyAddr < 32; PhyAddr++) { > + Status = GenericPhyRead (Phy, PhyAddr, GENERIC_PHY_PHYIDR1, &Id1); > + if (EFI_ERROR (Status)) { > + continue; > + } > + Status = GenericPhyRead (Phy, PhyAddr, GENERIC_PHY_PHYIDR2, &Id2); > + if (EFI_ERROR (Status)) { > + continue; > + } > + if (Id1 != 0xFFFF && Id2 != 0xFFFF) { > + Phy->PhyAddr = PhyAddr; > + DEBUG ((DEBUG_INFO, > + "%a: PHY detected at address 0x%02X (PHYIDR1=0x%04X, PHYIDR2=0x%04X)\n", > + __FUNCTION__, PhyAddr, Id1, Id2)); > + return EFI_SUCCESS; > + } > + } > + > + return EFI_NOT_FOUND; > +} > + > +/** > + Start link auto-negotiation on a PHY. > + > + @param Phy[in] Pointer to GENERIC_PHY_PRIVATE_DATA. > + > + @retval EFI_SUCCESS Auto-netogiation started. > + @retval EFI_DEVICE_ERROR PHY register read/write error. > + > +**/ > +STATIC > +EFI_STATUS > +GenericPhyAutoNegotiate ( > + IN GENERIC_PHY_PRIVATE_DATA *Phy > + ) > +{ > + EFI_STATUS Status; > + UINT16 Anar, Gbcr, Bmcr; 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.
> - > - SPDX-License-Identifier: BSD-2-Clause-Patent > - > - This driver acts like a stub to set the Broadcom > - Genet MAC address, until the actual network driver > - is in place. > - > -**/ > - > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include > -#include > - > -STATIC > -VOID > -RMWRegister ( > - UINT32 Offset, > - UINT32 Mask, > - UINT32 In > - ) > -{ > - EFI_PHYSICAL_ADDRESS Addr; > - UINT32 Data; > - UINT32 Shift; > - > - Addr = GENET_BASE_ADDRESS + Offset; > - Data = 0; > - Shift = 1; > - if (In) { > - while (!(Mask & Shift)) > - Shift <<= 1; > - Data = (MmioRead32 (Addr) & ~Mask) | ((In * Shift) & Mask); > - } else { > - Data = MmioRead32 (Addr) & ~Mask; > - } > - > - MmioWrite32 (Addr, Data); > - > - ArmDataMemoryBarrier (); > -} > - > -STATIC > -VOID > -WdRegister ( > - UINT32 Offset, > - UINT32 In > - ) > -{ > - EFI_PHYSICAL_ADDRESS Base = GENET_BASE_ADDRESS; > - > - MmioWrite32 (Base + Offset, In); > - > - ArmDataMemoryBarrier (); > -} > - > -STATIC > -VOID > -SetMacAddress ( > - UINT8* MacAddr > -) > -{ > - // Bring the UMAC out of reset > - RMWRegister (GENET_SYS_RBUF_FLUSH_CTRL, 0x2, 1); > - gBS->Stall (10); > - RMWRegister (GENET_SYS_RBUF_FLUSH_CTRL, 0x2, 0); > - > - // Update the MAC > - DEBUG ((DEBUG_INFO, "Using MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", > - MacAddr[0], MacAddr[1], MacAddr[2], MacAddr[3], MacAddr[4], MacAddr[5])); > - > - WdRegister (GENET_UMAC_MAC0, (MacAddr[0] << 24) | (MacAddr[1] << 16) | > - (MacAddr[2] << 8) | MacAddr[3]); > - WdRegister (GENET_UMAC_MAC1, (MacAddr[4] << 8) | MacAddr[5]); > - > -} > - > -/** > - The entry point of Genet UEFI Driver. > - > - @param ImageHandle The image handle of the UEFI Driver. > - @param SystemTable A pointer to the EFI System Table. > - > - @retval EFI_SUCCESS The Driver or UEFI Driver exited normally. > - @retval EFI_INCOMPATIBLE_VERSION _gUefiDriverRevision is greater than > - SystemTable->Hdr.Revision. > - > -**/ > -EFI_STATUS > -EFIAPI > -GenetEntryPoint ( > - IN EFI_HANDLE ImageHandle, > - IN EFI_SYSTEM_TABLE *SystemTable > - ) > -{ > - UINT64 MacAddr; > - > - // Read the MAC address > - MacAddr = PcdGet64 (PcdBcmGenetMacAddress); > - > - if (MacAddr != 0) { > - SetMacAddress ((UINT8*)&MacAddr); > - } > - > - return EFI_SUCCESS; > -} > diff --git a/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c b/Silicon/Broadcom/Drivers/Net/BcmGenetDxe/GenetUtil.c > new file mode 100644 > index 000000000000..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 > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include "GenetUtil.h" > + > +#include > +#include > +#include > + > +#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 > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "GenetUtil.h" > + > +#include > + > + > +/** > + 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 > > > >