/** @file Implementation of starting a network adapter. ;****************************************************************************** ;* Copyright (c) 2020, Insyde Software Corporation. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Snp.h" /** Call UNDI to start the interface and changes the snp state. @param Snp pointer to snp driver structure. @retval EFI_SUCCESS UNDI is started successfully. @retval EFI_DEVICE_ERROR UNDI could not be started. **/ EFI_STATUS PxeStart ( IN SNP_DRIVER *Snp ) { PXE_CPB_START_31 *Cpb31; UINTN Index; BOOLEAN ErrFlag; Cpb31 = 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->IfNum; 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->IsSwUndi) { Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_START_31); Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb31; Cpb31->Delay = (UINT64)(UINTN) &SnpUndi32CallbackDelay; Cpb31->Block = (UINT64)(UINTN) &SnpUndi32CallbackBlock; // // Virtual == Physical. This can be set to zero. // Cpb31->Virt2Phys = (UINT64)(UINTN) 0; Cpb31->Mem_IO = (UINT64)(UINTN) &SnpUndi32CallbackMemio; Cpb31->Map_Mem = (UINT64)(UINTN) &SnpUndi32CallbackMap; Cpb31->UnMap_Mem = (UINT64)(UINTN) &SnpUndi32CallbackUnmap; Cpb31->Sync_Mem = (UINT64)(UINTN) &SnpUndi32CallbackSync; Cpb31->Unique_ID = (UINT64)(UINTN) Snp; } // // Issue UNDI command and check result. // DEBUG ((EFI_D_NET, "\nsnp->undi.start() ")); for (Index = 0; Index < 3; Index++) { Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE; Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; PerformanceStartMeasure (0, "UNDI Start", NULL, 0); (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb); PerformanceEndMeasure (0, "UNDI Start", NULL, 0); // // E.4.3.3 Waiting for the Command to Execute // Monitor the upper two bits (14 & 15) in the CDB.StatFlags field. // Until these bits change to report PXE_STATFLAGS_COMMAND_COMPLETE // or PXE_STATFLAGS_COMMAND_FAILED // if ((((Snp->Cdb.StatFlags) & PXE_STATFLAGS_STATUS_MASK) == PXE_STATFLAGS_COMMAND_COMPLETE) || (((Snp->Cdb.StatFlags) & PXE_STATFLAGS_STATUS_MASK) == PXE_STATFLAGS_COMMAND_FAILED)) { break; } DEBUG ((EFI_D_NET, "retrying (%x:%x)...\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode)); } // // There are two fields need to be checked here: // 1. The upper two bits (14 & 15) in the CDB.StatFlags field. // 2. the CDB.StatCode field contains the result of the command execution. // ErrFlag = TRUE; if (((Snp->Cdb.StatFlags) & PXE_STATFLAGS_STATUS_MASK) == PXE_STATFLAGS_COMMAND_COMPLETE) { if (Snp->Cdb.StatCode == PXE_STATCODE_SUCCESS) { ErrFlag = FALSE; } } if (Snp->Cdb.StatCode == PXE_STATCODE_ALREADY_STARTED) { ErrFlag = FALSE; } if (ErrFlag == TRUE) { // // 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; } /** Change the state of a network interface from "stopped" to "started." This function starts a network interface. If the network interface successfully starts, then EFI_SUCCESS will be returned. @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. @retval EFI_SUCCESS The network interface was started. @retval EFI_ALREADY_STARTED The network interface is already in the started state. @retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid EFI_SIMPLE_NETWORK_PROTOCOL structure. @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. @retval EFI_UNSUPPORTED This function is not supported by the network interface. **/ EFI_STATUS EFIAPI SnpUndi32Start ( 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 = PxeStart (Snp); if (EFI_ERROR (Status)) { goto ON_EXIT; } // // clear the map_list in SNP structure // for (Index = 0; Index < MAX_MAP_LENGTH; Index++) { Snp->MapList[Index].VirtualAddress = 0; Snp->MapList[Index].MapCookie = 0; } Snp->Mode.MCastFilterCount = 0; ON_EXIT: gBS->RestoreTPL (OldTpl); return Status; }