From 8a67d61da4d5a8f08a656cbeea2d902d0ad9042a Mon Sep 17 00:00:00 2001 From: vanjeff Date: Tue, 24 Jul 2007 08:06:37 +0000 Subject: Import SnpDxe, Tcp4Dxe, Udp4Dxe and MnpDxe. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3416 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/Network/SnpDxe/ComponentName.c | 163 +++ MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf | 75 ++ MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.msa | 90 ++ .../Universal/Network/SnpDxe/WaitForPacket.c | 97 ++ MdeModulePkg/Universal/Network/SnpDxe/callback.c | 611 ++++++++++ MdeModulePkg/Universal/Network/SnpDxe/get_status.c | 195 +++ MdeModulePkg/Universal/Network/SnpDxe/initialize.c | 245 ++++ .../Universal/Network/SnpDxe/mcast_ip_to_mac.c | 165 +++ MdeModulePkg/Universal/Network/SnpDxe/nvdata.c | 185 +++ MdeModulePkg/Universal/Network/SnpDxe/receive.c | 255 ++++ .../Universal/Network/SnpDxe/receive_filters.c | 406 +++++++ MdeModulePkg/Universal/Network/SnpDxe/reset.c | 128 ++ MdeModulePkg/Universal/Network/SnpDxe/shutdown.c | 148 +++ MdeModulePkg/Universal/Network/SnpDxe/snp.c | 1269 ++++++++++++++++++++ MdeModulePkg/Universal/Network/SnpDxe/snp.h | 454 +++++++ MdeModulePkg/Universal/Network/SnpDxe/start.c | 191 +++ .../Universal/Network/SnpDxe/station_address.c | 237 ++++ MdeModulePkg/Universal/Network/SnpDxe/statistics.c | 201 ++++ MdeModulePkg/Universal/Network/SnpDxe/stop.c | 118 ++ MdeModulePkg/Universal/Network/SnpDxe/transmit.c | 399 ++++++ 20 files changed, 5632 insertions(+) create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/ComponentName.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.msa create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/WaitForPacket.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/callback.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/get_status.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/initialize.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/mcast_ip_to_mac.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/nvdata.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/receive.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/receive_filters.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/reset.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/shutdown.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/snp.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/snp.h create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/start.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/station_address.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/statistics.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/stop.c create mode 100644 MdeModulePkg/Universal/Network/SnpDxe/transmit.c (limited to 'MdeModulePkg/Universal/Network/SnpDxe') 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 @@ + + + SnpDxe + DXE_DRIVER + A2f436EA-A127-4EF8-957C-8048606FF670 + 1.0 + 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. + FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052 + + + IA32 X64 IPF EBC + false + SnpDxe + + + + DebugLib + + + BaseMemoryLib + + + UefiDriverEntryPoint + + + UefiBootServicesTableLib + + + BaseLib + + + UefiLib + + + + station_address.c + SNPEntry.c + callback.c + ComponentName.c + initialize.c + receive_filters.c + WaitForPacket.c + transmit.c + mcast_ip_to_mac.c + shutdown.c + reset.c + statistics.c + stop.c + snp.c + start.c + get_status.c + nvdata.c + snp.h + receive.c + + + + + + + + gEfiNetworkInterfaceIdentifierProtocolGuid + + + gEfiDevicePathProtocolGuid + + + gEfiSimpleNetworkProtocolGuid + + + gEfiPciIoProtocolGuid + + + + EFI_SPECIFICATION_VERSION 0x00020000 + EDK_RELEASE_VERSION 0x00020000 + + InitializeSnpNiiDriver + + + \ 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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#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; +} -- cgit v1.2.3