/** @file
Copyright (c) 2011 - 2019, Intel Corporaton. All rights reserved.
Copyright (c) 2020, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "DwEmacSnpDxe.h"
#include
#include
#include
#include
#include
#include
STATIC
EFI_STATUS
EFIAPI
DriverSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
STATIC
EFI_STATUS
EFIAPI
DriverStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
STATIC
EFI_STATUS
EFIAPI
DriverStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
);
STATIC
EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {
DriverSupported,
DriverStart,
DriverStop,
0xa,
NULL,
NULL
};
STATIC
SIMPLE_NETWORK_DEVICE_PATH PathTemplate = {
{
{
MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP,
{(UINT8)(sizeof (MAC_ADDR_DEVICE_PATH)), (UINT8)((sizeof (MAC_ADDR_DEVICE_PATH)) >> 8)}
},
{{ 0 }},
0
},
{
END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
{sizeof (EFI_DEVICE_PATH_PROTOCOL), 0}
}
};
STATIC
EFI_STATUS
EFIAPI
DriverSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
NON_DISCOVERABLE_DEVICE *Dev;
EFI_STATUS Status;
// Connect to the non-discoverable device
Status = gBS->OpenProtocol (Controller,
&gEdkiiNonDiscoverableDeviceProtocolGuid,
(VOID **)&Dev,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER);
if (EFI_ERROR (Status)) {
return Status;
}
// Clean up.
gBS->CloseProtocol (Controller,
&gEdkiiNonDiscoverableDeviceProtocolGuid,
This->DriverBindingHandle,
Controller);
return Status;
}
STATIC
EFI_STATUS
EFIAPI
DriverStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
SIMPLE_NETWORK_DRIVER *Snp;
EFI_SIMPLE_NETWORK_MODE *SnpMode;
SIMPLE_NETWORK_DEVICE_PATH *DevicePath;
UINT64 DefaultMacAddress;
EFI_MAC_ADDRESS *SwapMacAddressPtr;
UINTN DescriptorSize;
UINTN BufferSize;
UINTN *RxBufferAddr;
EFI_PHYSICAL_ADDRESS RxBufferAddrMap;
// Allocate Resources
Snp = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (SIMPLE_NETWORK_DRIVER)));
if (Snp == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = gBS->OpenProtocol (Controller,
&gEdkiiNonDiscoverableDeviceProtocolGuid,
(VOID **)&Snp->Dev,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER);
// Size for descriptor
DescriptorSize = EFI_PAGES_TO_SIZE (sizeof (DESIGNWARE_HW_DESCRIPTOR));
// Size for transmit and receive buffer
BufferSize = ETH_BUFSIZE;
for (int Index=0; Index < DESC_NUM; Index++) {
//DMA TxdescRing allocate buffer and map
Status = DmaAllocateBuffer (EfiBootServicesData,
EFI_SIZE_TO_PAGES (sizeof (DESIGNWARE_HW_DESCRIPTOR)), (VOID *)&Snp->MacDriver.TxdescRing[Index]);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a () for TxdescRing: %r\n", __FUNCTION__, Status));
return Status;
}
Status = DmaMap (MapOperationBusMasterCommonBuffer, Snp->MacDriver.TxdescRing[Index],
&DescriptorSize, &Snp->MacDriver.TxdescRingMap[Index].AddrMap, &Snp->MacDriver.TxdescRingMap[Index].Mapping);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a () for TxdescRing: %r\n", __FUNCTION__, Status));
return Status;
}
// DMA RxdescRing allocte buffer and map
Status = DmaAllocateBuffer (EfiBootServicesData,
EFI_SIZE_TO_PAGES (sizeof (DESIGNWARE_HW_DESCRIPTOR)), (VOID *)&Snp->MacDriver.RxdescRing[Index]);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a () for RxdescRing: %r\n", __FUNCTION__, Status));
return Status;
}
Status = DmaMap (MapOperationBusMasterCommonBuffer, Snp->MacDriver.RxdescRing[Index],
&DescriptorSize, &Snp->MacDriver.RxdescRingMap[Index].AddrMap, &Snp->MacDriver.RxdescRingMap[Index].Mapping);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a () for RxdescRing: %r\n", __FUNCTION__, Status));
return Status;
}
//DMA mapping for receive buffer
RxBufferAddr = (UINTN*)((UINTN)Snp->MacDriver.RxBuffer + (Index * BufferSize));
Status = DmaMap (MapOperationBusMasterWrite, (VOID *) RxBufferAddr,
&BufferSize, &RxBufferAddrMap, &Snp->MacDriver.RxBufNum[Index].Mapping);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a () for Rxbuffer: %r\n", __FUNCTION__, Status));
return Status;
}
Snp->MacDriver.RxBufNum[Index].AddrMap= RxBufferAddrMap;
}
DevicePath = (SIMPLE_NETWORK_DEVICE_PATH*)AllocateCopyPool (sizeof (SIMPLE_NETWORK_DEVICE_PATH), &PathTemplate);
if (DevicePath == NULL) {
return EFI_OUT_OF_RESOURCES;
}
// Initialized signature (used by INSTANCE_FROM_SNP_THIS macro)
Snp->Signature = SNP_DRIVER_SIGNATURE;
EfiInitializeLock (&Snp->Lock, TPL_CALLBACK);
// Initialize pointers
SnpMode = &Snp->SnpMode;
Snp->Snp.Mode = SnpMode;
// Get MAC controller base address
Snp->MacBase = (UINTN)Snp->Dev->Resources[0].AddrRangeMin;
// Assign fields and func pointers
Snp->Snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
Snp->Snp.WaitForPacket = NULL;
Snp->Snp.Initialize = SnpInitialize;
Snp->Snp.Start = SnpStart;
Snp->Snp.Stop = SnpStop;
Snp->Snp.Reset = SnpReset;
Snp->Snp.Shutdown = SnpShutdown;
Snp->Snp.ReceiveFilters = SnpReceiveFilters;
Snp->Snp.StationAddress = SnpStationAddress;
Snp->Snp.Statistics = SnpStatistics;
Snp->Snp.MCastIpToMac = SnpMcastIptoMac;
Snp->Snp.NvData = SnpNvData;
Snp->Snp.GetStatus = SnpGetStatus;
Snp->Snp.Transmit = SnpTransmit;
Snp->Snp.Receive = SnpReceive;
Snp->RecycledTxBuf = AllocatePool (sizeof (UINT64) * SNP_TX_BUFFER_INCREASE);
if (Snp->RecycledTxBuf == NULL) {
Status = EFI_OUT_OF_RESOURCES;
}
Snp->MaxRecycledTxBuf = SNP_TX_BUFFER_INCREASE;
Snp->RecycledTxBufCount = 0;
// Start completing simple network mode structure
SnpMode->State = EfiSimpleNetworkStopped;
SnpMode->HwAddressSize = NET_ETHER_ADDR_LEN; // HW address is 6 bytes
SnpMode->MediaHeaderSize = sizeof (ETHER_HEAD);
SnpMode->MaxPacketSize = EFI_PAGE_SIZE; // Preamble + SOF + Ether Frame (with VLAN tag +4bytes)
SnpMode->NvRamSize = 0; // No NVRAM with this device
SnpMode->NvRamAccessSize = 0; // No NVRAM with this device
// Update network mode information
SnpMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS |
EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
// We do not intend to receive anything for the time being.
SnpMode->ReceiveFilterSetting = 0;
// EMAC has 64bit hash table, can filter 64 MCast MAC Addresses
SnpMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;
SnpMode->MCastFilterCount = 0;
ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof (EFI_MAC_ADDRESS));
// Set the interface type (1: Ethernet or 6: IEEE 802 Networks)
SnpMode->IfType = NET_IFTYPE_ETHERNET;
// Mac address is changeable as it is loaded from erasable memory
SnpMode->MacAddressChangeable = TRUE;
// Can only transmit one packet at a time
SnpMode->MultipleTxSupported = FALSE;
// MediaPresent checks for cable connection and partner link
SnpMode->MediaPresentSupported = TRUE;
SnpMode->MediaPresent = FALSE;
// Set broadcast address
SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF);
//Set current address
DefaultMacAddress = Snp->Dev->Resources[1].AddrRangeMin;
// Swap PCD human readable form to correct endianess
SwapMacAddressPtr = (EFI_MAC_ADDRESS *) &DefaultMacAddress;
SnpMode->CurrentAddress.Addr[0] = SwapMacAddressPtr->Addr[5];
SnpMode->CurrentAddress.Addr[1] = SwapMacAddressPtr->Addr[4];
SnpMode->CurrentAddress.Addr[2] = SwapMacAddressPtr->Addr[3];
SnpMode->CurrentAddress.Addr[3] = SwapMacAddressPtr->Addr[2];
SnpMode->CurrentAddress.Addr[4] = SwapMacAddressPtr->Addr[1];
SnpMode->CurrentAddress.Addr[5] = SwapMacAddressPtr->Addr[0];
// Assign fields for device path
CopyMem (&DevicePath->MacAddrDP.MacAddress, &Snp->Snp.Mode->CurrentAddress, NET_ETHER_ADDR_LEN);
DevicePath->MacAddrDP.IfType = Snp->Snp.Mode->IfType;
Status = gBS->InstallMultipleProtocolInterfaces (
&Controller,
&gEfiSimpleNetworkProtocolGuid, &(Snp->Snp),
&gEfiDevicePathProtocolGuid, DevicePath,
NULL
);
if (EFI_ERROR(Status)) {
gBS->CloseProtocol (Controller,
&gEdkiiNonDiscoverableDeviceProtocolGuid,
This->DriverBindingHandle,
Controller);
FreePages (Snp, EFI_SIZE_TO_PAGES (sizeof (SIMPLE_NETWORK_DRIVER)));
} else {
Snp->ControllerHandle = Controller;
}
return Status;
}
STATIC
EFI_STATUS
EFIAPI
DriverStop (
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;
SIMPLE_NETWORK_DRIVER *Snp;
Status = gBS->HandleProtocol (
Controller,
&gEfiSimpleNetworkProtocolGuid,
(VOID **)&SnpProtocol
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a (): HandleProtocol: %r\n", __FUNCTION__, Status));
return Status;
}
Snp = INSTANCE_FROM_SNP_THIS(SnpProtocol);
Status = gBS->UninstallMultipleProtocolInterfaces (
Controller,
&gEfiSimpleNetworkProtocolGuid,
&Snp->Snp,
NULL);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a (): UninstallMultipleProtocolInterfaces: %r\n", __FUNCTION__, Status));
return Status;
}
FreePool (Snp->RecycledTxBuf);
FreePages (Snp, EFI_SIZE_TO_PAGES (sizeof (SIMPLE_NETWORK_DRIVER)));
return Status;
}
/**
UEFI Driver Entry Point API
@param ImageHandle EFI_HANDLE.
@param SystemTable EFI_SYSTEM_TABLE.
@return EFI_SUCCESS Success.
EFI_DEVICE_ERROR Fail.
**/
EFI_STATUS
EFIAPI
DwEmacSnpDxeEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&mDriverBinding,
ImageHandle,
&gSnpComponentName,
&gSnpComponentName2
);
return Status;
}