summaryrefslogtreecommitdiff
path: root/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c
diff options
context:
space:
mode:
Diffstat (limited to 'Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c')
-rw-r--r--Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c1271
1 files changed, 1271 insertions, 0 deletions
diff --git a/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c
new file mode 100644
index 0000000000..8de2473d09
--- /dev/null
+++ b/Platform/Marvell/Drivers/Net/Pp2Dxe/Pp2Dxe.c
@@ -0,0 +1,1271 @@
+/********************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/SimpleNetwork.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NetLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include "Mvpp2LibHw.h"
+#include "Mvpp2Lib.h"
+#include "Pp2Dxe.h"
+
+#define ReturnUnlock(tpl, status) do { gBS->RestoreTPL (tpl); return (status); } while(0)
+
+STATIC MVPP2_SHARED *Mvpp2Shared;
+STATIC BUFFER_LOCATION BufferLocation;
+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 (
+ VOID
+ )
+{
+ INTN Index;
+ UINT8 *PoolAddr;
+ UINT32 PoolSize = (sizeof(VOID *) * MVPP2_BM_SIZE) * 2 + MVPP2_BM_POOL_PTR_ALIGN;
+
+ 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);
+ }
+
+ Mvpp2Shared->BmPools = AllocateZeroPool (sizeof(MVPP2_BMS_POOL));
+
+ if (Mvpp2Shared->BmPools == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PoolAddr = UncachedAllocateAlignedZeroPool (PoolSize, MVPP2_BM_POOL_PTR_ALIGN);
+ if (PoolAddr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Mvpp2Shared->BmPools->Id = MVPP2_BM_POOL;
+ Mvpp2Shared->BmPools->VirtAddr = (UINT32 *)PoolAddr;
+ Mvpp2Shared->BmPools->PhysAddr = (UINTN)PoolAddr;
+
+ Mvpp2BmPoolHwCreate(Mvpp2Shared, Mvpp2Shared->BmPools, MVPP2_BM_SIZE);
+
+ return EFI_SUCCESS;
+}
+
+/* Enable and fill BM pool */
+STATIC
+EFI_STATUS
+Pp2DxeBmStart (
+ VOID
+ )
+{
+ UINT8 *Buff, *BuffPhys;
+ INTN Index;
+
+ ASSERT(BM_ALIGN >= sizeof(UINTN));
+
+ Mvpp2BmPoolCtrl(Mvpp2Shared, MVPP2_BM_POOL, MVPP2_START);
+ Mvpp2BmPoolBufsizeSet(Mvpp2Shared, Mvpp2Shared->BmPools, RX_BUFFER_SIZE);
+
+ /* Fill BM pool with Buffers */
+ for (Index = 0; Index < MVPP2_BM_SIZE; Index++) {
+ Buff = (UINT8 *)(BufferLocation.RxBuffers + (Index * RX_BUFFER_SIZE));
+ if (Buff == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BuffPhys = ALIGN_POINTER(Buff, BM_ALIGN);
+ Mvpp2BmPoolPut(Mvpp2Shared, MVPP2_BM_POOL, (UINTN)BuffPhys, (UINTN)BuffPhys);
+ }
+
+ 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;
+
+ 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;
+ 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;
+ 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 = BufferLocation.TxDescs;
+
+ 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 = BufferLocation.RxDescs;
+
+ 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, MVPP2_BM_POOL);
+ Mvpp2RxqShortPoolSet(Port, 0, MVPP2_BM_POOL);
+
+ /*
+ * 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;
+ UINT8 *PhyAddresses;
+
+ PhyAddresses = PcdGetPtr (PcdPhySmiAddresses);
+ Status = gBS->LocateProtocol (
+ &gMarvellPhyProtocolGuid,
+ NULL,
+ (VOID **) &Pp2Context->Phy
+ );
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (PhyAddresses[Pp2Context->Instance] == 0xff) {
+ /* PHY iniitalization not required */
+ return EFI_SUCCESS;
+ }
+
+ Status = Pp2Context->Phy->Init(
+ Pp2Context->Phy,
+ PhyAddresses[Pp2Context->Instance],
+ 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;
+ STATIC BOOLEAN CommonPartHalted = FALSE;
+
+ if (!CommonPartHalted) {
+ Mvpp2BmStop(Mvpp2Shared, MVPP2_BM_POOL);
+ CommonPartHalted = TRUE;
+ }
+
+ 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;
+ 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_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;
+ 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,
+ NULL
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Failed to install protocols.\n"));
+ }
+
+ return Status;
+}
+
+STATIC
+VOID
+Pp2DxeParsePortPcd (
+ IN PP2DXE_CONTEXT *Pp2Context
+ )
+{
+ UINT8 *PortIds, *GopIndexes, *PhyConnectionTypes, *AlwaysUp, *Speed;
+
+ PortIds = PcdGetPtr (PcdPp2PortIds);
+ GopIndexes = PcdGetPtr (PcdPp2GopIndexes);
+ PhyConnectionTypes = PcdGetPtr (PcdPhyConnectionTypes);
+ AlwaysUp = PcdGetPtr (PcdPp2InterfaceAlwaysUp);
+ Speed = PcdGetPtr (PcdPp2InterfaceSpeed);
+
+ ASSERT (PcdGetSize (PcdPp2GopIndexes) == PcdGetSize (PcdPp2PortIds));
+ ASSERT (PcdGetSize (PcdPhyConnectionTypes) == PcdGetSize (PcdPp2PortIds));
+ ASSERT (PcdGetSize (PcdPp2InterfaceAlwaysUp) == PcdGetSize (PcdPp2PortIds));
+ ASSERT (PcdGetSize (PcdPp2InterfaceSpeed) == PcdGetSize (PcdPp2PortIds));
+
+ Pp2Context->Port.Id = PortIds[Pp2Context->Instance];
+ Pp2Context->Port.GopIndex = GopIndexes[Pp2Context->Instance];
+ Pp2Context->Port.PhyInterface = PhyConnectionTypes[Pp2Context->Instance];
+ Pp2Context->Port.AlwaysUp = AlwaysUp[Pp2Context->Instance];
+ Pp2Context->Port.Speed = Speed[Pp2Context->Instance];
+ Pp2Context->Port.GmacBase = PcdGet64 (PcdPp2GmacBaseAddress) +
+ PcdGet32 (PcdPp2GmacDevSize) * Pp2Context->Port.GopIndex;
+ Pp2Context->Port.XlgBase = PcdGet64 (PcdPp2XlgBaseAddress) +
+ PcdGet32 (PcdPp2XlgDevSize) * Pp2Context->Port.GopIndex;
+}
+
+EFI_STATUS
+EFIAPI
+Pp2DxeInitialise (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ PP2DXE_CONTEXT *Pp2Context = NULL;
+ EFI_STATUS Status;
+ INTN Index;
+ VOID *BufferSpace;
+ UINT32 NetCompConfig = 0;
+ UINT8 NumPorts = PcdGet32 (PcdPp2NumPorts);
+
+ if (NumPorts == 0) {
+ DEBUG((DEBUG_ERROR, "Pp2Dxe: port number set to 0\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Initialize private data */
+ Mvpp2Shared = AllocateZeroPool (sizeof (MVPP2_SHARED));
+ if (Mvpp2Shared == NULL) {
+ DEBUG((DEBUG_ERROR, "Allocation fail.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Mvpp2Shared->Base = PcdGet64 (PcdPp2SharedAddress);
+ Mvpp2Shared->Rfu1Base = PcdGet64 (PcdPp2Rfu1BaseAddress);
+ Mvpp2Shared->SmiBase = PcdGet64 (PcdPp2SmiBaseAddress);
+ Mvpp2Shared->Tclk = PcdGet32 (PcdPp2ClockFrequency);
+
+ /* Prepare buffers */
+ BufferSpace = UncachedAllocateAlignedZeroPool (BD_SPACE, MVPP2_BUFFER_ALIGN_SIZE);
+ if (BufferSpace == NULL) {
+ DEBUG((DEBUG_ERROR, "Failed to allocate buffer space\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BufferLocation.TxDescs = BufferSpace;
+ BufferLocation.AggrTxDescs = (MVPP2_TX_DESC *)((UINTN)BufferSpace + MVPP2_MAX_TXD * sizeof(MVPP2_TX_DESC));
+ BufferLocation.RxDescs = (MVPP2_RX_DESC *)((UINTN)BufferSpace +
+ (MVPP2_MAX_TXD + MVPP2_AGGR_TXQ_SIZE) * sizeof(MVPP2_TX_DESC));
+ BufferLocation.RxBuffers = (DmaAddrT)(BufferSpace +
+ (MVPP2_MAX_TXD + MVPP2_AGGR_TXQ_SIZE) * sizeof(MVPP2_TX_DESC) +
+ MVPP2_MAX_RXD * sizeof(MVPP2_RX_DESC));
+
+ /* Initialize HW */
+ Mvpp2AxiConfig(Mvpp2Shared);
+ Pp2DxeBmPoolInit();
+ 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();
+ 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 = BufferLocation.AggrTxDescs;
+ Mvpp2Shared->AggrTxqs->Id = 0;
+ Mvpp2Shared->AggrTxqs->LogId = 0;
+ Mvpp2Shared->AggrTxqs->Size = MVPP2_AGGR_TXQ_SIZE;
+
+ for (Index = 0; Index < NumPorts; Index++) {
+ 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 = Index;
+
+ /* Install SNP protocol */
+ Status = Pp2DxeSnpInstall(Pp2Context);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Pp2DxeParsePortPcd(Pp2Context);
+ Pp2Context->Port.TxpNum = 1;
+ Pp2Context->Port.Priv = Mvpp2Shared;
+ Pp2Context->Port.FirstRxq = 4 * Pp2Context->Instance;
+
+ /* Gather accumulated configuration data of all ports' MAC's */
+ NetCompConfig |= MvpPp2xGop110NetcCfgCreate(&Pp2Context->Port);
+
+ MvGop110PortInit(&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;
+}