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