/********************************************************************************
Copyright (C) 2016 Marvell International Ltd.
Copyright (c) 2020, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
*******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "Mvpp2LibHw.h"
#include "Mvpp2Lib.h"
#include "Pp2Dxe.h"
#define ReturnUnlock(tpl, status) do { gBS->RestoreTPL (tpl); return (status); } while(0)
STATIC PP2_DEVICE_PATH Pp2DevicePathTemplate = {
{
{
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 }
}
};
EFI_SIMPLE_NETWORK_PROTOCOL Pp2SnpTemplate = {
EFI_SIMPLE_NETWORK_PROTOCOL_REVISION, // Revision
Pp2SnpStart, // Start
Pp2SnpStop, // Stop
Pp2DxeSnpInitialize, // Initialize
Pp2SnpReset, // Reset
Pp2SnpShutdown, // Shutdown
Pp2SnpReceiveFilters, // ReceiveFilters
Pp2SnpStationAddress, // StationAddress
Pp2SnpNetStat, // Statistics
Pp2SnpIpToMac, // MCastIpToMac
NULL, // NvData
Pp2SnpGetStatus, // GetStatus
Pp2SnpTransmit, // Transmit
Pp2SnpReceive, // Receive
NULL, // WaitForPacket
NULL // Mode
};
EFI_SIMPLE_NETWORK_MODE Pp2SnpModeTemplate = {
EfiSimpleNetworkStopped, // State
NET_ETHER_ADDR_LEN, // HwAddressSize
sizeof (ETHER_HEAD), // MediaHeaderSize
EFI_PAGE_SIZE, // MaxPacketSize
0, // NvRamSize
0, // MvRamAccessSize
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, // ReceiveFilterMask
EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST, // ReceiveFilterSetting
MAX_MCAST_FILTER_CNT, // MacMCastFilterCount
0, // MCastFilterCount
{
{ { 0 } }
}, // MCastFilter
{
{ 0 }
}, // CurrentAddress
{
{ 0 }
}, // BroadcastAddress
{
{ 0 }
}, // Permanent Address
NET_IFTYPE_ETHERNET, // IfType
TRUE, // MacAddressChangeable
FALSE, // MultipleTxSupported
TRUE, // MediaPresentSupported
FALSE // MediaPresent
};
#define QueueNext(off) ((((off) + 1) >= QUEUE_DEPTH) ? 0 : ((off) + 1))
STATIC
EFI_STATUS
QueueInsert (
IN PP2DXE_CONTEXT *Pp2Context,
IN VOID *Buffer
)
{
if (QueueNext (Pp2Context->CompletionQueueTail) == Pp2Context->CompletionQueueHead) {
return EFI_OUT_OF_RESOURCES;
}
Pp2Context->CompletionQueue[Pp2Context->CompletionQueueTail] = Buffer;
Pp2Context->CompletionQueueTail = QueueNext (Pp2Context->CompletionQueueTail);
return EFI_SUCCESS;
}
STATIC
VOID *
QueueRemove (
IN PP2DXE_CONTEXT *Pp2Context
)
{
VOID *Buffer;
if (Pp2Context->CompletionQueueTail == Pp2Context->CompletionQueueHead) {
return NULL;
}
Buffer = Pp2Context->CompletionQueue[Pp2Context->CompletionQueueHead];
Pp2Context->CompletionQueue[Pp2Context->CompletionQueueHead] = NULL;
Pp2Context->CompletionQueueHead = QueueNext (Pp2Context->CompletionQueueHead);
return Buffer;
}
STATIC
EFI_STATUS
Pp2DxeBmPoolInit (
MVPP2_SHARED *Mvpp2Shared
)
{
INTN Index;
UINT8 *PoolAddr;
UINT32 PoolSize;
EFI_STATUS Status;
ASSERT(MVPP2_BM_POOL_PTR_ALIGN >= sizeof(UINTN));
PoolSize = (sizeof(VOID *) * MVPP2_BM_SIZE) * 2 + MVPP2_BM_POOL_PTR_ALIGN;
for (Index = 0; Index < MVPP2_BM_POOLS_NUM; Index++) {
/* BmIrqClear */
Mvpp2BmIrqClear(Mvpp2Shared, Index);
}
for (Index = 0; Index < MVPP2_MAX_PORT; Index++) {
Mvpp2Shared->BmPools[Index] = AllocateZeroPool (sizeof(MVPP2_BMS_POOL));
if (Mvpp2Shared->BmPools[Index] == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto FreePools;
}
Status = DmaAllocateAlignedBuffer (EfiBootServicesData,
EFI_SIZE_TO_PAGES (PoolSize),
MVPP2_BM_POOL_PTR_ALIGN,
(VOID **)&PoolAddr);
if (EFI_ERROR (Status)) {
goto FreeBmPools;
}
ZeroMem (PoolAddr, PoolSize);
Mvpp2Shared->BmPools[Index]->Id = Index;
Mvpp2Shared->BmPools[Index]->VirtAddr = (UINT32 *)PoolAddr;
Mvpp2Shared->BmPools[Index]->PhysAddr = (UINTN)PoolAddr;
Mvpp2BmPoolHwCreate(Mvpp2Shared, Mvpp2Shared->BmPools[Index], MVPP2_BM_SIZE);
}
return EFI_SUCCESS;
FreeBmPools:
FreePool (Mvpp2Shared->BmPools[Index]);
FreePools:
while (Index-- >= 0) {
FreePool (Mvpp2Shared->BmPools[Index]);
DmaFreeBuffer (
EFI_SIZE_TO_PAGES (PoolSize),
Mvpp2Shared->BmPools[Index]->VirtAddr
);
}
return Status;
}
/* Enable and fill BM pool */
STATIC
EFI_STATUS
Pp2DxeBmStart (
MVPP2_SHARED *Mvpp2Shared
)
{
UINT8 *Buff, *BuffPhys;
INTN Index, Pool;
ASSERT(BM_ALIGN >= sizeof(UINTN));
for (Pool = 0; Pool < MVPP2_MAX_PORT; Pool++) {
Mvpp2BmPoolCtrl(Mvpp2Shared, Pool, MVPP2_START);
Mvpp2BmPoolBufsizeSet(Mvpp2Shared, Mvpp2Shared->BmPools[Pool], RX_BUFFER_SIZE);
/* Fill BM pool with Buffers */
for (Index = 0; Index < MVPP2_BM_SIZE; Index++) {
Buff = (UINT8 *)(Mvpp2Shared->BufferLocation.RxBuffers[Pool] + (Index * RX_BUFFER_SIZE));
if (Buff == NULL) {
return EFI_OUT_OF_RESOURCES;
}
BuffPhys = ALIGN_POINTER(Buff, BM_ALIGN);
Mvpp2BmPoolPut(Mvpp2Shared, Pool, (UINTN)BuffPhys, (UINTN)BuffPhys);
}
}
Mvpp2Shared->BmEnabled = TRUE;
return EFI_SUCCESS;
}
STATIC
VOID
Pp2DxeStartDev (
IN PP2DXE_CONTEXT *Pp2Context
)
{
PP2DXE_PORT *Port = &Pp2Context->Port;
/* Config classifier decoding table */
Mvpp2ClsPortConfig(Port);
Mvpp2ClsOversizeRxqSet(Port);
MvGop110PortEventsMask(Port);
MvGop110PortEnable(Port);
/* Enable transmit and receive */
Mvpp2EgressEnable(Port);
Mvpp2IngressEnable(Port);
}
STATIC
EFI_STATUS
Pp2DxeSetupRxqs (
IN PP2DXE_CONTEXT *Pp2Context
)
{
INTN Queue;
EFI_STATUS Status;
MVPP2_RX_QUEUE *Rxq;
for (Queue = 0; Queue < RxqNumber; Queue++) {
Rxq = &Pp2Context->Port.Rxqs[Queue];
Rxq->DescsPhys = (DmaAddrT)Rxq->Descs;
if (Rxq->Descs == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ErrCleanup;
}
Mvpp2RxqHwInit(&Pp2Context->Port, Rxq);
}
return EFI_SUCCESS;
ErrCleanup:
Mvpp2CleanupRxqs(&Pp2Context->Port);
return Status;
}
STATIC
EFI_STATUS
Pp2DxeSetupTxqs (
IN PP2DXE_CONTEXT *Pp2Context
)
{
INTN Queue;
MVPP2_TX_QUEUE *Txq;
EFI_STATUS Status;
for (Queue = 0; Queue < TxqNumber; Queue++) {
Txq = &Pp2Context->Port.Txqs[Queue];
Txq->DescsPhys = (DmaAddrT)Txq->Descs;
if (Txq->Descs == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ErrCleanup;
}
Mvpp2TxqHwInit(&Pp2Context->Port, Txq);
}
return EFI_SUCCESS;
ErrCleanup:
Mvpp2CleanupTxqs(&Pp2Context->Port);
return Status;
}
STATIC
EFI_STATUS
Pp2DxeSetupAggrTxqs (
IN PP2DXE_CONTEXT *Pp2Context
)
{
MVPP2_TX_QUEUE *AggrTxq;
MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
AggrTxq = Mvpp2Shared->AggrTxqs;
AggrTxq->DescsPhys = (DmaAddrT)AggrTxq->Descs;
if (AggrTxq->Descs == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Mvpp2AggrTxqHwInit(AggrTxq, AggrTxq->Size, 0, Mvpp2Shared);
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
Pp2DxeOpen (
IN PP2DXE_CONTEXT *Pp2Context
)
{
PP2DXE_PORT *Port = &Pp2Context->Port;
MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
UINT8 MacBcast[NET_ETHER_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
UINT8 DevAddr[NET_ETHER_ADDR_LEN];
INTN Ret;
EFI_STATUS Status;
CopyMem (DevAddr, Pp2Context->Snp.Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);
Ret = Mvpp2PrsMacDaAccept(Mvpp2Shared, Port->Id, MacBcast, TRUE);
if (Ret != 0) {
return EFI_DEVICE_ERROR;
}
Ret = Mvpp2PrsMacDaAccept(Mvpp2Shared, Port->Id, DevAddr, TRUE);
if (Ret != 0) {
return EFI_DEVICE_ERROR;
}
Ret = Mvpp2PrsTagModeSet(Mvpp2Shared, Port->Id, MVPP2_TAG_TYPE_MH);
if (Ret != 0) {
return EFI_DEVICE_ERROR;
}
Ret = Mvpp2PrsDefFlow(Port);
if (Ret != 0) {
return EFI_DEVICE_ERROR;
}
Status = Pp2DxeSetupRxqs(Pp2Context);
if (EFI_ERROR(Status)) {
return Status;
}
Status = Pp2DxeSetupTxqs(Pp2Context);
if (EFI_ERROR(Status)) {
return Status;
}
Status = Pp2DxeSetupAggrTxqs(Pp2Context);
if (EFI_ERROR(Status)) {
return Status;
}
Pp2DxeStartDev(Pp2Context);
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
Pp2DxeLatePortInitialize (
IN PP2DXE_CONTEXT *Pp2Context
)
{
PP2DXE_PORT *Port = &Pp2Context->Port;
MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
INTN Queue;
Port->TxRingSize = MVPP2_MAX_TXD;
Port->RxRingSize = MVPP2_MAX_RXD;
Mvpp2EgressDisable(Port);
MvGop110PortEventsMask(Port);
MvGop110PortDisable(Port);
Port->Txqs = AllocateZeroPool (sizeof(MVPP2_TX_QUEUE) * TxqNumber);
if (Port->Txqs == NULL) {
DEBUG((DEBUG_ERROR, "Failed to allocate Txqs\n"));
return EFI_OUT_OF_RESOURCES;
}
/* Use preallocated area */
Port->Txqs[0].Descs = Mvpp2Shared->BufferLocation.TxDescs[Port->Id];
for (Queue = 0; Queue < TxqNumber; Queue++) {
MVPP2_TX_QUEUE *Txq = &Port->Txqs[Queue];
Txq->Id = Mvpp2TxqPhys(Port->Id, Queue);
Txq->LogId = Queue;
Txq->Size = Port->TxRingSize;
}
Port->Rxqs = AllocateZeroPool (sizeof(MVPP2_RX_QUEUE) * RxqNumber);
if (Port->Rxqs == NULL) {
DEBUG((DEBUG_ERROR, "Failed to allocate Rxqs\n"));
return EFI_OUT_OF_RESOURCES;
}
Port->Rxqs[0].Descs = Mvpp2Shared->BufferLocation.RxDescs[Port->Id];
for (Queue = 0; Queue < TxqNumber; Queue++) {
MVPP2_RX_QUEUE *Rxq = &Port->Rxqs[Queue];
Rxq->Id = Queue + Port->FirstRxq;
Rxq->Size = Port->RxRingSize;
}
Mvpp2IngressDisable(Port);
Mvpp2DefaultsSet(Port);
return Pp2DxeOpen(Pp2Context);
}
STATIC
EFI_STATUS
Pp2DxeLateInitialize (
IN PP2DXE_CONTEXT *Pp2Context
)
{
PP2DXE_PORT *Port = &Pp2Context->Port;
EFI_STATUS Status;
if (!Pp2Context->LateInitialized) {
/* Full init on first call */
Status = Pp2DxeLatePortInitialize(Pp2Context);
if (EFI_ERROR(Status)) {
DEBUG((DEBUG_ERROR, "Pp2Dxe: late initialization failed\n"));
return Status;
}
/* Attach pool to Rxq */
Mvpp2RxqLongPoolSet(Port, 0, Port->Id);
Mvpp2RxqShortPoolSet(Port, 0, Port->Id);
/*
* Mark this port being fully initialized,
* otherwise it will be inited again
* during next networking transaction,
* including memory allocatation for
* TX/RX queue, PHY connect/configuration
* and address decode configuration.
*/
Pp2Context->LateInitialized = TRUE;
} else {
/* Upon all following calls, this is enough */
MvGop110PortEventsMask(Port);
MvGop110PortEnable(Port);
}
return 0;
}
EFI_STATUS
Pp2DxePhyInitialize (
PP2DXE_CONTEXT *Pp2Context
)
{
EFI_STATUS Status;
Status = gBS->LocateProtocol (
&gMarvellPhyProtocolGuid,
NULL,
(VOID **) &Pp2Context->Phy
);
if (EFI_ERROR(Status)) {
return Status;
}
if (Pp2Context->Port.PhyIndex == 0xff) {
/* PHY iniitalization not required */
return EFI_SUCCESS;
}
Status = Pp2Context->Phy->Init(
Pp2Context->Phy,
Pp2Context->Port.PhyIndex,
Pp2Context->Port.PhyInterface,
&Pp2Context->PhyDev
);
if (EFI_ERROR(Status) && Status != EFI_TIMEOUT) {
return Status;
}
Pp2Context->Phy->Status(Pp2Context->Phy, Pp2Context->PhyDev);
Mvpp2SmiPhyAddrCfg(&Pp2Context->Port, Pp2Context->Port.GopIndex, Pp2Context->PhyDev->Addr);
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
Pp2DxeSnpInitialize (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN UINTN ExtraRxBufferSize OPTIONAL,
IN UINTN ExtraTxBufferSize OPTIONAL
)
{
EFI_STATUS Status;
PP2DXE_CONTEXT *Pp2Context;
Pp2Context = INSTANCE_FROM_SNP(This);
UINT32 State = This->Mode->State;
EFI_TPL SavedTpl;
if (ExtraRxBufferSize != 0 || ExtraTxBufferSize != 0) {
DEBUG((DEBUG_ERROR, "Pp2Dxe%d: non-zero buffer requests\n", Pp2Context->Instance));
return EFI_UNSUPPORTED;
}
SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
if (State != EfiSimpleNetworkStarted) {
switch (State) {
case EfiSimpleNetworkInitialized:
DEBUG((DEBUG_WARN, "Pp2Dxe%d: already initialized\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_SUCCESS);
case EfiSimpleNetworkStopped:
DEBUG((DEBUG_WARN, "Pp2Dxe%d: network stopped\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_NOT_STARTED);
default:
DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR);
}
}
/* Successfully started, change state to Initialized */
This->Mode->State = EfiSimpleNetworkInitialized;
if (Pp2Context->Initialized) {
ReturnUnlock(SavedTpl, EFI_SUCCESS);
}
Pp2Context->Initialized = TRUE;
Status = Pp2DxePhyInitialize(Pp2Context);
if (EFI_ERROR(Status)) {
ReturnUnlock (SavedTpl, Status);
}
Status = Pp2DxeLateInitialize(Pp2Context);
ReturnUnlock (SavedTpl, Status);
}
EFI_STATUS
EFIAPI
Pp2SnpStart (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
PP2DXE_CONTEXT *Pp2Context;
UINT32 State = This->Mode->State;
EFI_TPL SavedTpl;
SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
Pp2Context = INSTANCE_FROM_SNP(This);
if (State != EfiSimpleNetworkStopped) {
switch (State) {
case EfiSimpleNetworkStarted:
case EfiSimpleNetworkInitialized:
DEBUG((DEBUG_WARN, "Pp2Dxe%d: already initialized\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_ALREADY_STARTED);
default:
DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR);
}
}
This->Mode->State = EfiSimpleNetworkStarted;
ReturnUnlock (SavedTpl, EFI_SUCCESS);
}
EFI_STATUS
EFIAPI
Pp2SnpStop (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
EFI_TPL SavedTpl;
SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This);
UINT32 State = This->Mode->State;
if (State != EfiSimpleNetworkStarted && State != EfiSimpleNetworkInitialized) {
switch (State) {
case EfiSimpleNetworkStopped:
DEBUG((DEBUG_WARN, "Pp2Dxe%d: not started\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_NOT_STARTED);
default:
DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR);
}
}
This->Mode->State = EfiSimpleNetworkStopped;
ReturnUnlock (SavedTpl, EFI_SUCCESS);
}
EFI_STATUS
EFIAPI
Pp2SnpReset (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
)
{
return EFI_SUCCESS;
}
VOID
EFIAPI
Pp2DxeHalt (
IN EFI_EVENT Event,
IN VOID *Context
)
{
PP2DXE_CONTEXT *Pp2Context = Context;
PP2DXE_PORT *Port = &Pp2Context->Port;
MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
INTN Index;
if (Mvpp2Shared->BmEnabled) {
for (Index = 0; Index < MVPP2_MAX_PORT; Index++) {
Mvpp2BmStop(Mvpp2Shared, Index);
}
Mvpp2Shared->BmEnabled = FALSE;
}
Mvpp2TxqDrainSet(Port, 0, TRUE);
Mvpp2IngressDisable(Port);
Mvpp2EgressDisable(Port);
MvGop110PortEventsMask(Port);
MvGop110PortDisable(Port);
}
EFI_STATUS
EFIAPI
Pp2SnpShutdown (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
EFI_TPL SavedTpl;
SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This);
UINT32 State = This->Mode->State;
if (State != EfiSimpleNetworkInitialized) {
switch (State) {
case EfiSimpleNetworkStopped:
DEBUG((DEBUG_WARN, "Pp2Dxe%d: not started\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_NOT_STARTED);
case EfiSimpleNetworkStarted:
/* Fall through */
default:
DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR);
}
}
ReturnUnlock (SavedTpl, EFI_SUCCESS);
}
EFI_STATUS
EFIAPI
Pp2SnpReceiveFilters (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN UINT32 Enable,
IN UINT32 Disable,
IN BOOLEAN ResetMCastFilter,
IN UINTN MCastFilterCnt OPTIONAL,
IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
)
{
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
Pp2SnpStationAddress (
IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
IN BOOLEAN Reset,
IN EFI_MAC_ADDRESS *NewMac
)
{
PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(Snp);
PP2_DEVICE_PATH *Pp2DevicePath = Pp2Context->DevicePath;
PP2DXE_PORT *Port = &Pp2Context->Port;
MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
UINT32 State = Snp->Mode->State;
EFI_TPL SavedTpl;
INTN Ret;
/* Check Snp instance */
ASSERT(Snp != NULL);
/* Serialize access to data and registers */
SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
/* Check that driver was started and initialised */
if (State != EfiSimpleNetworkInitialized) {
switch (State) {
case EfiSimpleNetworkStopped:
DEBUG((DEBUG_WARN, "Pp2Dxe%d: not started\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_NOT_STARTED);
case EfiSimpleNetworkStarted:
/* Fall through */
default:
DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR);
}
}
/* Invalidate old unicast address in parser */
Ret = Mvpp2PrsMacDaAccept(Mvpp2Shared, Port->Id, Snp->Mode->CurrentAddress.Addr, FALSE);
if (Ret != 0) {
DEBUG((DEBUG_ERROR, "Pp2SnpStationAddress - Fail\n"));
return EFI_DEVICE_ERROR;
}
if (Reset) {
CopyMem (Snp->Mode->CurrentAddress.Addr, Snp->Mode->PermanentAddress.Addr, NET_ETHER_ADDR_LEN);
CopyMem (NewMac->Addr, Snp->Mode->PermanentAddress.Addr, NET_ETHER_ADDR_LEN);
CopyMem (Pp2DevicePath->Pp2Mac.MacAddress.Addr, Snp->Mode->PermanentAddress.Addr, NET_ETHER_ADDR_LEN);
} else {
if (NewMac == NULL) {
ReturnUnlock (SavedTpl, EFI_INVALID_PARAMETER);
}
CopyMem (Snp->Mode->CurrentAddress.Addr, NewMac->Addr, NET_ETHER_ADDR_LEN);
CopyMem (Pp2DevicePath->Pp2Mac.MacAddress.Addr, NewMac->Addr, NET_ETHER_ADDR_LEN);
}
/* Update parser with new unicast address */
Ret = Mvpp2PrsMacDaAccept(Mvpp2Shared, Port->Id, Snp->Mode->CurrentAddress.Addr, TRUE);
if (Ret != 0) {
DEBUG((DEBUG_ERROR, "Pp2SnpStationAddress - Fail\n"));
return EFI_DEVICE_ERROR;
}
/* Restore TPL and return */
gBS->RestoreTPL (SavedTpl);
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
Pp2SnpNetStat (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN BOOLEAN Reset,
IN OUT UINTN *StatisticsSize OPTIONAL,
OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
Pp2SnpIpToMac (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN BOOLEAN IPv6,
IN EFI_IP_ADDRESS *IP,
OUT EFI_MAC_ADDRESS *MAC
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
Pp2SnpNvData (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN BOOLEAN ReadWrite,
IN UINTN Offset,
IN UINTN BufferSize,
IN OUT VOID *Buffer
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
Pp2SnpGetStatus (
IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp,
OUT UINT32 *InterruptStatus OPTIONAL,
OUT VOID **TxBuf OPTIONAL
)
{
PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(Snp);
PP2DXE_PORT *Port = &Pp2Context->Port;
BOOLEAN LinkUp;
EFI_TPL SavedTpl;
SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
if (!Pp2Context->Initialized)
ReturnUnlock(SavedTpl, EFI_NOT_READY);
LinkUp = Port->AlwaysUp ? TRUE : MvGop110PortIsLinkUp(Port);
if (LinkUp != Snp->Mode->MediaPresent) {
DEBUG((DEBUG_INFO, "Pp2Dxe%d: Link ", Pp2Context->Instance));
DEBUG((DEBUG_INFO, LinkUp ? "up\n" : "down\n"));
}
Snp->Mode->MediaPresent = LinkUp;
if (TxBuf != NULL) {
*TxBuf = QueueRemove (Pp2Context);
}
ReturnUnlock(SavedTpl, EFI_SUCCESS);
}
EFI_STATUS
EFIAPI
Pp2SnpTransmit (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN UINTN HeaderSize,
IN UINTN BufferSize,
IN VOID *Buffer,
IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
IN UINT16 *EtherTypePtr OPTIONAL
)
{
PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This);
PP2DXE_PORT *Port = &Pp2Context->Port;
MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
MVPP2_TX_QUEUE *AggrTxq = Mvpp2Shared->AggrTxqs;
MVPP2_TX_DESC *TxDesc;
EFI_STATUS Status;
INTN PollingCount;
INTN TxSent;
UINT8 *DataPtr = Buffer;
UINT16 EtherType;
UINT32 State = This->Mode->State;
EFI_TPL SavedTpl;
if (This == NULL || Buffer == NULL) {
DEBUG((DEBUG_ERROR, "Pp2Dxe: NULL Snp or Buffer\n"));
return EFI_INVALID_PARAMETER;
}
if (HeaderSize != 0) {
ASSERT (HeaderSize == This->Mode->MediaHeaderSize);
ASSERT (EtherTypePtr != NULL);
ASSERT (DestAddr != NULL);
}
SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
/* Check that driver was started and initialised */
if (State != EfiSimpleNetworkInitialized) {
switch (State) {
case EfiSimpleNetworkStopped:
DEBUG((DEBUG_WARN, "Pp2Dxe%d: not started\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_NOT_STARTED);
case EfiSimpleNetworkStarted:
/* Fall through */
default:
DEBUG((DEBUG_ERROR, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance));
ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR);
}
}
if (!This->Mode->MediaPresent) {
DEBUG((DEBUG_ERROR, "Pp2Dxe: link not ready\n"));
ReturnUnlock(SavedTpl, EFI_NOT_READY);
}
EtherType = HTONS (*EtherTypePtr);
/* Fetch next descriptor */
TxDesc = Mvpp2TxqNextDescGet(AggrTxq);
if (!TxDesc) {
DEBUG((DEBUG_ERROR, "No tx descriptor to use\n"));
ReturnUnlock(SavedTpl, EFI_OUT_OF_RESOURCES);
}
if (HeaderSize != 0) {
CopyMem(DataPtr, DestAddr, NET_ETHER_ADDR_LEN);
if (SrcAddr != NULL)
CopyMem(DataPtr + NET_ETHER_ADDR_LEN, SrcAddr, NET_ETHER_ADDR_LEN);
else
CopyMem(DataPtr + NET_ETHER_ADDR_LEN, &This->Mode->CurrentAddress, NET_ETHER_ADDR_LEN);
CopyMem(DataPtr + NET_ETHER_ADDR_LEN * 2, &EtherType, 2);
}
/* Set descriptor fields */
TxDesc->command = MVPP2_TXD_IP_CSUM_DISABLE | MVPP2_TXD_L4_CSUM_NOT |
MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC;
TxDesc->DataSize = BufferSize;
TxDesc->PacketOffset = (PhysAddrT)DataPtr & MVPP2_TX_DESC_ALIGN;
Mvpp2x2TxdescPhysAddrSet((PhysAddrT)DataPtr & ~MVPP2_TX_DESC_ALIGN, TxDesc);
TxDesc->PhysTxq = Mvpp2TxqPhys(Port->Id, 0);
InvalidateDataCacheRange (DataPtr, BufferSize);
/* Issue send */
Mvpp2AggrTxqPendDescAdd(Port, 1);
/*
* Egress processing:
* Wait until packet is passed from per-cpu aggregated queue
* to physical per-port TXQ.
*/
PollingCount = 0;
TxSent = Mvpp2AggrTxqPendDescNumGet(Mvpp2Shared, 0);
do {
if (PollingCount++ > MVPP2_TX_SEND_MAX_POLLING_COUNT) {
DEBUG((DEBUG_ERROR, "Pp2Dxe: transmit polling failed\n"));
ReturnUnlock(SavedTpl, EFI_TIMEOUT);
}
TxSent = Mvpp2AggrTxqPendDescNumGet(Mvpp2Shared, 0);
} while (TxSent);
/* Wait for packet to be transmitted by hardware. */
PollingCount = 0;
TxSent = Mvpp2TxqSentDescProc(Port, &Port->Txqs[0]);
while (!TxSent) {
if (PollingCount++ > MVPP2_TX_SEND_MAX_POLLING_COUNT) {
DEBUG((DEBUG_ERROR, "Pp2Dxe: transmit polling failed\n"));
ReturnUnlock(SavedTpl, EFI_TIMEOUT);
}
TxSent = Mvpp2TxqSentDescProc(Port, &Port->Txqs[0]);
}
/*
* At this point TxSent has increased - HW sent the packet
* Add buffer to completion queue and return.
*/
Status = QueueInsert (Pp2Context, Buffer);
ReturnUnlock (SavedTpl, Status);
}
EFI_STATUS
EFIAPI
Pp2SnpReceive (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
OUT UINTN *HeaderSize OPTIONAL,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer,
OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL,
OUT UINT16 *EtherType OPTIONAL
)
{
INTN ReceivedPackets;
PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This);
PP2DXE_PORT *Port = &Pp2Context->Port;
MVPP2_SHARED *Mvpp2Shared = Pp2Context->Port.Priv;
UINTN PhysAddr, VirtAddr;
EFI_STATUS Status = EFI_SUCCESS;
EFI_TPL SavedTpl;
UINT32 StatusReg;
INTN PoolId;
UINTN PktLength;
UINT8 *DataPtr;
MVPP2_RX_DESC *RxDesc;
MVPP2_RX_QUEUE *Rxq = &Port->Rxqs[0];
ASSERT (Port != NULL);
ASSERT (Rxq != NULL);
SavedTpl = gBS->RaiseTPL (TPL_CALLBACK);
ReceivedPackets = Mvpp2RxqReceived(Port, Rxq->Id);
if (ReceivedPackets == 0) {
ReturnUnlock(SavedTpl, EFI_NOT_READY);
}
/* Process one packet per call */
RxDesc = Mvpp2RxqNextDescGet(Rxq);
StatusReg = RxDesc->status;
/* extract addresses from descriptor */
PhysAddr = RxDesc->BufPhysAddrKeyHash & MVPP22_ADDR_MASK;
VirtAddr = RxDesc->BufCookieBmQsetClsInfo & MVPP22_ADDR_MASK;
/* Drop packets with error or with buffer header (MC, SG) */
if ((StatusReg & MVPP2_RXD_BUF_HDR) || (StatusReg & MVPP2_RXD_ERR_SUMMARY)) {
DEBUG((DEBUG_WARN, "Pp2Dxe: dropping packet\n"));
Status = EFI_DEVICE_ERROR;
goto drop;
}
PktLength = (UINTN) RxDesc->DataSize - 2;
if (PktLength > *BufferSize) {
*BufferSize = PktLength;
DEBUG((DEBUG_ERROR, "Pp2Dxe: buffer too small\n"));
ReturnUnlock(SavedTpl, EFI_BUFFER_TOO_SMALL);
}
CopyMem (Buffer, (VOID*) (PhysAddr + 2), PktLength);
*BufferSize = PktLength;
if (HeaderSize != NULL) {
*HeaderSize = Pp2Context->Snp.Mode->MediaHeaderSize;
}
DataPtr = Buffer;
/* Extract the destination address */
if (DstAddr != NULL) {
ZeroMem (DstAddr, sizeof(EFI_MAC_ADDRESS));
CopyMem (DstAddr, &DataPtr[0], NET_ETHER_ADDR_LEN);
}
/* Get the source address */
if (SrcAddr != NULL) {
ZeroMem (SrcAddr, sizeof(EFI_MAC_ADDRESS));
CopyMem (SrcAddr, &DataPtr[6], NET_ETHER_ADDR_LEN);
}
/* Obtain Ether Type */
if (EtherType != NULL) {
*EtherType = NTOHS (*(UINT16 *)(&DataPtr[12]));
}
drop:
/* Refill: pass packet back to BM */
PoolId = (StatusReg & MVPP2_RXD_BM_POOL_ID_MASK) >> MVPP2_RXD_BM_POOL_ID_OFFS;
Mvpp2BmPoolPut(Mvpp2Shared, PoolId, PhysAddr, VirtAddr);
/* Update counters with 1 packet received and 1 packet refilled */
Mvpp2RxqStatusUpdate(Port, Rxq->Id, 1, 1);
ReturnUnlock(SavedTpl, Status);
}
EFI_STATUS
Pp2DxeSnpInstall (
IN PP2DXE_CONTEXT *Pp2Context
)
{
EFI_HANDLE Handle = NULL;
EFI_STATUS Status;
PP2_DEVICE_PATH *Pp2DevicePath;
EFI_SIMPLE_NETWORK_MODE *SnpMode;
Pp2DevicePath = AllocateCopyPool (sizeof (PP2_DEVICE_PATH), &Pp2DevicePathTemplate);
if (Pp2DevicePath == NULL) {
return EFI_OUT_OF_RESOURCES;
}
SnpMode = AllocateZeroPool (sizeof (EFI_SIMPLE_NETWORK_MODE));
if (SnpMode == NULL) {
return EFI_OUT_OF_RESOURCES;
}
/* Copy SNP data from templates */
CopyMem (&Pp2Context->Snp, &Pp2SnpTemplate, sizeof (EFI_SIMPLE_NETWORK_PROTOCOL));
CopyMem (SnpMode, &Pp2SnpModeTemplate, sizeof (EFI_SIMPLE_NETWORK_MODE));
/* Handle device path of the controller */
Pp2DevicePath->Pp2Mac.MacAddress.Addr[5] = Pp2Context->Instance + 1;
Pp2Context->Signature = PP2DXE_SIGNATURE;
Pp2Context->DevicePath = Pp2DevicePath;
Pp2DevicePath->Pp2Mac.IfType = SnpMode->IfType;
/* Update SNP Mode */
CopyMem (SnpMode->CurrentAddress.Addr, Pp2DevicePath->Pp2Mac.MacAddress.Addr, NET_ETHER_ADDR_LEN);
CopyMem (SnpMode->PermanentAddress.Addr, Pp2DevicePath->Pp2Mac.MacAddress.Addr, NET_ETHER_ADDR_LEN);
ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS));
SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF);
Pp2Context->Snp.Mode = SnpMode;
/* Install protocol */
Status = gBS->InstallMultipleProtocolInterfaces (
&Handle,
&gEfiSimpleNetworkProtocolGuid, &Pp2Context->Snp,
&gEfiDevicePathProtocolGuid, Pp2DevicePath,
&gEfiAdapterInformationProtocolGuid, &Pp2Context->Aip,
NULL
);
if (EFI_ERROR(Status)) {
DEBUG((DEBUG_ERROR, "Failed to install protocols.\n"));
}
return Status;
}
/**
Returns the current state information for the adapter.
This function returns information of type InformationType from the adapter.
If an adapter does not support the requested informational type, then
EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_ADAPTER_INFORMATION_PROTOCOL instance.
@param[in] InformationType A pointer to an EFI_GUID that defines the contents of InformationBlock.
@param[out] InformationBlock The service returns a pointer to the buffer with the InformationBlock
structure which contains details about the data specific to InformationType.
@param[out] InformationBlockSize The driver returns the size of the InformationBlock in bytes.
@retval EFI_SUCCESS The InformationType information was retrieved.
@retval EFI_UNSUPPORTED The InformationType is not known.
@retval EFI_DEVICE_ERROR The device reported an error.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_INVALID_PARAMETER InformationBlock is NULL.
@retval EFI_INVALID_PARAMETER InformationBlockSize is NULL.
**/
STATIC
EFI_STATUS
EFIAPI
Pp2AipGetInformation (
IN EFI_ADAPTER_INFORMATION_PROTOCOL *This,
IN EFI_GUID *InformationType,
OUT VOID **InformationBlock,
OUT UINTN *InformationBlockSize
)
{
EFI_ADAPTER_INFO_MEDIA_STATE *AdapterInfo;
PP2DXE_CONTEXT *Pp2Context;
EFI_STATUS Status;
if (This == NULL || InformationBlock == NULL || InformationBlockSize == NULL) {
return EFI_INVALID_PARAMETER;
}
if (!CompareGuid (InformationType, &gEfiAdapterInfoMediaStateGuid)) {
return EFI_UNSUPPORTED;
}
AdapterInfo = AllocateZeroPool (sizeof (EFI_ADAPTER_INFO_MEDIA_STATE));
if (AdapterInfo == NULL) {
return EFI_OUT_OF_RESOURCES;
}
*InformationBlock = AdapterInfo;
*InformationBlockSize = sizeof (EFI_ADAPTER_INFO_MEDIA_STATE);
Pp2Context = INSTANCE_FROM_AIP (This);
Status = Pp2Context->Snp.GetStatus (&(Pp2Context->Snp), NULL, NULL);
if (Status == EFI_NOT_READY){
AdapterInfo->MediaState = EFI_NOT_READY;
return EFI_SUCCESS;
} else if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a Failed to get media status\n", __FUNCTION__));
return EFI_DEVICE_ERROR;
}
if (Pp2Context->Snp.Mode->MediaPresent) {
AdapterInfo->MediaState = EFI_SUCCESS;
} else {
AdapterInfo->MediaState = EFI_NOT_READY;
}
return EFI_SUCCESS;
}
/**
Sets state information for an adapter.
This function sends information of type InformationType for an adapter.
If an adapter does not support the requested information type, then EFI_UNSUPPORTED
is returned.
@param[in] This A pointer to the EFI_ADAPTER_INFORMATION_PROTOCOL instance.
@param[in] InformationType A pointer to an EFI_GUID that defines the contents of InformationBlock.
@param[in] InformationBlock A pointer to the InformationBlock structure which contains details
about the data specific to InformationType.
@param[in] InformationBlockSize The size of the InformationBlock in bytes.
@retval EFI_SUCCESS The information was received and interpreted successfully.
@retval EFI_UNSUPPORTED The InformationType is not known.
@retval EFI_DEVICE_ERROR The device reported an error.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_INVALID_PARAMETER InformationBlock is NULL.
@retval EFI_WRITE_PROTECTED The InformationType cannot be modified using EFI_ADAPTER_INFO_SET_INFO().
**/
STATIC
EFI_STATUS
EFIAPI
Pp2AipSetInformation (
IN EFI_ADAPTER_INFORMATION_PROTOCOL *This,
IN EFI_GUID *InformationType,
IN VOID *InformationBlock,
IN UINTN InformationBlockSize
)
{
if (This == NULL || InformationBlock == NULL) {
return EFI_INVALID_PARAMETER;
}
if (CompareGuid (InformationType, &gEfiAdapterInfoMediaStateGuid)) {
return EFI_WRITE_PROTECTED;
}
return EFI_UNSUPPORTED;
}
/**
Get a list of supported information types for this instance of the protocol.
This function returns a list of InformationType GUIDs that are supported on an
adapter with this instance of EFI_ADAPTER_INFORMATION_PROTOCOL. The list is returned
in InfoTypesBuffer, and the number of GUID pointers in InfoTypesBuffer is returned in
InfoTypesBufferCount.
@param[in] This A pointer to the EFI_ADAPTER_INFORMATION_PROTOCOL instance.
@param[out] InfoTypesBuffer A pointer to the array of InformationType GUIDs that are supported
by This.
@param[out] InfoTypesBufferCount A pointer to the number of GUIDs present in InfoTypesBuffer.
@retval EFI_SUCCESS The list of information type GUIDs that are supported on this adapter was
returned in InfoTypesBuffer. The number of information type GUIDs was
returned in InfoTypesBufferCount.
@retval EFI_INVALID_PARAMETER This is NULL.
@retval EFI_INVALID_PARAMETER InfoTypesBuffer is NULL.
@retval EFI_INVALID_PARAMETER InfoTypesBufferCount is NULL.
@retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the results.
**/
STATIC
EFI_STATUS
EFIAPI
Pp2AipGetSupportedTypes (
IN EFI_ADAPTER_INFORMATION_PROTOCOL *This,
OUT EFI_GUID **InfoTypesBuffer,
OUT UINTN *InfoTypesBufferCount
)
{
if (This == NULL || InfoTypesBuffer == NULL || InfoTypesBufferCount == NULL) {
return EFI_INVALID_PARAMETER;
}
*InfoTypesBuffer = AllocatePool (sizeof (EFI_GUID));
if (*InfoTypesBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
*InfoTypesBufferCount = 1;
CopyGuid (*InfoTypesBuffer, &gEfiAdapterInfoMediaStateGuid);
return EFI_SUCCESS;
}
STATIC
VOID
Pp2DxeParsePortPcd (
IN PP2DXE_CONTEXT *Pp2Context,
IN INTN Index
)
{
UINT8 *PortIds, *GopIndexes, *PhyConnectionTypes, *AlwaysUp, *Speed, *PhyIndexes;
PortIds = PcdGetPtr (PcdPp2PortIds);
GopIndexes = PcdGetPtr (PcdPp2GopIndexes);
PhyConnectionTypes = PcdGetPtr (PcdPp2PhyConnectionTypes);
PhyIndexes = PcdGetPtr (PcdPp2PhyIndexes);
AlwaysUp = PcdGetPtr (PcdPp2InterfaceAlwaysUp);
Speed = PcdGetPtr (PcdPp2InterfaceSpeed);
ASSERT (PcdGetSize (PcdPp2GopIndexes) == PcdGetSize (PcdPp2PortIds));
ASSERT (PcdGetSize (PcdPp2PhyConnectionTypes) == PcdGetSize (PcdPp2PortIds));
ASSERT (PcdGetSize (PcdPp2InterfaceAlwaysUp) == PcdGetSize (PcdPp2PortIds));
ASSERT (PcdGetSize (PcdPp2InterfaceSpeed) == PcdGetSize (PcdPp2PortIds));
ASSERT (PcdGetSize (PcdPp2PhyIndexes) == PcdGetSize (PcdPp2PortIds));
Pp2Context->Port.Id = PortIds[Index];
Pp2Context->Port.GopIndex = GopIndexes[Index];
Pp2Context->Port.PhyInterface = PhyConnectionTypes[Index];
Pp2Context->Port.PhyIndex = PhyIndexes[Index];
Pp2Context->Port.AlwaysUp = AlwaysUp[Index];
Pp2Context->Port.Speed = Speed[Index];
}
STATIC
EFI_STATUS
Pp2DxeInitialiseController (
IN UINT8 ControllerIndex,
IN MVPP2_SHARED *Mvpp2Shared,
IN UINTN BaseAddress,
IN UINTN ClockFrequency
)
{
PP2DXE_CONTEXT *Pp2Context = NULL;
EFI_STATUS Status;
INTN Index;
INTN PortIndex = 0;
VOID *BufferSpace;
UINT32 NetCompConfig = 0;
STATIC UINT8 DeviceInstance;
UINT8 *Pp2PortMappingTable;
Mvpp2Shared->Base = BaseAddress;
Mvpp2Shared->Rfu1Base = Mvpp2Shared->Base + MVPP22_RFU1_OFFSET;
Mvpp2Shared->XpcsBase = Mvpp2Shared->Base + MVPP22_XPCS_OFFSET;
Mvpp2Shared->MpcsBase = Mvpp2Shared->Base + MVPP22_MPCS_OFFSET;
Mvpp2Shared->SmiBase = Mvpp2Shared->Base + MVPP22_SMI_OFFSET;
Mvpp2Shared->Tclk = ClockFrequency;
/* Prepare buffers */
Status = DmaAllocateAlignedBuffer (EfiBootServicesData,
EFI_SIZE_TO_PAGES (BD_SPACE),
MVPP2_BUFFER_ALIGN_SIZE,
&BufferSpace);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Failed to allocate buffer space\n"));
return Status;
}
ZeroMem (BufferSpace, BD_SPACE);
for (Index = 0; Index < MVPP2_MAX_PORT; Index++) {
Mvpp2Shared->BufferLocation.TxDescs[Index] = (MVPP2_TX_DESC *)
((UINTN)BufferSpace + Index * MVPP2_MAX_TXD * sizeof(MVPP2_TX_DESC));
}
Mvpp2Shared->BufferLocation.AggrTxDescs = (MVPP2_TX_DESC *)
((UINTN)BufferSpace + MVPP2_MAX_TXD * MVPP2_MAX_PORT * sizeof(MVPP2_TX_DESC));
for (Index = 0; Index < MVPP2_MAX_PORT; Index++) {
Mvpp2Shared->BufferLocation.RxDescs[Index] = (MVPP2_RX_DESC *)
((UINTN)BufferSpace + (MVPP2_MAX_TXD * MVPP2_MAX_PORT + MVPP2_AGGR_TXQ_SIZE) *
sizeof(MVPP2_TX_DESC) + Index * MVPP2_MAX_RXD * sizeof(MVPP2_RX_DESC));
}
for (Index = 0; Index < MVPP2_MAX_PORT; Index++) {
Mvpp2Shared->BufferLocation.RxBuffers[Index] = (DmaAddrT)
((UINTN)BufferSpace + (MVPP2_MAX_TXD * MVPP2_MAX_PORT + MVPP2_AGGR_TXQ_SIZE) *
sizeof(MVPP2_TX_DESC) + MVPP2_MAX_RXD * MVPP2_MAX_PORT * sizeof(MVPP2_RX_DESC) +
Index * MVPP2_BM_SIZE * RX_BUFFER_SIZE);
}
/* Initialize HW */
Mvpp2AxiConfig(Mvpp2Shared);
Pp2DxeBmPoolInit (Mvpp2Shared);
Mvpp2RxFifoInit(Mvpp2Shared);
Mvpp2Shared->PrsShadow = AllocateZeroPool (sizeof(MVPP2_PRS_SHADOW) * MVPP2_PRS_TCAM_SRAM_SIZE);
if (Mvpp2Shared->PrsShadow == NULL) {
DEBUG((DEBUG_ERROR, "Failed to allocate PrsShadow\n"));
return EFI_OUT_OF_RESOURCES;
}
Status = Mvpp2PrsDefaultInit(Mvpp2Shared);
if (EFI_ERROR(Status)) {
DEBUG((DEBUG_ERROR, "Failed to intialize prs\n"));
return EFI_DEVICE_ERROR;
}
Mvpp2ClsInit(Mvpp2Shared);
Status = Pp2DxeBmStart (Mvpp2Shared);
if (EFI_ERROR(Status)) {
DEBUG((DEBUG_ERROR, "Pp2Dxe: BM start error\n"));
return Status;
}
/* Initialize aggregated transmit queues */
Mvpp2Shared->AggrTxqs = AllocateZeroPool (sizeof(MVPP2_TX_QUEUE));
if (Mvpp2Shared->AggrTxqs == NULL) {
DEBUG((DEBUG_ERROR, "Failed to allocate aggregated Txqs\n"));
return EFI_OUT_OF_RESOURCES;
}
Mvpp2Shared->AggrTxqs->Descs = Mvpp2Shared->BufferLocation.AggrTxDescs;
Mvpp2Shared->AggrTxqs->Id = 0;
Mvpp2Shared->AggrTxqs->LogId = 0;
Mvpp2Shared->AggrTxqs->Size = MVPP2_AGGR_TXQ_SIZE;
Pp2PortMappingTable = (UINT8 *)PcdGetPtr (PcdPp2Port2Controller);
for (Index = 0; Index < PcdGetSize (PcdPp2Port2Controller); Index++) {
if (Pp2PortMappingTable[Index] != ControllerIndex) {
continue;
}
if (PortIndex++ > MVPP2_MAX_PORT) {
DEBUG ((DEBUG_ERROR, "Pp2Dxe: Wrong too many ports for single controller\n"));
return EFI_INVALID_PARAMETER;
}
Pp2Context = AllocateZeroPool (sizeof (PP2DXE_CONTEXT));
if (Pp2Context == NULL) {
/*
* If allocation fails, all resources allocated before will get freed
* at ExitBootServices, as only EfiBootServicesData is used.
*/
DEBUG((DEBUG_ERROR, "Allocation fail.\n"));
return EFI_OUT_OF_RESOURCES;
}
/* Instances are enumerated from 0 */
Pp2Context->Instance = DeviceInstance;
DeviceInstance++;
/* Prepare AIP Protocol */
Pp2Context->Aip.GetInformation = Pp2AipGetInformation;
Pp2Context->Aip.SetInformation = Pp2AipSetInformation;
Pp2Context->Aip.GetSupportedTypes = Pp2AipGetSupportedTypes;
/* Install SNP protocol */
Status = Pp2DxeSnpInstall(Pp2Context);
if (EFI_ERROR(Status)) {
return Status;
}
Pp2DxeParsePortPcd(Pp2Context, Index);
Pp2Context->Port.TxpNum = 1;
Pp2Context->Port.Priv = Mvpp2Shared;
Pp2Context->Port.FirstRxq = 4 * (PortIndex - 1);
Pp2Context->Port.GmacBase = Mvpp2Shared->Base + MVPP22_GMAC_OFFSET +
MVPP22_GMAC_REG_SIZE * Pp2Context->Port.GopIndex;
Pp2Context->Port.XlgBase = Mvpp2Shared->Base + MVPP22_XLG_OFFSET +
MVPP22_XLG_REG_SIZE * Pp2Context->Port.GopIndex;
/* Gather accumulated configuration data of all ports' MAC's */
NetCompConfig |= MvpPp2xGop110NetcCfgCreate(&Pp2Context->Port);
MvGop110PortInit(&Pp2Context->Port);
if (Pp2Context->Port.AlwaysUp == TRUE) {
MvGop110GmacForceLinkUp (&Pp2Context->Port);
MvGop110FlCfg (&Pp2Context->Port);
}
Status = gBS->CreateEvent (
EVT_SIGNAL_EXIT_BOOT_SERVICES,
TPL_NOTIFY,
Pp2DxeHalt,
Pp2Context,
&Pp2Context->EfiExitBootServicesEvent
);
if (EFI_ERROR(Status)) {
return Status;
}
}
MvGop110NetcInit(&Pp2Context->Port, NetCompConfig, MV_NETC_FIRST_PHASE);
MvGop110NetcInit(&Pp2Context->Port, NetCompConfig, MV_NETC_SECOND_PHASE);
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
Pp2DxeInitialise (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
MARVELL_BOARD_DESC_PROTOCOL *BoardDescProtocol;
MV_BOARD_PP2_DESC *Pp2BoardDesc;
MVPP2_SHARED *Mvpp2Shared;
EFI_STATUS Status;
UINTN Index;
/* Obtain table with enabled Pp2 devices */
Status = gBS->LocateProtocol (&gMarvellBoardDescProtocolGuid,
NULL,
(VOID **)&BoardDescProtocol);
if (EFI_ERROR (Status)) {
return Status;
}
Status = BoardDescProtocol->BoardDescPp2Get (BoardDescProtocol,
&Pp2BoardDesc);
if (EFI_ERROR (Status)) {
return Status;
}
/* Initialize enabled chips */
for (Index = 0; Index < Pp2BoardDesc->Pp2DevCount; Index++) {
/* Initialize private data */
Mvpp2Shared = AllocateZeroPool (sizeof (MVPP2_SHARED));
if (Mvpp2Shared == NULL) {
DEBUG ((DEBUG_ERROR, "Pp2Dxe #%d: Mvpp2Shared allocation fail\n", Index));
return EFI_OUT_OF_RESOURCES;
}
Status = Pp2DxeInitialiseController (
Index,
Mvpp2Shared,
Pp2BoardDesc[Index].SoC->Pp2BaseAddress,
Pp2BoardDesc[Index].SoC->Pp2ClockFrequency
);
if (EFI_ERROR(Status)) {
FreePool (Mvpp2Shared);
DEBUG ((DEBUG_ERROR, "Pp2Dxe #%d: Controller initialisation fail\n", Index));
return Status;
}
}
BoardDescProtocol->BoardDescFree (Pp2BoardDesc);
return EFI_SUCCESS;
}