summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/Network/SnpDxe
diff options
context:
space:
mode:
authorvanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>2007-07-24 08:06:37 +0000
committervanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>2007-07-24 08:06:37 +0000
commit8a67d61da4d5a8f08a656cbeea2d902d0ad9042a (patch)
tree6618049196a9f4a206b8d6e42fb8b67a71558503 /MdeModulePkg/Universal/Network/SnpDxe
parentf9bef4b3ac2bf3bd5f79313f772519800761f104 (diff)
downloadedk2-platforms-8a67d61da4d5a8f08a656cbeea2d902d0ad9042a.tar.xz
Import SnpDxe, Tcp4Dxe, Udp4Dxe and MnpDxe.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3416 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Universal/Network/SnpDxe')
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/ComponentName.c163
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf75
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.msa90
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/WaitForPacket.c97
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/callback.c611
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/get_status.c195
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/initialize.c245
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/mcast_ip_to_mac.c165
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/nvdata.c185
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/receive.c255
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/receive_filters.c406
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/reset.c128
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/shutdown.c148
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/snp.c1269
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/snp.h454
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/start.c191
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/station_address.c237
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/statistics.c201
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/stop.c118
-rw-r--r--MdeModulePkg/Universal/Network/SnpDxe/transmit.c399
20 files changed, 5632 insertions, 0 deletions
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/ComponentName.c b/MdeModulePkg/Universal/Network/SnpDxe/ComponentName.c
new file mode 100644
index 0000000000..6da17a3633
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/ComponentName.c
@@ -0,0 +1,163 @@
+/** @file
+
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ ComponentName.c
+
+Abstract:
+
+
+**/
+
+
+
+#include "Snp.h"
+
+//
+// EFI Component Name Functions
+//
+EFI_STATUS
+EFIAPI
+SimpleNetworkComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// EFI Component Name Protocol
+//
+EFI_COMPONENT_NAME_PROTOCOL gSimpleNetworkComponentName = {
+ SimpleNetworkComponentNameGetDriverName,
+ SimpleNetworkComponentNameGetControllerName,
+ "eng"
+};
+
+static EFI_UNICODE_STRING_TABLE mSimpleNetworkDriverNameTable[] = {
+ {
+ "eng",
+ L"Simple Network Protocol Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+/*++
+
+ Routine Description:
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+ Arguments:
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ Language - A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the driver name that 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.
+ DriverName - 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.
+
+ Returns:
+ EFI_SUCCESS - The Unicode string for the Driver specified by This
+ and the language specified by Language was returned
+ in DriverName.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - DriverName is NULL.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+
+--*/
+{
+ return LookupUnicodeString (
+ Language,
+ gSimpleNetworkComponentName.SupportedLanguages,
+ mSimpleNetworkDriverNameTable,
+ DriverName
+ );
+}
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+/*++
+
+ Routine Description:
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ Arguments:
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ ControllerHandle - The handle of a controller that the driver specified by
+ This is managing. This handle specifies the controller
+ whose name is to be returned.
+ ChildHandle - 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.
+ Language - A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that 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.
+ ControllerName - 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.
+
+ Returns:
+ 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.
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - ControllerName is NULL.
+ EFI_UNSUPPORTED - The driver specified by This is not currently managing
+ the controller specified by ControllerHandle and
+ ChildHandle.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+
+--*/
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf b/MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf
new file mode 100644
index 0000000000..34623da4c7
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf
@@ -0,0 +1,75 @@
+#/** @file
+# Component name for module SNP
+#
+# FIX ME!
+# Copyright (c) 2006, Intel Corporation. All right reserved.
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SnpDxe
+ FILE_GUID = A2f436EA-A127-4EF8-957C-8048606FF670
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+ ENTRY_POINT = InitializeSnpNiiDriver
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ receive.c
+ snp.h
+ nvdata.c
+ get_status.c
+ start.c
+ snp.c
+ stop.c
+ statistics.c
+ reset.c
+ shutdown.c
+ mcast_ip_to_mac.c
+ transmit.c
+ WaitForPacket.c
+ receive_filters.c
+ initialize.c
+ ComponentName.c
+ callback.c
+ station_address.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ UefiLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+
+
+[Protocols]
+ gEfiPciIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSimpleNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiNetworkInterfaceIdentifierProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiNetworkInterfaceIdentifierProtocolGuid_31 # PROTOCOL ALWAYS_CONSUMED
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.msa b/MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.msa
new file mode 100644
index 0000000000..748b5c5383
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.msa
@@ -0,0 +1,90 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>SnpDxe</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>A2f436EA-A127-4EF8-957C-8048606FF670</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component name for module SNP</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>
+ <License>All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>SnpDxe</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiDriverEntryPoint</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>station_address.c</Filename>
+ <Filename>SNPEntry.c</Filename>
+ <Filename>callback.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ <Filename>initialize.c</Filename>
+ <Filename>receive_filters.c</Filename>
+ <Filename>WaitForPacket.c</Filename>
+ <Filename>transmit.c</Filename>
+ <Filename>mcast_ip_to_mac.c</Filename>
+ <Filename>shutdown.c</Filename>
+ <Filename>reset.c</Filename>
+ <Filename>statistics.c</Filename>
+ <Filename>stop.c</Filename>
+ <Filename>snp.c</Filename>
+ <Filename>start.c</Filename>
+ <Filename>get_status.c</Filename>
+ <Filename>nvdata.c</Filename>
+ <Filename>snp.h</Filename>
+ <Filename>receive.c</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiNetworkInterfaceIdentifierProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiDevicePathProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiSimpleNetworkProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiPciIoProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ <Extern>
+ <ModuleEntryPoint>InitializeSnpNiiDriver</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea> \ No newline at end of file
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/WaitForPacket.c b/MdeModulePkg/Universal/Network/SnpDxe/WaitForPacket.c
new file mode 100644
index 0000000000..57d82ea160
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/WaitForPacket.c
@@ -0,0 +1,97 @@
+/** @file
+Copyright (c) 2004, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ WaitForPacket.c
+
+Abstract:
+ Event handler to check for available packet.
+
+
+**/
+
+#include "Snp.h"
+
+
+/**
+
+
+
+**/
+VOID
+EFIAPI
+SnpWaitForPacketNotify (
+ EFI_EVENT Event,
+ VOID *SnpPtr
+ )
+{
+ PXE_DB_GET_STATUS PxeDbGetStatus;
+
+ //
+ // Do nothing if either parameter is a NULL pointer.
+ //
+ if (Event == NULL || SnpPtr == NULL) {
+ return ;
+ }
+ //
+ // Do nothing if the SNP interface is not initialized.
+ //
+ switch (((SNP_DRIVER *) SnpPtr)->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ case EfiSimpleNetworkStarted:
+ default:
+ return ;
+ }
+ //
+ // Fill in CDB for UNDI GetStatus().
+ //
+ ((SNP_DRIVER *) SnpPtr)->cdb.OpCode = PXE_OPCODE_GET_STATUS;
+ ((SNP_DRIVER *) SnpPtr)->cdb.OpFlags = 0;
+ ((SNP_DRIVER *) SnpPtr)->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ ((SNP_DRIVER *) SnpPtr)->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ ((SNP_DRIVER *) SnpPtr)->cdb.DBsize = sizeof (UINT32) * 2;
+ ((SNP_DRIVER *) SnpPtr)->cdb.DBaddr = (UINT64)(UINTN) (((SNP_DRIVER *) SnpPtr)->db);
+ ((SNP_DRIVER *) SnpPtr)->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ ((SNP_DRIVER *) SnpPtr)->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ ((SNP_DRIVER *) SnpPtr)->cdb.IFnum = ((SNP_DRIVER *) SnpPtr)->if_num;
+ ((SNP_DRIVER *) SnpPtr)->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Clear contents of DB buffer.
+ //
+ ZeroMem (((SNP_DRIVER *) SnpPtr)->db, sizeof (UINT32) * 2);
+
+ //
+ // Issue UNDI command and check result.
+ //
+ (*((SNP_DRIVER *) SnpPtr)->issue_undi32_command) ((UINT64)(UINTN) &((SNP_DRIVER *) SnpPtr)->cdb);
+
+ if (((SNP_DRIVER *) SnpPtr)->cdb.StatCode != EFI_SUCCESS) {
+ return ;
+ }
+ //
+ // We might have a packet. Check the receive length and signal
+ // the event if the length is not zero.
+ //
+ CopyMem (
+ &PxeDbGetStatus,
+ ((SNP_DRIVER *) SnpPtr)->db,
+ sizeof (UINT32) * 2
+ );
+
+ if (PxeDbGetStatus.RxFrameLen != 0) {
+ gBS->SignalEvent (Event);
+ }
+}
+
+/* eof - WaitForPacket.c */
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/callback.c b/MdeModulePkg/Universal/Network/SnpDxe/callback.c
new file mode 100644
index 0000000000..c246874917
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/callback.c
@@ -0,0 +1,611 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ callback.c
+
+Abstract:
+ This file contains two sets of callback routines for undi3.0 and undi3.1.
+ the callback routines for Undi3.1 have an extra parameter UniqueId which
+ stores the interface context for the NIC that snp is trying to talk..
+
+--*/
+
+
+#include "Snp.h"
+
+//
+// Global variables
+// these 2 global variables are used only for 3.0 undi. we could not place
+// them in the snp structure because we will not know which snp structure
+// in the callback context!
+//
+STATIC BOOLEAN mInitializeLock = TRUE;
+STATIC EFI_LOCK mLock;
+
+//
+// End Global variables
+//
+extern EFI_PCI_IO_PROTOCOL *mPciIoFncs;
+
+VOID
+snp_undi32_callback_v2p_30 (
+ IN UINT64 CpuAddr,
+ IN OUT UINT64 DeviceAddrPtr
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine with a virtual or CPU address that SNP provided
+ to convert it to a physical or device address. Since EFI uses the identical
+ mapping, this routine returns the physical address same as the virtual address
+ for most of the addresses. an address above 4GB cannot generally be used as a
+ device address, it needs to be mapped to a lower physical address. This routine
+ does not call the map routine itself, but it assumes that the mapping was done
+ at the time of providing the address to UNDI. This routine just looks up the
+ address in a map table (which is the v2p structure chain)
+
+Arguments:
+ CpuAddr - virtual address of a buffer
+ DeviceAddrPtr - pointer to the physical address
+
+Returns:
+ void - The DeviceAddrPtr will contain 0 in case of any error
+
+--*/
+{
+ struct s_v2p *v2p;
+ //
+ // Do nothing if virtual address is zero or physical pointer is NULL.
+ // No need to map if the virtual address is within 4GB limit since
+ // EFI uses identical mapping
+ //
+ if ((CpuAddr == 0) || (DeviceAddrPtr == 0)) {
+ DEBUG ((EFI_D_ERROR, "\nv2p: Null virtual address or physical pointer.\n"));
+ return ;
+ }
+
+ if (CpuAddr < FOUR_GIGABYTES) {
+ *(UINT64 *) (UINTN) DeviceAddrPtr = CpuAddr;
+ return ;
+ }
+ //
+ // SNP creates a vaddr tp paddr mapping at the time of calling undi with any
+ // big address, this callback routine just looks up in the v2p list and
+ // returns the physical address for any given virtual address.
+ //
+ if (find_v2p (&v2p, (VOID *) (UINTN) CpuAddr) != EFI_SUCCESS) {
+ *(UINT64 *) (UINTN) DeviceAddrPtr = CpuAddr;
+ } else {
+ *(UINT64 *) (UINTN) DeviceAddrPtr = v2p->paddr;
+ }
+}
+
+VOID
+snp_undi32_callback_block_30 (
+ IN UINT32 Enable
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine when it wants to have exclusive access to a critical
+ section of the code/data
+
+Arguments:
+ Enable - non-zero indicates acquire
+ zero indicates release
+
+Returns:
+ void
+--*/
+{
+ //
+ // tcpip was calling snp at tpl_notify and if we acquire a lock that was
+ // created at a lower level (TPL_CALLBACK) it gives an assert!
+ //
+ if (mInitializeLock) {
+ EfiInitializeLock (&mLock, TPL_NOTIFY);
+ mInitializeLock = FALSE;
+ }
+
+ if (Enable != 0) {
+ EfiAcquireLock (&mLock);
+ } else {
+ EfiReleaseLock (&mLock);
+ }
+}
+
+VOID
+snp_undi32_callback_delay_30 (
+ IN UINT64 MicroSeconds
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine with the number of micro seconds when it wants to
+ pause.
+
+Arguments:
+ MicroSeconds - number of micro seconds to pause, ususlly multiple of 10
+
+Returns:
+ void
+--*/
+{
+ if (MicroSeconds != 0) {
+ gBS->Stall ((UINTN) MicroSeconds);
+ }
+}
+
+VOID
+snp_undi32_callback_memio_30 (
+ IN UINT8 ReadOrWrite,
+ IN UINT8 NumBytes,
+ IN UINT64 Address,
+ IN OUT UINT64 BufferAddr
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ This is the IO routine for UNDI. This is not currently being used by UNDI3.0
+ because Undi3.0 uses io/mem offsets relative to the beginning of the device
+ io/mem address and so it needs to use the PCI_IO_FUNCTION that abstracts the
+ start of the device's io/mem addresses. Since SNP cannot retrive the context
+ of the undi3.0 interface it cannot use the PCI_IO_FUNCTION that specific for
+ that NIC and uses one global IO functions structure, this does not work.
+ This however works fine for EFI1.0 Undis because they use absolute addresses
+ for io/mem access.
+
+Arguments:
+ ReadOrWrite - indicates read or write, IO or Memory
+ NumBytes - number of bytes to read or write
+ Address - IO or memory address to read from or write to
+ BufferAddr - memory location to read into or that contains the bytes
+ to write
+
+Returns:
+
+--*/
+{
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+
+ switch (NumBytes) {
+ case 2:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;
+ break;
+
+ case 4:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;
+ break;
+
+ case 8:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;
+ break;
+
+ default:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;
+ }
+
+ switch (ReadOrWrite) {
+ case PXE_IO_READ:
+ mPciIoFncs->Io.Read (
+ mPciIoFncs,
+ Width,
+ 1, // BAR 1, IO base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+
+ case PXE_IO_WRITE:
+ mPciIoFncs->Io.Write (
+ mPciIoFncs,
+ Width,
+ 1, // BAR 1, IO base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+
+ case PXE_MEM_READ:
+ mPciIoFncs->Mem.Read (
+ mPciIoFncs,
+ Width,
+ 0, // BAR 0, Memory base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+
+ case PXE_MEM_WRITE:
+ mPciIoFncs->Mem.Write (
+ mPciIoFncs,
+ Width,
+ 0, // BAR 0, Memory base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+ }
+
+ return ;
+}
+//
+// New callbacks for 3.1:
+// there won't be a virtual2physical callback for UNDI 3.1 because undi3.1 uses
+// the MemMap call to map the required address by itself!
+//
+VOID
+snp_undi32_callback_block (
+ IN UINT64 UniqueId,
+ IN UINT32 Enable
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI3.1 at undi_start time.
+ UNDI call this routine when it wants to have exclusive access to a critical
+ section of the code/data
+
+Arguments:
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store
+ Undi interface context (Undi does not read or write this variable)
+ Enable - non-zero indicates acquire
+ zero indicates release
+
+Returns:
+ void
+
+--*/
+{
+ SNP_DRIVER *snp;
+
+ snp = (SNP_DRIVER *) (UINTN) UniqueId;
+ //
+ // tcpip was calling snp at tpl_notify and when we acquire a lock that was
+ // created at a lower level (TPL_CALLBACK) it gives an assert!
+ //
+ if (Enable != 0) {
+ EfiAcquireLock (&snp->lock);
+ } else {
+ EfiReleaseLock (&snp->lock);
+ }
+}
+
+VOID
+snp_undi32_callback_delay (
+ IN UINT64 UniqueId,
+ IN UINT64 MicroSeconds
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine with the number of micro seconds when it wants to
+ pause.
+
+Arguments:
+ MicroSeconds - number of micro seconds to pause, ususlly multiple of 10
+
+Returns:
+ void
+--*/
+{
+ if (MicroSeconds != 0) {
+ gBS->Stall ((UINTN) MicroSeconds);
+ }
+}
+
+/*
+ * IO routine for UNDI start CPB.
+ */
+VOID
+snp_undi32_callback_memio (
+ UINT64 UniqueId,
+ UINT8 ReadOrWrite,
+ UINT8 NumBytes,
+ UINT64 Address,
+ UINT64 BufferAddr
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ This is the IO routine for UNDI3.1.
+
+Arguments:
+ ReadOrWrite - indicates read or write, IO or Memory
+ NumBytes - number of bytes to read or write
+ Address - IO or memory address to read from or write to
+ BufferAddr - memory location to read into or that contains the bytes
+ to write
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+
+ snp = (SNP_DRIVER *) (UINTN) UniqueId;
+
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;
+ switch (NumBytes) {
+ case 2:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;
+ break;
+
+ case 4:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;
+ break;
+
+ case 8:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;
+ break;
+ }
+
+ switch (ReadOrWrite) {
+ case PXE_IO_READ:
+ snp->IoFncs->Io.Read (
+ snp->IoFncs,
+ Width,
+ snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+
+ case PXE_IO_WRITE:
+ snp->IoFncs->Io.Write (
+ snp->IoFncs,
+ Width,
+ snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+
+ case PXE_MEM_READ:
+ snp->IoFncs->Mem.Read (
+ snp->IoFncs,
+ Width,
+ snp->MemoryBarIndex, // BAR 0, Memory base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+
+ case PXE_MEM_WRITE:
+ snp->IoFncs->Mem.Write (
+ snp->IoFncs,
+ Width,
+ snp->MemoryBarIndex, // BAR 0, Memory base address
+ Address,
+ 1, // count
+ (VOID *) (UINTN) BufferAddr
+ );
+ break;
+ }
+
+ return ;
+}
+
+VOID
+snp_undi32_callback_map (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN OUT UINT64 DeviceAddrPtr
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine when it has to map a CPU address to a device
+ address.
+
+Arguments:
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store
+ Undi interface context (Undi does not read or write this variable)
+ CpuAddr - Virtual address to be mapped!
+ NumBytes - size of memory to be mapped
+ Direction - direction of data flow for this memory's usage:
+ cpu->device, device->cpu or both ways
+ DeviceAddrPtr - pointer to return the mapped device address
+
+Returns:
+ None
+
+--*/
+{
+ EFI_PHYSICAL_ADDRESS *DevAddrPtr;
+ EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag;
+ UINTN BuffSize;
+ SNP_DRIVER *snp;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ BuffSize = (UINTN) NumBytes;
+ snp = (SNP_DRIVER *) (UINTN) UniqueId;
+ DevAddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr;
+
+ if (CpuAddr == 0) {
+ *DevAddrPtr = 0;
+ return ;
+ }
+
+ switch (Direction) {
+ case TO_AND_FROM_DEVICE:
+ DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer;
+ break;
+
+ case FROM_DEVICE:
+ DirectionFlag = EfiPciIoOperationBusMasterWrite;
+ break;
+
+ case TO_DEVICE:
+ DirectionFlag = EfiPciIoOperationBusMasterRead;
+ break;
+
+ default:
+ *DevAddrPtr = 0;
+ //
+ // any non zero indicates error!
+ //
+ return ;
+ }
+ //
+ // find an unused map_list entry
+ //
+ for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
+ if (snp->map_list[Index].virt == 0) {
+ break;
+ }
+ }
+
+ if (Index >= MAX_MAP_LENGTH) {
+ DEBUG ((EFI_D_INFO, "SNP maplist is FULL\n"));
+ *DevAddrPtr = 0;
+ return ;
+ }
+
+ snp->map_list[Index].virt = (EFI_PHYSICAL_ADDRESS) CpuAddr;
+
+ Status = snp->IoFncs->Map (
+ snp->IoFncs,
+ DirectionFlag,
+ (VOID *) (UINTN) CpuAddr,
+ &BuffSize,
+ DevAddrPtr,
+ &(snp->map_list[Index].map_cookie)
+ );
+ if (Status != EFI_SUCCESS) {
+ *DevAddrPtr = 0;
+ snp->map_list[Index].virt = 0;
+ }
+
+ return ;
+}
+
+VOID
+snp_undi32_callback_unmap (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN UINT64 DeviceAddr
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine when it wants to unmap an address that was previously
+ mapped using map callback
+
+Arguments:
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store
+ Undi interface context (Undi does not read or write this variable)
+ CpuAddr - Virtual address that was mapped!
+ NumBytes - size of memory mapped
+ Direction- direction of data flow for this memory's usage:
+ cpu->device, device->cpu or both ways
+ DeviceAddr - the mapped device address
+
+Returns:
+
+--*/
+{
+ SNP_DRIVER *snp;
+ UINT16 Index;
+
+ snp = (SNP_DRIVER *) (UINTN) UniqueId;
+
+ for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
+ if (snp->map_list[Index].virt == CpuAddr) {
+ break;
+ }
+ }
+
+ if (Index >= MAX_MAP_LENGTH)
+ {
+ DEBUG ((EFI_D_ERROR, "SNP could not find a mapping, failed to unmap.\n"));
+ return ;
+ }
+
+ snp->IoFncs->Unmap (snp->IoFncs, snp->map_list[Index].map_cookie);
+ snp->map_list[Index].virt = 0;
+ snp->map_list[Index].map_cookie = NULL;
+ return ;
+}
+
+VOID
+snp_undi32_callback_sync (
+ UINT64 UniqueId,
+ UINT64 CpuAddr,
+ UINT32 NumBytes,
+ UINT32 Direction,
+ UINT64 DeviceAddr
+ )
+/*++
+
+Routine Description:
+ This is a callback routine supplied to UNDI at undi_start time.
+ UNDI call this routine when it wants synchronize the virtual buffer contents
+ with the mapped buffer contents. The virtual and mapped buffers need not
+ correspond to the same physical memory (especially if the virtual address is
+ > 4GB). Depending on the direction for which the buffer is mapped, undi will
+ need to synchronize their contents whenever it writes to/reads from the buffer
+ using either the cpu address or the device address.
+
+ EFI does not provide a sync call, since virt=physical, we sould just do
+ the synchronization ourself here!
+
+Arguments:
+ UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store
+ Undi interface context (Undi does not read or write this variable)
+ CpuAddr - Virtual address that was mapped!
+ NumBytes - size of memory mapped
+ Direction- direction of data flow for this memory's usage:
+ cpu->device, device->cpu or both ways
+ DeviceAddr - the mapped device address
+
+Returns:
+
+--*/
+{
+ if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) {
+ return ;
+
+ }
+
+ switch (Direction) {
+ case FROM_DEVICE:
+ CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes);
+ break;
+
+ case TO_DEVICE:
+ CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes);
+ break;
+ }
+
+ return ;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/get_status.c b/MdeModulePkg/Universal/Network/SnpDxe/get_status.c
new file mode 100644
index 0000000000..0c1cd8a68e
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/get_status.c
@@ -0,0 +1,195 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ get_status.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-03 M(f)J Genesis.
+
+**/
+
+#include "Snp.h"
+
+STATIC
+/**
+ this routine calls undi to get the status of the interrupts, get the list of
+ transmit buffers that completed transmitting!
+
+ @param snp pointer to snp driver structure
+ @param InterruptStatusPtr a non null pointer gets the interrupt status
+ @param TransmitBufferListPtrs a non null ointer gets the list of pointers of
+ previously transmitted buffers whose
+ transmission was completed asynchrnously.
+
+
+**/
+EFI_STATUS
+pxe_getstatus (
+ SNP_DRIVER *snp,
+ UINT32 *InterruptStatusPtr,
+ VOID **TransmitBufferListPtr
+ )
+{
+ PXE_DB_GET_STATUS *db;
+ UINT16 InterruptFlags;
+ UINT64 TempData;
+
+ db = snp->db;
+ snp->cdb.OpCode = PXE_OPCODE_GET_STATUS;
+
+ snp->cdb.OpFlags = 0;
+
+ if (TransmitBufferListPtr != NULL) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS;
+ }
+
+ if (InterruptStatusPtr != NULL) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_GET_INTERRUPT_STATUS;
+ }
+
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+
+ //
+ // size DB for return of one buffer
+ //
+ snp->cdb.DBsize = (UINT16) (((UINT16) (sizeof (PXE_DB_GET_STATUS)) - (UINT16) (sizeof db->TxBuffer)) + (UINT16) (sizeof db->TxBuffer[0]));
+
+ snp->cdb.DBaddr = (UINT64)(UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.get_status() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != EFI_SUCCESS) {
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.get_status() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatFlags)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // report the values back..
+ //
+ if (InterruptStatusPtr != NULL) {
+ InterruptFlags = (UINT16) (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK);
+
+ *InterruptStatusPtr = 0;
+
+ if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_RECEIVE) {
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+ }
+
+ if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_TRANSMIT) {
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+ }
+
+ if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_COMMAND) {
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;
+ }
+
+ if (InterruptFlags & PXE_STATFLAGS_GET_STATUS_SOFTWARE) {
+ *InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;
+ }
+
+ }
+
+ if (TransmitBufferListPtr != NULL) {
+ *TransmitBufferListPtr =
+ (
+ (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN) ||
+ (snp->cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY)
+ ) ? 0 : (VOID *) (UINTN) db->TxBuffer[0];
+
+ TempData = (UINT64) (UINTN) (*TransmitBufferListPtr);
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {
+ del_v2p ((VOID *) (UINTN) (db->TxBuffer[0]));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This is the SNP interface routine for getting the status
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_getstatus routine to actually get the undi status
+
+ @param this context pointer
+ @param InterruptStatusPtr a non null pointer gets the interrupt status
+ @param TransmitBufferListPtrs a non null ointer gets the list of pointers of
+ previously transmitted buffers whose
+ transmission was completed asynchrnously.
+
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_get_status (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ OUT UINT32 *InterruptStatusPtr OPTIONAL,
+ OUT VOID **TransmitBufferListPtr OPTIONAL
+ )
+{
+ SNP_DRIVER *snp;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InterruptStatusPtr == NULL && TransmitBufferListPtr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ Status = pxe_getstatus (snp, InterruptStatusPtr, TransmitBufferListPtr);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/initialize.c b/MdeModulePkg/Universal/Network/SnpDxe/initialize.c
new file mode 100644
index 0000000000..69154fc0c7
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/initialize.c
@@ -0,0 +1,245 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ initialize.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-09 M(f)J Genesis.
+
+**/
+
+
+#include "Snp.h"
+
+VOID
+EFIAPI
+SnpWaitForPacketNotify (
+ IN EFI_EVENT Event,
+ IN VOID *SnpPtr
+ );
+
+
+/**
+ this routine calls undi to initialize the interface.
+
+ @param snp pointer to snp driver structure
+ @param CableDetectFlag Do/don't detect the cable (depending on what undi
+ supports)
+
+
+**/
+EFI_STATUS
+pxe_init (
+ SNP_DRIVER *snp,
+ UINT16 CableDetectFlag
+ )
+{
+ PXE_CPB_INITIALIZE *cpb;
+ VOID *addr;
+ EFI_STATUS Status;
+
+ cpb = snp->cpb;
+ if (snp->tx_rx_bufsize != 0) {
+ Status = snp->IoFncs->AllocateBuffer (
+ snp->IoFncs,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ SNP_MEM_PAGES (snp->tx_rx_bufsize),
+ &addr,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->pxe_init() AllocateBuffer %xh (%r)\n",
+ Status,
+ Status)
+ );
+
+ return Status;
+ }
+
+ ASSERT (addr);
+
+ snp->tx_rx_buffer = addr;
+ }
+
+ cpb->MemoryAddr = (UINT64)(UINTN) snp->tx_rx_buffer;
+
+ cpb->MemoryLength = snp->tx_rx_bufsize;
+
+ //
+ // let UNDI decide/detect these values
+ //
+ cpb->LinkSpeed = 0;
+ cpb->TxBufCnt = 0;
+ cpb->TxBufSize = 0;
+ cpb->RxBufCnt = 0;
+ cpb->RxBufSize = 0;
+
+ cpb->DuplexMode = PXE_DUPLEX_DEFAULT;
+
+ cpb->LoopBackMode = LOOPBACK_NORMAL;
+
+ snp->cdb.OpCode = PXE_OPCODE_INITIALIZE;
+ snp->cdb.OpFlags = CableDetectFlag;
+
+ snp->cdb.CPBsize = sizeof (PXE_CPB_INITIALIZE);
+ snp->cdb.DBsize = sizeof (PXE_DB_INITIALIZE);
+
+ snp->cdb.CPBaddr = (UINT64)(UINTN) snp->cpb;
+ snp->cdb.DBaddr = (UINT64)(UINTN) snp->db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ DEBUG ((EFI_D_NET, "\nsnp->undi.initialize() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode == PXE_STATCODE_SUCCESS) {
+ snp->mode.State = EfiSimpleNetworkInitialized;
+
+ Status = EFI_SUCCESS;
+ } else {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nsnp->undi.initialize() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ if (snp->tx_rx_buffer != NULL) {
+ snp->IoFncs->FreeBuffer (
+ snp->IoFncs,
+ SNP_MEM_PAGES (snp->tx_rx_bufsize),
+ (VOID *) snp->tx_rx_buffer
+ );
+ }
+
+ snp->tx_rx_buffer = NULL;
+
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+
+/**
+ This is the SNP interface routine for initializing the interface
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_initialize routine to actually do the undi initialization
+
+ @param this context pointer
+ @param extra_rx_buffer_size optional parameter, indicates extra space for
+ rx_buffers
+ @param extra_tx_buffer_size optional parameter, indicates extra space for
+ tx_buffers
+
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_initialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN UINTN extra_rx_buffer_size OPTIONAL,
+ IN UINTN extra_tx_buffer_size OPTIONAL
+ )
+{
+ EFI_STATUS EfiStatus;
+ SNP_DRIVER *snp;
+ EFI_TPL OldTpl;
+
+ //
+ //
+ //
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (snp == NULL) {
+ EfiStatus = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ EfiStatus = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ EfiStatus = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ EfiStatus = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ &SnpWaitForPacketNotify,
+ snp,
+ &snp->snp.WaitForPacket
+ );
+
+ if (EFI_ERROR (EfiStatus)) {
+ snp->snp.WaitForPacket = NULL;
+ EfiStatus = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ //
+ //
+ //
+ snp->mode.MCastFilterCount = 0;
+ snp->mode.ReceiveFilterSetting = 0;
+ ZeroMem (snp->mode.MCastFilter, sizeof snp->mode.MCastFilter);
+ CopyMem (
+ &snp->mode.CurrentAddress,
+ &snp->mode.PermanentAddress,
+ sizeof (EFI_MAC_ADDRESS)
+ );
+
+ //
+ // Compute tx/rx buffer sizes based on UNDI init info and parameters.
+ //
+ snp->tx_rx_bufsize = (UINT32) (snp->init_info.MemoryRequired + extra_rx_buffer_size + extra_tx_buffer_size);
+
+ if (snp->mode.MediaPresentSupported) {
+ if (pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) == EFI_SUCCESS) {
+ snp->mode.MediaPresent = TRUE;
+ goto ON_EXIT;
+ }
+ }
+
+ snp->mode.MediaPresent = FALSE;
+
+ EfiStatus = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
+
+ if (EFI_ERROR (EfiStatus)) {
+ gBS->CloseEvent (snp->snp.WaitForPacket);
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return EfiStatus;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/mcast_ip_to_mac.c b/MdeModulePkg/Universal/Network/SnpDxe/mcast_ip_to_mac.c
new file mode 100644
index 0000000000..91b5e02fc1
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/mcast_ip_to_mac.c
@@ -0,0 +1,165 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ mcast_ip_to_mac.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-17 M(f)J Genesis.
+
+**/
+
+#include "Snp.h"
+
+/**
+ this routine calls undi to convert an multicast IP address to a MAC address
+
+ @param snp pointer to snp driver structure
+ @param IPv6 flag to indicate if this is an ipv6 address
+ @param IP multicast IP address
+ @param MAC pointer to hold the return MAC address
+
+
+**/
+STATIC
+EFI_STATUS
+pxe_ip2mac (
+ IN SNP_DRIVER *snp,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ IN OUT EFI_MAC_ADDRESS *MAC
+ )
+{
+ PXE_CPB_MCAST_IP_TO_MAC *cpb;
+ PXE_DB_MCAST_IP_TO_MAC *db;
+
+ cpb = snp->cpb;
+ db = snp->db;
+ snp->cdb.OpCode = PXE_OPCODE_MCAST_IP_TO_MAC;
+ snp->cdb.OpFlags = (UINT16) (IPv6 ? PXE_OPFLAGS_MCAST_IPV6_TO_MAC : PXE_OPFLAGS_MCAST_IPV4_TO_MAC);
+ snp->cdb.CPBsize = sizeof (PXE_CPB_MCAST_IP_TO_MAC);
+ snp->cdb.DBsize = sizeof (PXE_DB_MCAST_IP_TO_MAC);
+
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;
+ snp->cdb.DBaddr = (UINT64)(UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ CopyMem (&cpb->IP, IP, sizeof (PXE_IP_ADDR));
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.mcast_ip_to_mac() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_INVALID_CPB:
+ return EFI_INVALID_PARAMETER;
+
+ case PXE_STATCODE_UNSUPPORTED:
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.mcast_ip_to_mac() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+ return EFI_UNSUPPORTED;
+
+ default:
+ //
+ // UNDI command failed. Return EFI_DEVICE_ERROR
+ // to caller.
+ //
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.mcast_ip_to_mac() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (MAC, &db->MAC, sizeof (PXE_MAC_ADDR));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This is the SNP interface routine for converting a multicast IP address to
+ a MAC address.
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_ip2mac routine to actually do the conversion
+
+ @param this context pointer
+ @param IPv6 flag to indicate if this is an ipv6 address
+ @param IP multicast IP address
+ @param MAC pointer to hold the return MAC address
+
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_mcast_ip_to_mac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+{
+ SNP_DRIVER *snp;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Get pointer to SNP driver instance for *this.
+ //
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IP == NULL || MAC == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ Status = pxe_ip2mac (snp, IPv6, IP, MAC);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/nvdata.c b/MdeModulePkg/Universal/Network/SnpDxe/nvdata.c
new file mode 100644
index 0000000000..531a4d6929
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/nvdata.c
@@ -0,0 +1,185 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ nvdata.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-03 M(f)J Genesis.
+
+**/
+
+#include "snp.h"
+
+
+/**
+ This routine calls Undi to read the desired number of eeprom bytes.
+
+ @param snp pointer to the snp driver structure
+ @param RegOffset eeprom register value relative to the base address
+ @param NumBytes number of bytes to read
+ @param BufferPtr pointer where to read into
+
+
+**/
+STATIC
+EFI_STATUS
+pxe_nvdata_read (
+ IN SNP_DRIVER *snp,
+ IN UINTN RegOffset,
+ IN UINTN NumBytes,
+ IN OUT VOID *BufferPtr
+ )
+{
+ PXE_DB_NVDATA *db;
+
+ db = snp->db;
+ snp->cdb.OpCode = PXE_OPCODE_NVDATA;
+
+ snp->cdb.OpFlags = PXE_OPFLAGS_NVDATA_READ;
+
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+
+ snp->cdb.DBsize = sizeof (PXE_DB_NVDATA);
+ snp->cdb.DBaddr = (UINT64)(UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.nvdata () "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_UNSUPPORTED:
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.nvdata() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_UNSUPPORTED;
+
+ default:
+ DEBUG (
+ (EFI_D_NET,
+ "\nsnp->undi.nvdata() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (BufferPtr, db->Data.Byte + RegOffset, NumBytes);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This is an interface call provided by SNP.
+ It does the basic checking on the input parameters and retrieves snp structure
+ and then calls the read_nvdata() call which does the actual reading
+
+ @param this context pointer
+ @param ReadOrWrite true for reading and false for writing
+ @param RegOffset eeprom register relative to the base
+ @param NumBytes how many bytes to read
+ @param BufferPtr address of memory to read into
+
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_nvdata (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN ReadOrWrite,
+ IN UINTN RegOffset,
+ IN UINTN NumBytes,
+ IN OUT VOID *BufferPtr
+ )
+{
+ SNP_DRIVER *snp;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Get pointer to SNP driver instance for *this.
+ //
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Return error if the SNP is not initialized.
+ //
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ //
+ // Return error if non-volatile memory variables are not valid.
+ //
+ if (snp->mode.NvRamSize == 0 || snp->mode.NvRamAccessSize == 0) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_EXIT;
+ }
+ //
+ // Check for invalid parameter combinations.
+ //
+ if ((NumBytes == 0) ||
+ (BufferPtr == NULL) ||
+ (RegOffset >= snp->mode.NvRamSize) ||
+ (RegOffset + NumBytes > snp->mode.NvRamSize) ||
+ (NumBytes % snp->mode.NvRamAccessSize != 0) ||
+ (RegOffset % snp->mode.NvRamAccessSize != 0)
+ ) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+ //
+ // check the implementation flags of undi if we can write the nvdata!
+ //
+ if (!ReadOrWrite) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = pxe_nvdata_read (snp, RegOffset, NumBytes, BufferPtr);
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/receive.c b/MdeModulePkg/Universal/Network/SnpDxe/receive.c
new file mode 100644
index 0000000000..64ca2565d9
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/receive.c
@@ -0,0 +1,255 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ receive.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-03 M(f)J Genesis.
+
+**/
+
+
+#include "Snp.h"
+
+/**
+ this routine calls undi to receive a packet and fills in the data in the
+ input pointers!
+
+ @param snp pointer to snp driver structure
+ @param BufferPtr pointer to the memory for the received data
+ @param BuffSizePtr is a pointer to the length of the buffer on entry and
+ contains the length of the received data on return
+ @param HeaderSizePtr pointer to the header portion of the data received.
+ @param SourceAddrPtr optional parameter, is a pointer to contain the
+ source ethernet address on return
+ @param DestinationAddrPtr optional parameter, is a pointer to contain the
+ destination ethernet address on return
+ @param ProtocolPtr optional parameter, is a pointer to contain the
+ protocol type from the ethernet header on return
+
+
+**/
+STATIC
+EFI_STATUS
+pxe_receive (
+ SNP_DRIVER *snp,
+ VOID *BufferPtr,
+ UINTN *BuffSizePtr,
+ UINTN *HeaderSizePtr,
+ EFI_MAC_ADDRESS *SourceAddrPtr,
+ EFI_MAC_ADDRESS *DestinationAddrPtr,
+ UINT16 *ProtocolPtr
+ )
+{
+ PXE_CPB_RECEIVE *cpb;
+ PXE_DB_RECEIVE *db;
+ UINTN buf_size;
+ UINT64 TempData;
+
+ cpb = snp->cpb;
+ db = snp->db;
+ buf_size = *BuffSizePtr;
+ //
+ // IMPORTANT NOTE:
+ // In case of the older 3.0 UNDI, if the input buffer address is beyond 4GB,
+ // DO NOT call the map function on the given buffer, instead use
+ // a global buffer. The reason is that UNDI3.0 has some unnecessary check of
+ // making sure that all the addresses (whether or not they will be given
+ // to the NIC ) supplied to it are below 4GB. It may or may not use
+ // the mapped address after all (like in case of CPB and DB)!
+ // Instead of using the global buffer whose address is allocated within the
+ // 2GB limit if I start mapping the given buffer we lose the data, here is
+ // why!!!
+ // if our address is > 4GB, the map call creates another buffer below 2GB and
+ // copies data to/from the original buffer to the mapped buffer either at
+ // map time or unmap time depending on the map direction.
+ // UNDI will not complain since we already mapped the buffer to be
+ // within the 2GB limit but will not use (I know undi) the mapped address
+ // since it does not give the user buffers to the NIC's receive unit,
+ // It just copies the received packet into the user buffer using the virtual
+ // (CPU) address rather than the mapped (device or physical) address.
+ // When the UNDI call returns, if we then unmap the buffer, we will lose
+ // the contents because unmap copies the contents of the mapped buffer into
+ // the original buffer (since the direction is FROM_DEVICE) !!!
+ //
+ // this is not a problem in Undi 3.1 because this undi uses it's map callback
+ // routine to map a cpu address to device address and it does it only if
+ // it is giving the address to the device and unmaps it before using the cpu
+ // address!
+ //
+ TempData = (UINT64) (UINTN) BufferPtr;
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {
+ cpb->BufferAddr = (UINT64)(UINTN) snp->receive_buf;
+ cpb->BufferLen = (UINT32) (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);
+ } else {
+ cpb->BufferAddr = (UINT64)(UINTN) BufferPtr;
+ cpb->BufferLen = (UINT32) *BuffSizePtr;
+ }
+
+ cpb->reserved = 0;
+
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+
+ snp->cdb.CPBsize = sizeof (PXE_CPB_RECEIVE);
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;
+
+ snp->cdb.DBsize = sizeof (PXE_DB_RECEIVE);
+ snp->cdb.DBaddr = (UINT64)(UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_INFO, "\nsnp->undi.receive () "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_NO_DATA:
+ DEBUG (
+ (EFI_D_INFO,
+ "\nsnp->undi.receive () %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_NOT_READY;
+
+ default:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ *BuffSizePtr = db->FrameLen;
+
+ if (HeaderSizePtr != NULL) {
+ *HeaderSizePtr = db->MediaHeaderLen;
+ }
+
+ if (SourceAddrPtr != NULL) {
+ CopyMem (SourceAddrPtr, &db->SrcAddr, snp->mode.HwAddressSize);
+ }
+
+ if (DestinationAddrPtr != NULL) {
+ CopyMem (DestinationAddrPtr, &db->DestAddr, snp->mode.HwAddressSize);
+ }
+
+ if (ProtocolPtr != NULL) {
+ *ProtocolPtr = (UINT16) PXE_SWAP_UINT16 (db->Protocol); /* we need to do the byte swapping */
+ }
+
+ TempData = (UINT64) (UINTN) BufferPtr;
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {
+ CopyMem (BufferPtr, snp->receive_buf, snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);
+ }
+
+ return (*BuffSizePtr <= buf_size) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
+}
+
+
+/**
+ This is the SNP interface routine for receiving network data.
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_receive routine to actually do the receive!
+
+ @param this context pointer
+ @param HeaderSizePtr optional parameter and is a pointer to the header
+ portion of the data received.
+ @param BuffSizePtr is a pointer to the length of the buffer on entry and
+ contains the length of the received data on return
+ @param BufferPtr pointer to the memory for the received data
+ @param SourceAddrPtr optional parameter, is a pointer to contain the
+ source ethernet address on return
+ @param DestinationAddrPtr optional parameter, is a pointer to contain the
+ destination ethernet address on return
+ @param ProtocolPtr optional parameter, is a pointer to contain the
+ protocol type from the ethernet header on return
+
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_receive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ OUT UINTN *HeaderSizePtr OPTIONAL,
+ IN OUT UINTN *BuffSizePtr,
+ OUT VOID *BufferPtr,
+ OUT EFI_MAC_ADDRESS * SourceAddrPtr OPTIONAL,
+ OUT EFI_MAC_ADDRESS * DestinationAddrPtr OPTIONAL,
+ OUT UINT16 *ProtocolPtr OPTIONAL
+ )
+{
+ SNP_DRIVER *snp;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ if ((BuffSizePtr == NULL) || (BufferPtr == NULL)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if (!snp->mode.ReceiveFilterSetting) {
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ Status = pxe_receive (
+ snp,
+ BufferPtr,
+ BuffSizePtr,
+ HeaderSizePtr,
+ SourceAddrPtr,
+ DestinationAddrPtr,
+ ProtocolPtr
+ );
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/receive_filters.c b/MdeModulePkg/Universal/Network/SnpDxe/receive_filters.c
new file mode 100644
index 0000000000..3886d2078d
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/receive_filters.c
@@ -0,0 +1,406 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ receive_filters.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-17 M(f)J Genesis.
+
+**/
+
+
+
+#include "Snp.h"
+
+/**
+ this routine calls undi to enable the receive filters.
+
+ @param snp pointer to snp driver structure
+ @param EnableFlags bit mask for enabling the receive filters
+ @param MCastAddressCount multicast address count for a new multicast address
+ list
+ @param MCastAddressList list of new multicast addresses
+
+
+**/
+STATIC
+EFI_STATUS
+pxe_rcvfilter_enable (
+ SNP_DRIVER *snp,
+ UINT32 EnableFlags,
+ UINTN MCastAddressCount,
+ EFI_MAC_ADDRESS *MCastAddressList
+ )
+{
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
+ snp->cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_ENABLE;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
+ }
+
+ if (MCastAddressCount != 0) {
+ snp->cdb.CPBsize = (UINT16) (MCastAddressCount * sizeof (EFI_MAC_ADDRESS));
+ snp->cdb.CPBaddr = (UINT64)(UINTN) snp->cpb;
+ CopyMem (snp->cpb, MCastAddressList, snp->cdb.CPBsize);
+ }
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != EFI_SUCCESS) {
+ //
+ // UNDI command failed. Return UNDI status to caller.
+ //
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive_filters() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_INVALID_CDB:
+ case PXE_STATCODE_INVALID_CPB:
+ case PXE_STATCODE_INVALID_PARAMETER:
+ return EFI_INVALID_PARAMETER;
+
+ case PXE_STATCODE_UNSUPPORTED:
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ this routine calls undi to disable the receive filters.
+
+ @param snp pointer to snp driver structure
+ @param DisableFlags bit mask for disabling the receive filters
+ @param ResetMCastList boolean flag to reset/delete the multicast filter list
+
+
+**/
+STATIC
+EFI_STATUS
+pxe_rcvfilter_disable (
+ SNP_DRIVER *snp,
+ UINT32 DisableFlags,
+ BOOLEAN ResetMCastList
+ )
+{
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ snp->cdb.OpFlags = (UINT16) (DisableFlags ? PXE_OPFLAGS_RECEIVE_FILTER_DISABLE : PXE_OPFLAGS_NOT_USED);
+
+ if (ResetMCastList) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
+ }
+
+ if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ snp->cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
+ }
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != EFI_SUCCESS) {
+ //
+ // UNDI command failed. Return UNDI status to caller.
+ //
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive_filters() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ this routine calls undi to read the receive filters.
+
+ @param snp pointer to snp driver structure
+
+
+**/
+STATIC
+EFI_STATUS
+pxe_rcvfilter_read (
+ SNP_DRIVER *snp
+ )
+{
+ snp->cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
+ snp->cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_READ;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = (UINT16) (snp->mode.MaxMCastFilterCount * sizeof (EFI_MAC_ADDRESS));
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ if (snp->cdb.DBsize == 0) {
+ snp->cdb.DBaddr = (UINT64)(UINTN) NULL;
+ } else {
+ snp->cdb.DBaddr = (UINT64)(UINTN) snp->db;
+ ZeroMem (snp->db, snp->cdb.DBsize);
+ }
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != EFI_SUCCESS) {
+ //
+ // UNDI command failed. Return UNDI status to caller.
+ //
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.receive_filters() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Convert UNDI32 StatFlags to EFI SNP filter flags.
+ //
+ snp->mode.ReceiveFilterSetting = 0;
+
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_UNICAST) != 0) {
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
+ }
+
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST) != 0) {
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+ }
+
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS) != 0) {
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
+ }
+
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) {
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+ }
+
+ if ((snp->cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
+ snp->mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
+ }
+
+ CopyMem (snp->mode.MCastFilter, snp->db, snp->cdb.DBsize);
+
+ //
+ // Count number of active entries in multicast filter list.
+ //
+ {
+ EFI_MAC_ADDRESS ZeroMacAddr;
+
+ SetMem (&ZeroMacAddr, sizeof ZeroMacAddr, 0);
+
+ for (snp->mode.MCastFilterCount = 0;
+ snp->mode.MCastFilterCount < snp->mode.MaxMCastFilterCount;
+ snp->mode.MCastFilterCount++
+ ) {
+ if (CompareMem (
+ &snp->mode.MCastFilter[snp->mode.MCastFilterCount],
+ &ZeroMacAddr,
+ sizeof ZeroMacAddr
+ ) == 0) {
+ break;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This is the SNP interface routine for reading/enabling/disabling the
+ receive filters.
+ This routine basically retrieves snp structure, checks the SNP state and
+ checks the parameter validity, calls one of the above routines to actually
+ do the work
+
+ @param this context pointer
+ @param EnableFlags bit mask for enabling the receive filters
+ @param DisableFlags bit mask for disabling the receive filters
+ @param ResetMCastList boolean flag to reset/delete the multicast filter list
+ @param MCastAddressCount multicast address count for a new multicast address
+ list
+ @param MCastAddressList list of new multicast addresses
+
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_receive_filters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN UINT32 EnableFlags,
+ IN UINT32 DisableFlags,
+ IN BOOLEAN ResetMCastList,
+ IN UINTN MCastAddressCount OPTIONAL,
+ IN EFI_MAC_ADDRESS * MCastAddressList OPTIONAL
+ )
+{
+ SNP_DRIVER *snp;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ //
+ // check if we are asked to enable or disable something that the UNDI
+ // does not even support!
+ //
+ if (((EnableFlags &~snp->mode.ReceiveFilterMask) != 0) ||
+ ((DisableFlags &~snp->mode.ReceiveFilterMask) != 0)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if (ResetMCastList) {
+
+ DisableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & snp->mode.ReceiveFilterMask;
+ MCastAddressCount = 0;
+ MCastAddressList = NULL;
+ } else {
+ if (MCastAddressCount != 0) {
+ if ((MCastAddressCount > snp->mode.MaxMCastFilterCount) ||
+ (MCastAddressList == NULL)) {
+
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+ }
+ }
+
+ if (EnableFlags == 0 && DisableFlags == 0 && !ResetMCastList && MCastAddressCount == 0) {
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+
+ if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastAddressCount == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if ((EnableFlags != 0) || (MCastAddressCount != 0)) {
+ Status = pxe_rcvfilter_enable (
+ snp,
+ EnableFlags,
+ MCastAddressCount,
+ MCastAddressList
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ if ((DisableFlags != 0) || ResetMCastList) {
+ Status = pxe_rcvfilter_disable (snp, DisableFlags, ResetMCastList);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ Status = pxe_rcvfilter_read (snp);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/reset.c b/MdeModulePkg/Universal/Network/SnpDxe/reset.c
new file mode 100644
index 0000000000..0a08032fc4
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/reset.c
@@ -0,0 +1,128 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ reset.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-09 M(f)J Genesis.
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ This routine calls undi to reset the nic.
+
+ @param snp pointer to the snp driver structure
+
+ @return EFI_SUCCESSFUL for a successful completion
+ @return other for failed calls
+
+**/
+STATIC
+EFI_STATUS
+pxe_reset (
+ SNP_DRIVER *snp
+ )
+{
+ snp->cdb.OpCode = PXE_OPCODE_RESET;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.reset() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nsnp->undi32.reset() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ //
+ // UNDI could not be reset. Return UNDI error.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This is the SNP interface routine for resetting the NIC
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_reset routine to actually do the reset!
+
+ @param this context pointer
+ @param ExtendedVerification not implemented
+
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_reset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ SNP_DRIVER *snp;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Resolve Warning 4 unreferenced parameter problem
+ //
+ ExtendedVerification = 0;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ Status = pxe_reset (snp);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/shutdown.c b/MdeModulePkg/Universal/Network/SnpDxe/shutdown.c
new file mode 100644
index 0000000000..8e0ae45503
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/shutdown.c
@@ -0,0 +1,148 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ shutdown.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-14 M(f)J Genesis.
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ this routine calls undi to shut down the interface.
+
+ @param snp pointer to snp driver structure
+
+
+**/
+EFI_STATUS
+pxe_shutdown (
+ IN SNP_DRIVER *snp
+ )
+{
+ snp->cdb.OpCode = PXE_OPCODE_SHUTDOWN;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.shutdown() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ //
+ // UNDI could not be shutdown. Return UNDI error.
+ //
+ DEBUG ((EFI_D_WARN, "\nsnp->undi.shutdown() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Free allocated memory.
+ //
+ if (snp->tx_rx_buffer != NULL) {
+ snp->IoFncs->FreeBuffer (
+ snp->IoFncs,
+ SNP_MEM_PAGES (snp->tx_rx_bufsize),
+ (VOID *) snp->tx_rx_buffer
+ );
+ }
+
+ snp->tx_rx_buffer = NULL;
+ snp->tx_rx_bufsize = 0;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This is the SNP interface routine for shutting down the interface
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_shutdown routine to actually do the undi shutdown
+
+ @param this context pointer
+
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_shutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+{
+ SNP_DRIVER *snp;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ //
+ //
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ //
+ //
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ //
+ //
+ //
+ Status = pxe_shutdown (snp);
+
+ snp->mode.State = EfiSimpleNetworkStarted;
+ snp->mode.ReceiveFilterSetting = 0;
+
+ snp->mode.MCastFilterCount = 0;
+ snp->mode.ReceiveFilterSetting = 0;
+ ZeroMem (snp->mode.MCastFilter, sizeof snp->mode.MCastFilter);
+ CopyMem (
+ &snp->mode.CurrentAddress,
+ &snp->mode.PermanentAddress,
+ sizeof (EFI_MAC_ADDRESS)
+ );
+
+ gBS->CloseEvent (snp->snp.WaitForPacket);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/snp.c b/MdeModulePkg/Universal/Network/SnpDxe/snp.c
new file mode 100644
index 0000000000..460cdfd472
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/snp.c
@@ -0,0 +1,1269 @@
+/** @file
+Copyright (c) 2004 - 2005, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ snp.c
+
+Abstract:
+
+
+**/
+
+#include "Snp.h"
+
+EFI_STATUS
+pxe_start (
+ SNP_DRIVER *snp
+ );
+EFI_STATUS
+pxe_stop (
+ SNP_DRIVER *snp
+ );
+EFI_STATUS
+pxe_init (
+ SNP_DRIVER *snp,
+ UINT16 OpFlags
+ );
+EFI_STATUS
+pxe_shutdown (
+ SNP_DRIVER *snp
+ );
+EFI_STATUS
+pxe_get_stn_addr (
+ SNP_DRIVER *snp
+ );
+
+EFI_STATUS
+EFIAPI
+InitializeSnpNiiDriver (
+ IN EFI_HANDLE image_handle,
+ IN EFI_SYSTEM_TABLE *system_table
+ );
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// Simple Network Protocol Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL mSimpleNetworkDriverBinding = {
+ SimpleNetworkDriverSupported,
+ SimpleNetworkDriverStart,
+ SimpleNetworkDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+//
+// Module global variables needed to support undi 3.0 interface
+//
+EFI_PCI_IO_PROTOCOL *mPciIoFncs;
+struct s_v2p *_v2p = NULL; // undi3.0 map_list head
+// End Global variables
+//
+
+/**
+ This routine maps the given CPU address to a Device address. It creates a
+ an entry in the map list with the virtual and physical addresses and the
+ un map cookie.
+
+ @param v2p pointer to return a map list node pointer.
+ @param type the direction in which the data flows from the given
+ virtual address device->cpu or cpu->device or both
+ ways.
+ @param vaddr virtual address (or CPU address) to be mapped
+ @param bsize size of the buffer to be mapped.
+
+ @retval EFI_SUCEESS routine has completed the mapping
+ @retval other error as indicated.
+
+**/
+EFI_STATUS
+add_v2p (
+ IN OUT struct s_v2p **v2p,
+ EFI_PCI_IO_PROTOCOL_OPERATION type,
+ VOID *vaddr,
+ UINTN bsize
+ )
+{
+ EFI_STATUS Status;
+
+ if ((v2p == NULL) || (vaddr == NULL) || (bsize == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *v2p = AllocatePool (sizeof (struct s_v2p));
+ if (*v2p != NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = mPciIoFncs->Map (
+ mPciIoFncs,
+ type,
+ vaddr,
+ &bsize,
+ &(*v2p)->paddr,
+ &(*v2p)->unmap
+ );
+ if (Status != EFI_SUCCESS) {
+ FreePool (*v2p);
+ return Status;
+ }
+ (*v2p)->vaddr = vaddr;
+ (*v2p)->bsize = bsize;
+ (*v2p)->next = _v2p;
+ _v2p = *v2p;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This routine searches the linked list of mapped address nodes (for undi3.0
+ interface) to find the node that corresponds to the given virtual address and
+ returns a pointer to that node.
+
+ @param v2p pointer to return a map list node pointer.
+ @param vaddr virtual address (or CPU address) to be searched in
+ the map list
+
+ @retval EFI_SUCEESS if a match found!
+ @retval Other match not found
+
+**/
+EFI_STATUS
+find_v2p (
+ struct s_v2p **v2p,
+ VOID *vaddr
+ )
+{
+ struct s_v2p *v;
+
+ if (v2p == NULL || vaddr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (v = _v2p; v != NULL; v = v->next) {
+ if (v->vaddr == vaddr) {
+ *v2p = v;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This routine unmaps the given virtual address and frees the memory allocated
+ for the map list node corresponding to that address.
+
+ @param vaddr virtual address (or CPU address) to be unmapped
+
+ @retval EFI_SUCEESS if successfully unmapped
+ @retval Other as indicated by the error
+
+**/
+EFI_STATUS
+del_v2p (
+ VOID *vaddr
+ )
+{
+ struct s_v2p *v;
+ struct s_v2p *t;
+ EFI_STATUS Status;
+
+ if (vaddr == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (_v2p == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Is our node at the head of the list??
+ //
+ if ((v = _v2p)->vaddr == vaddr) {
+ _v2p = _v2p->next;
+
+ Status = mPciIoFncs->Unmap (mPciIoFncs, v->unmap);
+
+ FreePool (v);
+
+ if (Status) {
+ DEBUG ((EFI_D_ERROR, "Unmap failed with status = %x\n", Status));
+ }
+ return Status;
+ }
+
+ for (; v->next != NULL; v = t) {
+ if ((t = v->next)->vaddr == vaddr) {
+ v->next = t->next;
+ Status = mPciIoFncs->Unmap (mPciIoFncs, t->unmap);
+ FreePool (t);
+
+ if (Status) {
+ DEBUG ((EFI_D_ERROR, "Unmap failed with status = %x\n", Status));
+ }
+ return Status;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+STATIC
+EFI_STATUS
+issue_hwundi_command (
+ UINT64 cdb
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+--*/
+{
+ DEBUG ((EFI_D_ERROR, "\nissue_hwundi_command() - This should not be called!"));
+
+ if (cdb == 0) {
+ return EFI_INVALID_PARAMETER;
+
+ }
+ //
+ // %%TBD - For now, nothing is done.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Compute 8-bit checksum of a buffer.
+
+ @param ptr Pointer to buffer.
+ @param len Length of buffer in bytes.
+
+ @return 8-bit checksum of all bytes in buffer.
+ @return If ptr is NULL or len is zero, zero is returned.
+
+**/
+STATIC
+UINT8
+calc_8bit_cksum (
+ VOID *ptr,
+ UINTN len
+ )
+{
+ UINT8 *bptr;
+ UINT8 cksum;
+
+ bptr = ptr;
+ cksum = 0;
+
+ if (ptr == NULL || len == 0) {
+ return 0;
+ }
+
+ while (len--) {
+ cksum = (UINT8) (cksum +*bptr++);
+ }
+
+ return cksum;
+}
+
+
+/**
+ Test to see if this driver supports Controller. Any Controller
+ that contains a Nii protocol can be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
+ PXE_UNDI *pxe;
+ BOOLEAN IsUndi31;
+
+ IsUndi31 = FALSE;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ (VOID **) &NiiProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED)
+ {
+ DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %x\n", Controller));
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (!EFI_ERROR (Status))
+ {
+ DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %x\n", Controller));
+ IsUndi31 = TRUE;
+ } else {
+ //
+ // try the older 3.0 driver
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ (VOID **) &NiiProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "Support(): UNDI3.0 found on handle %x\n", Controller));
+ }
+ //
+ // check the version, we don't want to connect to the undi16
+ //
+ if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ //
+ // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.
+ //
+ if (NiiProtocol->ID & 0x0F) {
+ DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->ID);
+
+ //
+ // Verify !PXE revisions.
+ //
+ if (pxe->hw.Signature != PXE_ROMID_SIGNATURE) {
+ DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (pxe->hw.Rev < PXE_ROMID_REV) {
+ DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {
+
+ DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+
+ } else if (pxe->hw.MajorVer == PXE_ROMID_MAJORVER && pxe->hw.MinorVer < PXE_ROMID_MINORVER) {
+ DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ //
+ // Do S/W UNDI specific checks.
+ //
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {
+ if (pxe->sw.EntryPoint < pxe->sw.Len) {
+ DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (pxe->sw.BusCnt == 0) {
+ DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ }
+
+ Status = EFI_SUCCESS;
+ DEBUG ((EFI_D_INFO, "Support(): supported on %x\n", Controller));
+
+Done:
+ if (IsUndi31) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ } else {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ return Status;
+}
+
+
+/**
+ called for any handle that we said "supported" in the above call!
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to start
+ @param RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval other This driver failed to start this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;
+ EFI_DEVICE_PATH_PROTOCOL *NiiDevicePath;
+ EFI_STATUS Status;
+ PXE_UNDI *pxe;
+ SNP_DRIVER *snp;
+ VOID *addr;
+ VOID *addrUnmap;
+ EFI_PHYSICAL_ADDRESS paddr;
+ EFI_HANDLE Handle;
+ UINTN Size;
+ BOOLEAN UndiNew;
+ PXE_PCI_CONFIG_INFO ConfigInfo;
+ PCI_TYPE00 *ConfigHeader;
+ UINT32 *TempBar;
+ UINT8 BarIndex;
+ PXE_STATFLAGS InitStatFlags;
+
+ DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() "));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &NiiDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->LocateDevicePath (
+ &gEfiPciIoProtocolGuid,
+ &NiiDevicePath,
+ &Handle
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &mPciIoFncs,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the NII interface. look for 3.1 undi first, if it is not there
+ // then look for 3.0, validate the interface.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ (VOID **) &Nii,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // probably not a 3.1 UNDI
+ //
+ UndiNew = TRUE;
+ DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));
+
+ } else {
+ UndiNew = FALSE;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ (VOID **) &Nii,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "Start(): UNDI3.0 found\n"));
+ }
+
+ pxe = (PXE_UNDI *) (UINTN) (Nii->ID);
+
+ if (calc_8bit_cksum (pxe, pxe->hw.Len) != 0) {
+ DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));
+ goto NiiError;
+ }
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
+ //
+ // We can get any packets.
+ //
+ } else if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
+ //
+ // We need to be able to get broadcast packets for DHCP.
+ // If we do not have promiscuous support, we must at least have
+ // broadcast support or we cannot do DHCP!
+ //
+ } else {
+ DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));
+ goto NiiError;
+ }
+ //
+ // OK, we like this UNDI, and we know snp is not already there on this handle
+ // Allocate and initialize a new simple network protocol structure.
+ //
+ Status = mPciIoFncs->AllocateBuffer (
+ mPciIoFncs,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
+ &addr,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));
+ goto NiiError;
+ }
+
+ snp = (SNP_DRIVER *) (UINTN) addr;
+
+ if (!UndiNew) {
+ Size = SNP_MEM_PAGES (sizeof (SNP_DRIVER));
+
+ Status = mPciIoFncs->Map (
+ mPciIoFncs,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ addr,
+ &Size,
+ &paddr,
+ &addrUnmap
+ );
+
+ ASSERT (paddr);
+
+ DEBUG ((EFI_D_NET, "\nSNP_DRIVER @ %Xh, sizeof(SNP_DRIVER) == %d", addr, sizeof (SNP_DRIVER)));
+ snp = (SNP_DRIVER *) (UINTN) paddr;
+ snp->SnpDriverUnmap = addrUnmap;
+ }
+
+ ZeroMem (snp, sizeof (SNP_DRIVER));
+
+ snp->IoFncs = mPciIoFncs;
+ snp->IsOldUndi = (BOOLEAN) (!UndiNew);
+
+ snp->Signature = SNP_DRIVER_SIGNATURE;
+
+ EfiInitializeLock (&snp->lock, TPL_NOTIFY);
+
+ snp->snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
+ snp->snp.Start = snp_undi32_start;
+ snp->snp.Stop = snp_undi32_stop;
+ snp->snp.Initialize = snp_undi32_initialize;
+ snp->snp.Reset = snp_undi32_reset;
+ snp->snp.Shutdown = snp_undi32_shutdown;
+ snp->snp.ReceiveFilters = snp_undi32_receive_filters;
+ snp->snp.StationAddress = snp_undi32_station_address;
+ snp->snp.Statistics = snp_undi32_statistics;
+ snp->snp.MCastIpToMac = snp_undi32_mcast_ip_to_mac;
+ snp->snp.NvData = snp_undi32_nvdata;
+ snp->snp.GetStatus = snp_undi32_get_status;
+ snp->snp.Transmit = snp_undi32_transmit;
+ snp->snp.Receive = snp_undi32_receive;
+ snp->snp.WaitForPacket = NULL;
+
+ snp->snp.Mode = &snp->mode;
+
+ snp->tx_rx_bufsize = 0;
+ snp->tx_rx_buffer = NULL;
+
+ snp->if_num = Nii->IfNum;
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {
+ snp->is_swundi = FALSE;
+ snp->issue_undi32_command = &issue_hwundi_command;
+ } else {
+ snp->is_swundi = TRUE;
+
+ if ((pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {
+ snp->issue_undi32_command = (issue_undi32_command) (UINTN) pxe->sw.EntryPoint;
+ } else {
+ snp->issue_undi32_command = (issue_undi32_command) (UINTN) ((UINT8) (UINTN) pxe + pxe->sw.EntryPoint);
+ }
+ }
+ //
+ // Allocate a global CPB and DB buffer for this UNDI interface.
+ // we do this because:
+ //
+ // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be
+ // within 2GB limit, create them here and map them so that when undi calls
+ // v2p callback to check if the physical address is < 2gb, we will pass.
+ //
+ // -This is not a requirement for 3.1 or later UNDIs but the code looks
+ // simpler if we use the same cpb, db variables for both old and new undi
+ // interfaces from all the SNP interface calls (we don't map the buffers
+ // for the newer undi interfaces though)
+ // .
+ // -it is OK to allocate one global set of CPB, DB pair for each UNDI
+ // interface as EFI does not multi-task and so SNP will not be re-entered!
+ //
+ Status = mPciIoFncs->AllocateBuffer (
+ mPciIoFncs,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ SNP_MEM_PAGES (4096),
+ &addr,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));
+ goto Error_DeleteSNP;
+ }
+
+ if (snp->IsOldUndi) {
+ Size = SNP_MEM_PAGES (4096);
+
+ Status = mPciIoFncs->Map (
+ mPciIoFncs,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ addr,
+ &Size,
+ &paddr,
+ &snp->CpbUnmap
+ );
+
+ ASSERT (paddr);
+
+ snp->cpb = (VOID *) (UINTN) paddr;
+ snp->db = (VOID *) ((UINTN) paddr + 2048);
+ } else {
+ snp->cpb = (VOID *) (UINTN) addr;
+ snp->db = (VOID *) ((UINTN) addr + 2048);
+ }
+ //
+ // pxe_start call is going to give the callback functions to UNDI, these callback
+ // functions use the BarIndex values from the snp structure, so these must be initialized
+ // with default values before doing a pxe_start. The correct values can be obtained after
+ // getting the config information from UNDI
+ //
+ snp->MemoryBarIndex = 0;
+ snp->IoBarIndex = 1;
+
+ //
+ // we need the undi init information many times in this snp code, just get it
+ // once here and store it in the snp driver structure. to get Init Info
+ // from UNDI we have to start undi first.
+ //
+ Status = pxe_start (snp);
+
+ if (Status != EFI_SUCCESS) {
+ goto Error_DeleteCPBDB;
+ }
+
+ snp->cdb.OpCode = PXE_OPCODE_GET_INIT_INFO;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_DBADDR_NOT_USED;
+
+ snp->cdb.DBsize = sizeof snp->init_info;
+ snp->cdb.DBaddr = (UINT64)(UINTN) &snp->init_info;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ DEBUG ((EFI_D_NET, "\nsnp->undi.get_init_info() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ //
+ // Save the INIT Stat Code...
+ //
+ InitStatFlags = snp->cdb.StatFlags;
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG ((EFI_D_NET, "\nsnp->undi.init_info() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));
+ pxe_stop (snp);
+ goto Error_DeleteCPBDB;
+ }
+
+ snp->cdb.OpCode = PXE_OPCODE_GET_CONFIG_INFO;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_DBADDR_NOT_USED;
+
+ snp->cdb.DBsize = sizeof ConfigInfo;
+ snp->cdb.DBaddr = (UINT64)(UINTN) &ConfigInfo;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ DEBUG ((EFI_D_NET, "\nsnp->undi.get_config_info() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG ((EFI_D_NET, "\nsnp->undi.config_info() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));
+ pxe_stop (snp);
+ goto Error_DeleteCPBDB;
+ }
+ //
+ // Find the correct BAR to do IO.
+ //
+ //
+ // Enumerate through the PCI BARs for the device to determine which one is
+ // the IO BAR. Save the index of the BAR into the adapter info structure.
+ // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped
+ //
+ ConfigHeader = (PCI_TYPE00 *) &ConfigInfo.Config.Byte[0];
+ TempBar = (UINT32 *) &ConfigHeader->Device.Bar[0];
+ for (BarIndex = 0; BarIndex <= 5; BarIndex++) {
+ if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {
+ //
+ // This is a 64-bit memory bar, skip this and the
+ // next bar as well.
+ //
+ TempBar++;
+ }
+
+ if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {
+ snp->IoBarIndex = BarIndex;
+ break;
+ }
+
+ TempBar++;
+ }
+
+ //
+ // We allocate 2 more global buffers for undi 3.0 interface. We use these
+ // buffers to pass to undi when the user buffers are beyond 4GB.
+ // UNDI 3.0 wants all the addresses passed to it to be
+ // within 2GB limit, create them here and map them so that when undi calls
+ // v2p callback to check if the physical address is < 2gb, we will pass.
+ //
+ // For 3.1 and later UNDIs, we do not do this because undi is
+ // going to call the map() callback if and only if it wants to use the
+ // device address for any address it receives.
+ //
+ if (snp->IsOldUndi) {
+ //
+ // buffer for receive
+ //
+ Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);
+ Status = mPciIoFncs->AllocateBuffer (
+ mPciIoFncs,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Size,
+ &addr,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "\nCould not allocate receive buffer.\n"));
+ goto Error_DeleteCPBDB;
+ }
+
+ Status = mPciIoFncs->Map (
+ mPciIoFncs,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ addr,
+ &Size,
+ &paddr,
+ &snp->ReceiveBufUnmap
+ );
+
+ ASSERT (paddr);
+
+ snp->receive_buf = (UINT8 *) (UINTN) paddr;
+
+ //
+ // buffer for fill_header
+ //
+ Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen);
+ Status = mPciIoFncs->AllocateBuffer (
+ mPciIoFncs,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Size,
+ &addr,
+ 0
+ );
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "\nCould not allocate fill_header buffer.\n"));
+ goto Error_DeleteRCVBuf;
+ }
+
+ Status = mPciIoFncs->Map (
+ mPciIoFncs,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ addr,
+ &Size,
+ &paddr,
+ &snp->FillHdrBufUnmap
+ );
+
+ ASSERT (paddr);
+ snp->fill_hdr_buf = (UINT8 *) (UINTN) paddr;
+ }
+ //
+ // Initialize simple network protocol mode structure
+ //
+ snp->mode.State = EfiSimpleNetworkStopped;
+ snp->mode.HwAddressSize = snp->init_info.HWaddrLen;
+ snp->mode.MediaHeaderSize = snp->init_info.MediaHeaderLen;
+ snp->mode.MaxPacketSize = snp->init_info.FrameDataLen;
+ snp->mode.NvRamAccessSize = snp->init_info.NvWidth;
+ snp->mode.NvRamSize = snp->init_info.NvCount * snp->mode.NvRamAccessSize;
+ snp->mode.IfType = snp->init_info.IFtype;
+ snp->mode.MaxMCastFilterCount = snp->init_info.MCastFilterCnt;
+ snp->mode.MCastFilterCount = 0;
+
+ switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {
+ case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:
+ snp->mode.MediaPresentSupported = TRUE;
+ break;
+
+ case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:
+ default:
+ snp->mode.MediaPresentSupported = FALSE;
+ }
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {
+ snp->mode.MacAddressChangeable = TRUE;
+ } else {
+ snp->mode.MacAddressChangeable = FALSE;
+ }
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {
+ snp->mode.MultipleTxSupported = TRUE;
+ } else {
+ snp->mode.MultipleTxSupported = FALSE;
+ }
+
+ snp->mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+
+ }
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
+
+ }
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+
+ }
+
+ if ((pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
+
+ }
+
+ if (pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) {
+ snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+
+ }
+
+ snp->mode.ReceiveFilterSetting = 0;
+
+ //
+ // need to get the station address to save in the mode structure. we need to
+ // initialize the UNDI first for this.
+ //
+ snp->tx_rx_bufsize = snp->init_info.MemoryRequired;
+ Status = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
+
+ if (Status) {
+ pxe_stop (snp);
+ goto Error_DeleteHdrBuf;
+ }
+
+ Status = pxe_get_stn_addr (snp);
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "\nsnp->undi.get_station_addr() failed.\n"));
+ pxe_shutdown (snp);
+ pxe_stop (snp);
+ goto Error_DeleteHdrBuf;
+ }
+
+ snp->mode.MediaPresent = FALSE;
+
+ //
+ // We should not leave UNDI started and initialized here. this DriverStart()
+ // routine must only find and attach the SNP interface to UNDI layer that it
+ // finds on the given handle!
+ // The UNDI layer will be started when upper layers call snp->start.
+ // How ever, this DriverStart() must fill up the snp mode structure which
+ // contains the MAC address of the NIC. For this reason we started and
+ // initialized UNDI here, now we are done, do a shutdown and stop of the
+ // UNDI interface!
+ //
+ pxe_shutdown (snp);
+ pxe_stop (snp);
+
+ //
+ // add SNP to the undi handle
+ //
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &(snp->snp)
+ );
+
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+
+Error_DeleteHdrBuf:
+ if (snp->IsOldUndi) {
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ snp->FillHdrBufUnmap
+ );
+ Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen);
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ Size,
+ snp->fill_hdr_buf
+ );
+ }
+
+Error_DeleteRCVBuf:
+ if (snp->IsOldUndi) {
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ snp->ReceiveBufUnmap
+ );
+ Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ Size,
+ snp->receive_buf
+ );
+
+ }
+
+Error_DeleteCPBDB:
+ if (snp->IsOldUndi) {
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ snp->CpbUnmap
+ );
+ }
+
+ Status = mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ SNP_MEM_PAGES (4096),
+ snp->cpb
+ );
+
+Error_DeleteSNP:
+ if (snp->IsOldUndi) {
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ snp->SnpDriverUnmap
+ );
+ }
+
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
+ snp
+ );
+NiiError:
+ if (!UndiNew) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ } else {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+
+
+
+**/
+EFI_STATUS
+EFIAPI
+SimpleNetworkDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;
+ SNP_DRIVER *Snp;
+
+ //
+ // Get our context back.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ (VOID **) &SnpProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiSimpleNetworkProtocolGuid,
+ &Snp->snp
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!Snp->IsOldUndi) {
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ This->DriverBindingHandle,
+ Controller
+ );
+ } else {
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ pxe_shutdown (Snp);
+ pxe_stop (Snp);
+
+ if (Snp->IsOldUndi) {
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ Snp->FillHdrBufUnmap
+ );
+
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ SNP_MEM_PAGES (Snp->init_info.MediaHeaderLen),
+ Snp->fill_hdr_buf
+ );
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ Snp->ReceiveBufUnmap
+ );
+
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ SNP_MEM_PAGES (Snp->init_info.MediaHeaderLen + Snp->init_info.FrameDataLen),
+ Snp->receive_buf
+ );
+
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ Snp->CpbUnmap
+ );
+ Status = mPciIoFncs->Unmap (
+ mPciIoFncs,
+ Snp->SnpDriverUnmap
+ );
+ }
+
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ SNP_MEM_PAGES (4096),
+ Snp->cpb
+ );
+
+ mPciIoFncs->FreeBuffer (
+ mPciIoFncs,
+ SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
+ Snp
+ );
+
+ return Status;
+}
+
+
+/**
+ Install all the driver protocol
+
+ @param entry EFI_IMAGE_ENTRY_POINT)
+
+ @retval EFI_SUCEESS Initialization routine has found UNDI hardware,
+ loaded it's ROM, and installed a notify event for
+ the Network Indentifier Interface Protocol
+ successfully.
+ @retval Other Return value from HandleProtocol for
+ DeviceIoProtocol or LoadedImageProtocol
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSnpNiiDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallAllDriverProtocols (
+ ImageHandle,
+ SystemTable,
+ &mSimpleNetworkDriverBinding,
+ NULL,
+ COMPONENT_NAME,
+ NULL,
+ NULL
+ );
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/snp.h b/MdeModulePkg/Universal/Network/SnpDxe/snp.h
new file mode 100644
index 0000000000..624a44c971
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/snp.h
@@ -0,0 +1,454 @@
+/** @file
+
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ snp.h
+
+Abstract:
+
+Revision history:
+
+
+**/
+#ifndef _SNP_H
+#define _SNP_H
+
+
+#include <PiDxe.h>
+
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/NetworkInterfaceIdentifier.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <IndustryStandard/Pci22.h>
+
+#define FOUR_GIGABYTES (UINT64) 0x100000000ULL
+
+//
+// Driver Consumed Protocol Prototypes
+//
+//@MT:#include EFI_PROTOCOL_DEFINITION (DevicePath)
+//@MT:#include EFI_PROTOCOL_DEFINITION (PciIo)
+//@MT:#include EFI_PROTOCOL_DEFINITION (EfiNetworkInterfaceIdentifier)
+
+//
+// Driver Produced Protocol Prototypes
+//
+//@MT:#include EFI_PROTOCOL_DEFINITION (DriverBinding)
+//@MT:#include EFI_PROTOCOL_DEFINITION (ComponentName)
+//@MT:#include EFI_PROTOCOL_DEFINITION (ComponentName2)
+//@MT:#include EFI_PROTOCOL_DEFINITION (SimpleNetwork)
+
+#define SNP_DRIVER_SIGNATURE EFI_SIGNATURE_32 ('s', 'n', 'd', 's')
+#define MAX_MAP_LENGTH 100
+
+#define PCI_BAR_IO_MASK 0x00000003
+#define PCI_BAR_IO_MODE 0x00000001
+
+#define PCI_BAR_MEM_MASK 0x0000000F
+#define PCI_BAR_MEM_MODE 0x00000000
+#define PCI_BAR_MEM_64BIT 0x00000004
+
+typedef struct {
+ UINT32 Signature;
+ EFI_LOCK lock;
+
+ EFI_SIMPLE_NETWORK_PROTOCOL snp;
+ EFI_SIMPLE_NETWORK_MODE mode;
+
+ EFI_HANDLE device_handle;
+ EFI_DEVICE_PATH_PROTOCOL *device_path;
+
+ //
+ // Local instance data needed by SNP driver
+ //
+ // Pointer to S/W UNDI API entry point
+ // This will be NULL for H/W UNDI
+ //
+ EFI_STATUS (*issue_undi32_command) (UINT64 cdb);
+
+ BOOLEAN is_swundi;
+
+ //
+ // undi interface number, if one undi manages more nics
+ //
+ PXE_IFNUM if_num;
+
+ //
+ // Allocated tx/rx buffer that was passed to UNDI Initialize.
+ //
+ UINT32 tx_rx_bufsize;
+ VOID *tx_rx_buffer;
+ //
+ // mappable buffers for receive and fill header for undi3.0
+ // these will be used if the user buffers are above 4GB limit (instead of
+ // mapping the user buffers)
+ //
+ UINT8 *receive_buf;
+ VOID *ReceiveBufUnmap;
+ UINT8 *fill_hdr_buf;
+ VOID *FillHdrBufUnmap;
+
+ EFI_PCI_IO_PROTOCOL *IoFncs;
+ UINT8 IoBarIndex;
+ UINT8 MemoryBarIndex;
+ BOOLEAN IsOldUndi; // true for EFI1.0 UNDI (3.0) drivers
+ //
+ // Buffers for command descriptor block, command parameter block
+ // and data block.
+ //
+ PXE_CDB cdb;
+ VOID *cpb;
+ VOID *CpbUnmap;
+ VOID *db;
+
+ //
+ // UNDI structure, we need to remember the init info for a long time!
+ //
+ PXE_DB_GET_INIT_INFO init_info;
+
+ VOID *SnpDriverUnmap;
+ //
+ // when ever we map an address, we must remember it's address and the un-map
+ // cookie so that we can unmap later
+ //
+ struct s_map_list {
+ EFI_PHYSICAL_ADDRESS virt;
+ VOID *map_cookie;
+ } map_list[MAX_MAP_LENGTH];
+}
+SNP_DRIVER;
+
+#define EFI_SIMPLE_NETWORK_DEV_FROM_THIS(a) CR (a, SNP_DRIVER, snp, SNP_DRIVER_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_COMPONENT_NAME_PROTOCOL gSimpleNetworkComponentName;
+
+//
+// Virtual to physical mapping for all UNDI 3.0s.
+//
+extern struct s_v2p {
+ struct s_v2p *next;
+ VOID *vaddr;
+ UINTN bsize;
+ EFI_PHYSICAL_ADDRESS paddr;
+ VOID *unmap;
+}
+*_v2p;
+
+EFI_STATUS
+add_v2p (
+ struct s_v2p **v2p,
+ EFI_PCI_IO_PROTOCOL_OPERATION type,
+ VOID *vaddr,
+ UINTN bsize
+ )
+;
+
+EFI_STATUS
+find_v2p (
+ struct s_v2p **v2p,
+ VOID *vaddr
+ )
+;
+
+EFI_STATUS
+del_v2p (
+ VOID *vaddr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_block_30 (
+ IN UINT32 Enable
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_delay_30 (
+ IN UINT64 MicroSeconds
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_memio_30 (
+ IN UINT8 ReadOrWrite,
+ IN UINT8 NumBytes,
+ IN UINT64 MemOrPortAddress,
+ IN OUT UINT64 BufferPtr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_v2p_30 (
+ IN UINT64 CpuAddr,
+ IN OUT UINT64 DeviceAddrPtr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_block (
+ IN UINT64 UniqueId,
+ IN UINT32 Enable
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_delay (
+ IN UINT64 UniqueId,
+ IN UINT64 MicroSeconds
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_memio (
+ IN UINT64 UniqueId,
+ IN UINT8 ReadOrWrite,
+ IN UINT8 NumBytes,
+ IN UINT64 MemOrPortAddr,
+ IN OUT UINT64 BufferPtr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_map (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN OUT UINT64 DeviceAddrPtr
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_unmap (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN UINT64 DeviceAddr // not a pointer to device address
+ )
+;
+
+extern
+VOID
+snp_undi32_callback_sync (
+ IN UINT64 UniqueId,
+ IN UINT64 CpuAddr,
+ IN UINT32 NumBytes,
+ IN UINT32 Direction,
+ IN UINT64 DeviceAddr // not a pointer to device address
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_start (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_stop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_initialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN UINTN extra_rx_buffer_size OPTIONAL,
+ IN UINTN extra_tx_buffer_size OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_reset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN ExtendedVerification
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_shutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_receive_filters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN UINT32 enable,
+ IN UINT32 disable,
+ IN BOOLEAN reset_mcast_filter,
+ IN UINTN mcast_filter_count OPTIONAL,
+ IN EFI_MAC_ADDRESS * mcast_filter OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_station_address (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN BOOLEAN reset,
+ IN EFI_MAC_ADDRESS *new OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_statistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN BOOLEAN reset,
+ IN OUT UINTN *statistics_size OPTIONAL,
+ IN OUT EFI_NETWORK_STATISTICS * statistics_table OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_mcast_ip_to_mac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_nvdata (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this,
+ IN BOOLEAN read_write,
+ IN UINTN offset,
+ IN UINTN buffer_size,
+ IN OUT VOID *buffer
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_get_status (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ OUT UINT32 *interrupt_status OPTIONAL,
+ OUT VOID **tx_buffer OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_transmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN UINTN header_size,
+ IN UINTN buffer_size,
+ IN VOID *buffer,
+ IN EFI_MAC_ADDRESS * src_addr OPTIONAL,
+ IN EFI_MAC_ADDRESS * dest_addr OPTIONAL,
+ IN UINT16 *protocol OPTIONAL
+ )
+;
+
+extern
+EFI_STATUS
+EFIAPI
+snp_undi32_receive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ OUT UINTN *header_size OPTIONAL,
+ IN OUT UINTN *buffer_size,
+ OUT VOID *buffer,
+ OUT EFI_MAC_ADDRESS * src_addr OPTIONAL,
+ OUT EFI_MAC_ADDRESS * dest_addr OPTIONAL,
+ OUT UINT16 *protocol OPTIONAL
+ )
+;
+
+typedef
+EFI_STATUS
+(*issue_undi32_command) (
+ UINT64 cdb
+ );
+typedef
+VOID
+(*ptr) (
+ VOID
+ );
+
+
+/**
+ Install all the driver protocol
+
+ @param ImageHandle Driver image handle
+ @param SystemTable System services table
+
+ @retval EFI_SUCEESS Initialization routine has found UNDI hardware, loaded it's
+ ROM, and installed a notify event for the Network
+ Indentifier Interface Protocol successfully.
+ @retval Other Return value from HandleProtocol for DeviceIoProtocol or
+ LoadedImageProtocol
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSnpNiiDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+;
+
+#ifdef EFI_SIZE_REDUCTION_APPLIED
+ #define COMPONENT_NAME_CODE(code)
+ #define COMPONENT_NAME NULL
+#else
+ #define COMPONENT_NAME_CODE(code) code
+ #define COMPONENT_NAME &gSimpleNetworkComponentName
+#endif
+
+#define SNP_MEM_PAGES(x) (((x) - 1) / 4096 + 1)
+
+
+#endif /* _SNP_H */
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/start.c b/MdeModulePkg/Universal/Network/SnpDxe/start.c
new file mode 100644
index 0000000000..0a43f8e60c
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/start.c
@@ -0,0 +1,191 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ start.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-07 M(f)J Genesis.
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ this routine calls undi to start the interface and changes the snp state!
+
+ @param snp pointer to snp driver structure
+
+
+**/
+EFI_STATUS
+pxe_start (
+ SNP_DRIVER *snp
+ )
+{
+ PXE_CPB_START_30 *cpb;
+ PXE_CPB_START_31 *cpb_31;
+
+ cpb = snp->cpb;
+ cpb_31 = snp->cpb;
+ //
+ // Initialize UNDI Start CDB for H/W UNDI
+ //
+ snp->cdb.OpCode = PXE_OPCODE_START;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Make changes to H/W UNDI Start CDB if this is
+ // a S/W UNDI.
+ //
+ if (snp->is_swundi) {
+ if (snp->IsOldUndi) {
+ snp->cdb.CPBsize = sizeof (PXE_CPB_START_30);
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;
+
+ cpb->Delay = (UINT64)(UINTN) &snp_undi32_callback_delay_30;
+ cpb->Block = (UINT64)(UINTN) &snp_undi32_callback_block_30;
+
+ //
+ // Virtual == Physical. This can be set to zero.
+ //
+ cpb->Virt2Phys = (UINT64)(UINTN) &snp_undi32_callback_v2p_30;
+ cpb->Mem_IO = (UINT64)(UINTN) &snp_undi32_callback_memio_30;
+ } else {
+ snp->cdb.CPBsize = sizeof (PXE_CPB_START_31);
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb_31;
+
+ cpb_31->Delay = (UINT64)(UINTN) &snp_undi32_callback_delay;
+ cpb_31->Block = (UINT64)(UINTN) &snp_undi32_callback_block;
+
+ //
+ // Virtual == Physical. This can be set to zero.
+ //
+ cpb_31->Virt2Phys = (UINT64)(UINTN) 0;
+ cpb_31->Mem_IO = (UINT64)(UINTN) &snp_undi32_callback_memio;
+
+ cpb_31->Map_Mem = (UINT64)(UINTN) &snp_undi32_callback_map;
+ cpb_31->UnMap_Mem = (UINT64)(UINTN) &snp_undi32_callback_unmap;
+ cpb_31->Sync_Mem = (UINT64)(UINTN) &snp_undi32_callback_sync;
+
+ cpb_31->Unique_ID = (UINT64)(UINTN) snp;
+ }
+ }
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.start() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ //
+ // UNDI could not be started. Return UNDI error.
+ //
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.start() %xh:%xh\n",
+ snp->cdb.StatCode,
+ snp->cdb.StatFlags)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set simple network state to Started and return success.
+ //
+ snp->mode.State = EfiSimpleNetworkStarted;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This is the SNP interface routine for starting the interface
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_start routine to actually do start undi interface
+
+ @param This context pointer
+
+ @retval EFI_INVALID_PARAMETER "This" is Null
+ @retval No SNP driver can be extracted from "This"
+ @retval EFI_ALREADY_STARTED The state of SNP is EfiSimpleNetworkStarted or
+ EfiSimpleNetworkInitialized
+ @retval EFI_DEVICE_ERROR The state of SNP is other than
+ EfiSimpleNetworkStarted,
+ EfiSimpleNetworkInitialized, and
+ EfiSimpleNetworkStopped
+ @retval EFI_SUCCESS UNDI interface is succesfully started
+ @retval Other Error occurs while calling pxe_start function.
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_start (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ SNP_DRIVER *Snp;
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ switch (Snp->mode.State) {
+ case EfiSimpleNetworkStopped:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ case EfiSimpleNetworkInitialized:
+ Status = EFI_ALREADY_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ Status = pxe_start (Snp);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ //
+ // clear the map_list in SNP structure
+ //
+ for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
+ Snp->map_list[Index].virt = 0;
+ Snp->map_list[Index].map_cookie = 0;
+ }
+
+ Snp->mode.MCastFilterCount = 0;
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/station_address.c b/MdeModulePkg/Universal/Network/SnpDxe/station_address.c
new file mode 100644
index 0000000000..b6e0728d71
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/station_address.c
@@ -0,0 +1,237 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ station_address.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-17 M(f)J Genesis.
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ this routine calls undi to read the MAC address of the NIC and updates the
+ mode structure with the address.
+
+ @param snp pointer to snp driver structure
+
+
+**/
+EFI_STATUS
+pxe_get_stn_addr (
+ SNP_DRIVER *snp
+ )
+{
+ PXE_DB_STATION_ADDRESS *db;
+
+ db = snp->db;
+ snp->cdb.OpCode = PXE_OPCODE_STATION_ADDRESS;
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_READ;
+
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+
+ snp->cdb.DBsize = sizeof (PXE_DB_STATION_ADDRESS);
+ snp->cdb.DBaddr = (UINT64)(UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.station_addr() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set new station address in SNP->Mode structure and return success.
+ //
+ CopyMem (
+ &(snp->mode.CurrentAddress),
+ &db->StationAddr,
+ snp->mode.HwAddressSize
+ );
+
+ CopyMem (
+ &snp->mode.BroadcastAddress,
+ &db->BroadcastAddr,
+ snp->mode.HwAddressSize
+ );
+
+ CopyMem (
+ &snp->mode.PermanentAddress,
+ &db->PermanentAddr,
+ snp->mode.HwAddressSize
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ this routine calls undi to set a new MAC address for the NIC,
+
+ @param snp pointer to snp driver structure
+ @param NewMacAddr pointer to a mac address to be set for the nic, if this is
+ NULL then this routine resets the mac address to the NIC's
+ original address.
+
+
+**/
+STATIC
+EFI_STATUS
+pxe_set_stn_addr (
+ SNP_DRIVER *snp,
+ EFI_MAC_ADDRESS *NewMacAddr
+ )
+{
+ PXE_CPB_STATION_ADDRESS *cpb;
+ PXE_DB_STATION_ADDRESS *db;
+
+ cpb = snp->cpb;
+ db = snp->db;
+ snp->cdb.OpCode = PXE_OPCODE_STATION_ADDRESS;
+
+ if (NewMacAddr == NULL) {
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_RESET;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ } else {
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_READ;
+ //
+ // even though the OPFLAGS are set to READ, supplying a new address
+ // in the CPB will make undi change the mac address to the new one.
+ //
+ CopyMem (&cpb->StationAddr, NewMacAddr, snp->mode.HwAddressSize);
+
+ snp->cdb.CPBsize = sizeof (PXE_CPB_STATION_ADDRESS);
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;
+ }
+
+ snp->cdb.DBsize = sizeof (PXE_DB_STATION_ADDRESS);
+ snp->cdb.DBaddr = (UINT64)(UINTN) db;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.station_addr() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ //
+ // UNDI command failed. Return UNDI status to caller.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // read the changed address and save it in SNP->Mode structure
+ //
+ pxe_get_stn_addr (snp);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This is the SNP interface routine for changing the NIC's mac address.
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the above routines to actually do the work
+
+ @param this context pointer
+ @param NewMacAddr pointer to a mac address to be set for the nic, if this is
+ NULL then this routine resets the mac address to the NIC's
+ original address.
+ @param ResetFlag If true, the mac address will change to NIC's original
+ address
+
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_station_address (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN BOOLEAN ResetFlag,
+ IN EFI_MAC_ADDRESS * NewMacAddr OPTIONAL
+ )
+{
+ SNP_DRIVER *snp;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ // Check for invalid parameter combinations.
+ //
+ if ((this == NULL) ||
+ (!ResetFlag && (NewMacAddr == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Return error if the SNP is not initialized.
+ //
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ if (ResetFlag) {
+ Status = pxe_set_stn_addr (snp, NULL);
+ } else {
+ Status = pxe_set_stn_addr (snp, NewMacAddr);
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/statistics.c b/MdeModulePkg/Universal/Network/SnpDxe/statistics.c
new file mode 100644
index 0000000000..19f28239a5
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/statistics.c
@@ -0,0 +1,201 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ statistics.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-17 M(f)J Genesis.
+
+**/
+
+
+#include "Snp.h"
+
+
+/**
+ This is the SNP interface routine for getting the NIC's statistics.
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_ routine to actually do the
+
+ @param this context pointer
+ @param ResetFlag true to reset the NIC's statistics counters to zero.
+ @param StatTableSizePtr pointer to the statistics table size
+ @param StatTablePtr pointer to the statistics table
+
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_statistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN BOOLEAN ResetFlag,
+ IN OUT UINTN *StatTableSizePtr OPTIONAL,
+ IN OUT EFI_NETWORK_STATISTICS * StatTablePtr OPTIONAL
+ )
+{
+ SNP_DRIVER *snp;
+ PXE_DB_STATISTICS *db;
+ UINT64 *stp;
+ UINT64 mask;
+ UINTN size;
+ UINTN n;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Get pointer to SNP driver instance for *this.
+ //
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Return error if the SNP is not initialized.
+ //
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+ //
+ // if we are not resetting the counters, we have to have a valid stat table
+ // with >0 size. if no reset, no table and no size, return success.
+ //
+ if (!ResetFlag && StatTableSizePtr == NULL) {
+ Status = StatTablePtr ? EFI_INVALID_PARAMETER : EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+ //
+ // Initialize UNDI Statistics CDB
+ //
+ snp->cdb.OpCode = PXE_OPCODE_STATISTICS;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ if (ResetFlag) {
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATISTICS_RESET;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ db = snp->db;
+ } else {
+ snp->cdb.OpFlags = PXE_OPFLAGS_STATISTICS_READ;
+ snp->cdb.DBsize = sizeof (PXE_DB_STATISTICS);
+ snp->cdb.DBaddr = (UINT64)(UINTN) (db = snp->db);
+ }
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.statistics() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ break;
+
+ case PXE_STATCODE_UNSUPPORTED:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.statistics() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ Status = EFI_UNSUPPORTED;
+ goto ON_EXIT;
+
+ default:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.statistics() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ if (ResetFlag) {
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+
+ if (StatTablePtr == NULL) {
+ *StatTableSizePtr = sizeof (EFI_NETWORK_STATISTICS);
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto ON_EXIT;
+ }
+ //
+ // Convert the UNDI statistics information to SNP statistics
+ // information.
+ //
+ ZeroMem (StatTablePtr, *StatTableSizePtr);
+ stp = (UINT64 *) StatTablePtr;
+ size = 0;
+
+ for (n = 0, mask = 1; n < 64; n++, mask = LShiftU64 (mask, 1), stp++) {
+ //
+ // There must be room for a full UINT64. Partial
+ // numbers will not be stored.
+ //
+ if ((n + 1) * sizeof (UINT64) > *StatTableSizePtr) {
+ break;
+ }
+
+ if (db->Supported & mask) {
+ *stp = db->Data[n];
+ size = n + 1;
+ } else {
+ SetMem (stp, sizeof (UINT64), 0xFF);
+ }
+ }
+ //
+ // Compute size up to last supported statistic.
+ //
+ while (++n < 64) {
+ if (db->Supported & (mask = LShiftU64 (mask, 1))) {
+ size = n;
+ }
+ }
+
+ size *= sizeof (UINT64);
+
+ if (*StatTableSizePtr >= size) {
+ *StatTableSizePtr = size;
+ Status = EFI_SUCCESS;
+ } else {
+ *StatTableSizePtr = size;
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/stop.c b/MdeModulePkg/Universal/Network/SnpDxe/stop.c
new file mode 100644
index 0000000000..63725237b7
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/stop.c
@@ -0,0 +1,118 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+ stop.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-09 M(f)J Genesis.
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ this routine calls undi to stop the interface and changes the snp state
+
+ @param snp pointer to snp driver structure
+
+
+**/
+EFI_STATUS
+pxe_stop (
+ SNP_DRIVER *snp
+ )
+{
+ snp->cdb.OpCode = PXE_OPCODE_STOP;
+ snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
+ snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.stop() "));
+
+ (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);
+
+ if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {
+ DEBUG (
+ (EFI_D_WARN,
+ "\nsnp->undi.stop() %xh:%xh\n",
+ snp->cdb.StatCode,
+ snp->cdb.StatFlags)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set simple network state to Started and return success.
+ //
+ snp->mode.State = EfiSimpleNetworkStopped;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This is the SNP interface routine for stopping the interface.
+ This routine basically retrieves snp structure, checks the SNP state and
+ calls the pxe_stop routine to actually stop the undi interface
+
+ @param this context pointer
+
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_stop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *this
+ )
+{
+ SNP_DRIVER *snp;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ Status = pxe_stop (snp);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/Network/SnpDxe/transmit.c b/MdeModulePkg/Universal/Network/SnpDxe/transmit.c
new file mode 100644
index 0000000000..d113edec96
--- /dev/null
+++ b/MdeModulePkg/Universal/Network/SnpDxe/transmit.c
@@ -0,0 +1,399 @@
+/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module name:
+
+ transmit.c
+
+Abstract:
+
+Revision history:
+ 2000-Feb-03 M(f)J Genesis.
+
+**/
+
+#include "Snp.h"
+
+
+/**
+ This routine calls undi to create the meadia header for the given data buffer.
+
+ @param snp pointer to SNP driver structure
+ @param MacHeaderPtr address where the media header will be filled in.
+ @param MacHeaderSize size of the memory at MacHeaderPtr
+ @param BufferPtr data buffer pointer
+ @param BufferLength Size of data in the BufferPtr
+ @param DestinationAddrPtr address of the destination mac address buffer
+ @param SourceAddrPtr address of the source mac address buffer
+ @param ProtocolPtr address of the protocol type
+
+ @retval EFI_SUCCESS if successfully completed the undi call
+ @retval Other error return from undi call.
+
+**/
+STATIC
+EFI_STATUS
+pxe_fillheader (
+ SNP_DRIVER *snp,
+ VOID *MacHeaderPtr,
+ UINTN MacHeaderSize,
+ VOID *BufferPtr,
+ UINTN BufferLength,
+ EFI_MAC_ADDRESS *DestinationAddrPtr,
+ EFI_MAC_ADDRESS *SourceAddrPtr,
+ UINT16 *ProtocolPtr
+ )
+{
+ PXE_CPB_FILL_HEADER_FRAGMENTED *cpb;
+ EFI_STATUS Status;
+ struct s_v2p *pkt_v2p;
+ UINT64 TempData;
+
+ cpb = snp->cpb;
+ if (SourceAddrPtr) {
+ CopyMem (
+ (VOID *) cpb->SrcAddr,
+ (VOID *) SourceAddrPtr,
+ snp->mode.HwAddressSize
+ );
+ } else {
+ CopyMem (
+ (VOID *) cpb->SrcAddr,
+ (VOID *) &(snp->mode.CurrentAddress),
+ snp->mode.HwAddressSize
+ );
+ }
+
+ CopyMem (
+ (VOID *) cpb->DestAddr,
+ (VOID *) DestinationAddrPtr,
+ snp->mode.HwAddressSize
+ );
+
+ //
+ // we need to do the byte swapping
+ //
+ cpb->Protocol = (UINT16) PXE_SWAP_UINT16 (*ProtocolPtr);
+
+ cpb->PacketLen = (UINT32) (BufferLength);
+ cpb->MediaHeaderLen = (UINT16) MacHeaderSize;
+
+ cpb->FragCnt = 2;
+ cpb->reserved = 0;
+
+ cpb->FragDesc[0].FragAddr = (UINT64)(UINTN) MacHeaderPtr;
+ cpb->FragDesc[0].FragLen = (UINT32) MacHeaderSize;
+ cpb->FragDesc[1].FragAddr = (UINT64)(UINTN) BufferPtr;
+ cpb->FragDesc[1].FragLen = (UINT32) BufferLength;
+
+ cpb->FragDesc[0].reserved = cpb->FragDesc[1].reserved = 0;
+
+ if (snp->IsOldUndi) {
+ TempData = (UINT64) (UINTN) MacHeaderPtr;
+ if (TempData >= FOUR_GIGABYTES) {
+ cpb->FragDesc[0].FragAddr = (UINT64) (UINTN) snp->fill_hdr_buf;
+ cpb->FragDesc[0].FragLen = (UINT32) snp->init_info.MediaHeaderLen;
+ }
+
+ TempData = (UINT64) (UINTN) (BufferPtr);
+ if (TempData >= FOUR_GIGABYTES) {
+ //
+ // Let the device just read this buffer
+ //
+ Status = add_v2p (
+ &pkt_v2p,
+ EfiPciIoOperationBusMasterRead,
+ BufferPtr,
+ BufferLength
+ );
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+ //
+ // give the virtual address to UNDI and it will call back on Virt2Phys
+ // to get the mapped address, if it needs it
+ //
+ cpb->FragDesc[1].FragLen = (UINT32) pkt_v2p->bsize;
+ }
+ }
+
+ snp->cdb.OpCode = PXE_OPCODE_FILL_HEADER;
+ snp->cdb.OpFlags = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED;
+
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+
+ snp->cdb.CPBsize = sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED);
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.fill_header() "));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ if (snp->IsOldUndi) {
+ TempData = (UINT64) (UINTN) (BufferPtr);
+ if (TempData >= FOUR_GIGABYTES) {
+ del_v2p (BufferPtr);
+ }
+ //
+ // if we used the global buffer for header, copy the contents
+ //
+ TempData = (UINT64) (UINTN) MacHeaderPtr;
+ if (TempData >= FOUR_GIGABYTES) {
+ CopyMem (
+ MacHeaderPtr,
+ snp->fill_hdr_buf,
+ snp->init_info.MediaHeaderLen
+ );
+ }
+ }
+
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ return EFI_SUCCESS;
+
+ case PXE_STATCODE_INVALID_PARAMETER:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.fill_header() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_INVALID_PARAMETER;
+
+ default:
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.fill_header() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+
+/**
+ This routine calls undi to transmit the given data buffer
+
+ @param snp pointer to SNP driver structure
+ @param BufferPtr data buffer pointer
+ @param BufferLength Size of data in the BufferPtr
+
+ @retval EFI_SUCCESS if successfully completed the undi call
+ @retval Other error return from undi call.
+
+**/
+STATIC
+EFI_STATUS
+pxe_transmit (
+ SNP_DRIVER *snp,
+ VOID *BufferPtr,
+ UINTN BufferLength
+ )
+{
+ PXE_CPB_TRANSMIT *cpb;
+ EFI_STATUS Status;
+ struct s_v2p *v2p;
+ UINT64 TempData;
+
+ cpb = snp->cpb;
+ cpb->FrameAddr = (UINT64) (UINTN) BufferPtr;
+ cpb->DataLen = (UINT32) BufferLength;
+
+ TempData = (UINT64) (UINTN) BufferPtr;
+ if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {
+ //
+ // we need to create a mapping now and give it to the undi when it calls
+ // the Virt2Phys on this address.
+ // this is a transmit, just map it for the device to READ
+ //
+ Status = add_v2p (
+ &v2p,
+ EfiPciIoOperationBusMasterRead,
+ BufferPtr,
+ BufferLength
+ );
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ cpb->DataLen = (UINT32) v2p->bsize;
+ }
+
+ cpb->MediaheaderLen = 0;
+ cpb->reserved = 0;
+
+ snp->cdb.OpFlags = PXE_OPFLAGS_TRANSMIT_WHOLE;
+
+ snp->cdb.CPBsize = sizeof (PXE_CPB_TRANSMIT);
+ snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;
+
+ snp->cdb.OpCode = PXE_OPCODE_TRANSMIT;
+ snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
+ snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
+
+ snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
+ snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
+ snp->cdb.IFnum = snp->if_num;
+ snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
+
+ //
+ // Issue UNDI command and check result.
+ //
+ DEBUG ((EFI_D_NET, "\nsnp->undi.transmit() "));
+ DEBUG ((EFI_D_NET, "\nsnp->cdb.OpCode == %x", snp->cdb.OpCode));
+ DEBUG ((EFI_D_NET, "\nsnp->cdb.CPBaddr == %X", snp->cdb.CPBaddr));
+ DEBUG ((EFI_D_NET, "\nsnp->cdb.DBaddr == %X", snp->cdb.DBaddr));
+ DEBUG ((EFI_D_NET, "\ncpb->FrameAddr == %X\n", cpb->FrameAddr));
+
+ (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
+
+ DEBUG ((EFI_D_NET, "\nexit snp->undi.transmit() "));
+ DEBUG ((EFI_D_NET, "\nsnp->cdb.StatCode == %r", snp->cdb.StatCode));
+
+ //
+ // we will unmap the buffers in get_status call, not here
+ //
+ switch (snp->cdb.StatCode) {
+ case PXE_STATCODE_SUCCESS:
+ return EFI_SUCCESS;
+
+ case PXE_STATCODE_QUEUE_FULL:
+ case PXE_STATCODE_BUSY:
+ Status = EFI_NOT_READY;
+ break;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ DEBUG (
+ (EFI_D_ERROR,
+ "\nsnp->undi.transmit() %xh:%xh\n",
+ snp->cdb.StatFlags,
+ snp->cdb.StatCode)
+ );
+
+ return Status;
+}
+
+
+/**
+ This is the snp interface routine for transmitting a packet. this routine
+ basically retrieves the snp structure, checks the snp state and calls
+ pxe_fill_header and pxe_transmit calls to complete the transmission.
+
+ @param this pointer to SNP driver context
+ @param MacHeaderSize size of the memory at MacHeaderPtr
+ @param BufferLength Size of data in the BufferPtr
+ @param BufferPtr data buffer pointer
+ @param SourceAddrPtr address of the source mac address buffer
+ @param DestinationAddrPtr address of the destination mac address buffer
+ @param ProtocolPtr address of the protocol type
+
+ @retval EFI_SUCCESS if successfully completed the undi call
+ @retval Other error return from undi call.
+
+**/
+EFI_STATUS
+EFIAPI
+snp_undi32_transmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
+ IN UINTN MacHeaderSize,
+ IN UINTN BufferLength,
+ IN VOID *BufferPtr,
+ IN EFI_MAC_ADDRESS * SourceAddrPtr OPTIONAL,
+ IN EFI_MAC_ADDRESS * DestinationAddrPtr OPTIONAL,
+ IN UINT16 *ProtocolPtr OPTIONAL
+ )
+{
+ SNP_DRIVER *snp;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (this == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (snp->mode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
+
+ if (BufferPtr == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if (BufferLength < snp->mode.MediaHeaderSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto ON_EXIT;
+ }
+
+ //
+ // if the MacHeaderSize is non-zero, we need to fill up the header and for that
+ // we need the destination address and the protocol
+ //
+ if (MacHeaderSize != 0) {
+ if (MacHeaderSize != snp->mode.MediaHeaderSize || DestinationAddrPtr == 0 || ProtocolPtr == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Status = pxe_fillheader (
+ snp,
+ BufferPtr,
+ MacHeaderSize,
+ (UINT8 *) BufferPtr + MacHeaderSize,
+ BufferLength - MacHeaderSize,
+ DestinationAddrPtr,
+ SourceAddrPtr,
+ ProtocolPtr
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ Status = pxe_transmit (snp, BufferPtr, BufferLength);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}