mirror of https://github.com/acidanthera/audk.git
284 lines
8.8 KiB
C
284 lines
8.8 KiB
C
/** @file
|
|
Implementation of initializing a network adapter.
|
|
|
|
Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
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.
|
|
|
|
**/
|
|
|
|
|
|
#include "Snp.h"
|
|
|
|
/**
|
|
Call 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).
|
|
|
|
@retval EFI_SUCCESS UNDI is initialized successfully.
|
|
@retval EFI_DEVICE_ERROR UNDI could not be initialized.
|
|
@retval Other Other errors as indicated.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
PxeInit (
|
|
SNP_DRIVER *Snp,
|
|
UINT16 CableDetectFlag
|
|
)
|
|
{
|
|
PXE_CPB_INITIALIZE *Cpb;
|
|
VOID *Addr;
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
Cpb = Snp->Cpb;
|
|
if (Snp->TxRxBufferSize != 0) {
|
|
Status = Snp->PciIo->AllocateBuffer (
|
|
Snp->PciIo,
|
|
AllocateAnyPages,
|
|
EfiBootServicesData,
|
|
SNP_MEM_PAGES (Snp->TxRxBufferSize),
|
|
&Addr,
|
|
0
|
|
);
|
|
|
|
if (Status != EFI_SUCCESS) {
|
|
DEBUG (
|
|
(EFI_D_ERROR,
|
|
"\nSnp->PxeInit() AllocateBuffer %xh (%r)\n",
|
|
Status,
|
|
Status)
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
ASSERT (Addr);
|
|
|
|
Snp->TxRxBuffer = Addr;
|
|
}
|
|
|
|
Cpb->MemoryAddr = (UINT64)(UINTN) Snp->TxRxBuffer;
|
|
|
|
Cpb->MemoryLength = Snp->TxRxBufferSize;
|
|
|
|
//
|
|
// 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 = (UINT16) sizeof (PXE_CPB_INITIALIZE);
|
|
Snp->Cdb.DBsize = (UINT16) 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->IfNum;
|
|
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
|
|
|
|
DEBUG ((EFI_D_NET, "\nSnp->undi.initialize() "));
|
|
|
|
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
|
|
|
|
//
|
|
// There are two fields need to be checked here:
|
|
// First is 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, the command has not been executed by the UNDI.
|
|
// Second is the CDB.StatCode field. After command execution completes, either successfully or not,
|
|
// the CDB.StatCode field contains the result of the command execution.
|
|
//
|
|
if ((((Snp->Cdb.StatFlags) & PXE_STATFLAGS_STATUS_MASK) == PXE_STATFLAGS_COMMAND_COMPLETE) &&
|
|
(Snp->Cdb.StatCode == PXE_STATCODE_SUCCESS)) {
|
|
//
|
|
// If cable detect feature is enabled in CDB.OpFlags, check the CDB.StatFlags to see if there is an
|
|
// active connection to this network device. If the no media StatFlag is set, the UNDI and network
|
|
// device are still initialized.
|
|
//
|
|
if (CableDetectFlag == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
|
|
if(((Snp->Cdb.StatFlags) & PXE_STATFLAGS_INITIALIZED_NO_MEDIA) != PXE_STATFLAGS_INITIALIZED_NO_MEDIA) {
|
|
Snp->Mode.MediaPresent = TRUE;
|
|
} else {
|
|
Snp->Mode.MediaPresent = FALSE;
|
|
}
|
|
}
|
|
|
|
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->TxRxBuffer != NULL) {
|
|
Snp->PciIo->FreeBuffer (
|
|
Snp->PciIo,
|
|
SNP_MEM_PAGES (Snp->TxRxBufferSize),
|
|
(VOID *) Snp->TxRxBuffer
|
|
);
|
|
}
|
|
|
|
Snp->TxRxBuffer = NULL;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Resets a network adapter and allocates the transmit and receive buffers
|
|
required by the network interface; optionally, also requests allocation of
|
|
additional transmit and receive buffers.
|
|
|
|
This function allocates the transmit and receive buffers required by the network
|
|
interface. If this allocation fails, then EFI_OUT_OF_RESOURCES is returned.
|
|
If the allocation succeeds and the network interface is successfully initialized,
|
|
then EFI_SUCCESS will be returned.
|
|
|
|
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
|
|
|
|
@param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space
|
|
that the driver should allocate for the network interface.
|
|
Some network interfaces will not be able to use the
|
|
extra buffer, and the caller will not know if it is
|
|
actually being used.
|
|
@param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space
|
|
that the driver should allocate for the network interface.
|
|
Some network interfaces will not be able to use the
|
|
extra buffer, and the caller will not know if it is
|
|
actually being used.
|
|
|
|
@retval EFI_SUCCESS The network interface was initialized.
|
|
@retval EFI_NOT_STARTED The network interface has not been started.
|
|
@retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and
|
|
receive buffers.
|
|
@retval EFI_INVALID_PARAMETER 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 The increased buffer size feature is not supported.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SnpUndi32Initialize (
|
|
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
|
|
IN UINTN ExtraRxBufferSize OPTIONAL,
|
|
IN UINTN ExtraTxBufferSize 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->TxRxBufferSize = (UINT32) (Snp->InitInfo.MemoryRequired + ExtraRxBufferSize + ExtraTxBufferSize);
|
|
|
|
//
|
|
// If UNDI support cable detect for INITIALIZE command, try it first.
|
|
//
|
|
if (Snp->CableDetectSupported) {
|
|
if (PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) == EFI_SUCCESS) {
|
|
goto ON_EXIT;
|
|
}
|
|
}
|
|
|
|
Snp->Mode.MediaPresent = FALSE;
|
|
|
|
EfiStatus = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
|
|
|
|
if (EFI_ERROR (EfiStatus)) {
|
|
gBS->CloseEvent (Snp->Snp.WaitForPacket);
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
//
|
|
// Try to update the MediaPresent field of EFI_SIMPLE_NETWORK_MODE if the UNDI support it.
|
|
//
|
|
if (Snp->MediaStatusSupported) {
|
|
PxeGetStatus (Snp, NULL, FALSE);
|
|
}
|
|
|
|
ON_EXIT:
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
return EfiStatus;
|
|
}
|