/******************************************************************************** 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; }