From: Bartosz Szczepanek bsz@semihalf.com
Pp2Dxe supports Marvell PP2 NIC. It comprise up to 3 ports in a single unit (1x 10G and 2x 2.5G). Also parser and hardware buffer manager offload engines support is enabled, as their usage is obligatory.
EFI_SIMPLE_NETWORK_PROTOCOL is implemented for configurable number of interfaces via PCD.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Bartosz Szczepanek bsz@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Documentation/Marvell/PortingGuide/Pp2.txt | 59 ++ Documentation/Marvell/UserGuide.txt | 1 + Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c | 65 +- Drivers/Net/Pp2Dxe/Pp2Dxe.c | 1191 ++++++++++++++++++++++++++++ Drivers/Net/Pp2Dxe/Pp2Dxe.h | 530 +++++++++++++ Drivers/Net/Pp2Dxe/Pp2Dxe.inf | 91 +++ Platforms/Marvell/Marvell.dec | 18 +- 7 files changed, 1944 insertions(+), 11 deletions(-) create mode 100644 Documentation/Marvell/PortingGuide/Pp2.txt create mode 100644 Drivers/Net/Pp2Dxe/Pp2Dxe.c create mode 100644 Drivers/Net/Pp2Dxe/Pp2Dxe.h create mode 100644 Drivers/Net/Pp2Dxe/Pp2Dxe.inf
diff --git a/Documentation/Marvell/PortingGuide/Pp2.txt b/Documentation/Marvell/PortingGuide/Pp2.txt new file mode 100644 index 0000000..2775d16 --- /dev/null +++ b/Documentation/Marvell/PortingGuide/Pp2.txt @@ -0,0 +1,59 @@ +Pp2Dxe porting guide +-------------------- +Pp2Dxe is driver supporting PP2 NIC on Marvell platforms. Following PCDs +are required to operate: + +Number of ports/network interfaces: + gMarvellTokenSpaceGuid.PcdPp2PortNumber + +Addresses of PHY devices: + gMarvellTokenSpaceGuid.PcdPhySmiAddresses + +Identificators of PP2 ports: + gMarvellTokenSpaceGuid.PcdPp2PortIds + +Indexes used in GOP operation: + gMarvellTokenSpaceGuid.PcdPp2GopIndexes + +Set to 0x1 for always-up interface, 0x0 otherwise: + gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp + +Values corresponding to PHY_SPEED enum: + gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed + +PHY_SPEED is defined as follows: + typedef enum { + 0 NO_SPEED, + 1 SPEED_10, + 2 SPEED_100, + 3 SPEED_1000, + 4 SPEED_2500, + 5 SPEED_10000 + } PHY_SPEED; + +Base address of shared register space of PP2: + gMarvellTokenSpaceGuid.PcdPp2SharedAddress + +Spacing between consecutive GMAC register spaces: + gMarvellTokenSpaceGuid.PcdPp2GmacObjSize + +Base address of GMAC: + gMarvellTokenSpaceGuid.PcdPp2GmacBaseAddress + +Spacing between consecutive XLG register spaces: + gMarvellTokenSpaceGuid.PcdPp2XlgObjSize + +Base address of XLG: + gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress + +Base address of RFU1: + gMarvellTokenSpaceGuid.PcdPp2Rfu1BaseAddress + +Base address of SMI: + gMarvellTokenSpaceGuid.PcdPp2SmiBaseAddress + +TCLK frequency: + gMarvellTokenSpaceGuid.PcdPp2ClockFrequency + +GMAC and XLG addresses are computed as follows: + address = base_address + obj_size * gop_index diff --git a/Documentation/Marvell/UserGuide.txt b/Documentation/Marvell/UserGuide.txt index dd51f8e..c4d2c19 100644 --- a/Documentation/Marvell/UserGuide.txt +++ b/Documentation/Marvell/UserGuide.txt @@ -13,6 +13,7 @@ Table of contents: mdio - PortingGuide/Mdio.txt mpp - PortingGuide/Mpp.txt phy - PortingGuide/Phy.txt + pp2 - PortingGuide/Pp2.txt ramdisk - PortingGuide/Ramdisk.txt reset library - PortingGuide/Reset.txt sata - PortingGuide/Sata.txt diff --git a/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c b/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c index 1c605ac..b697f6f 100644 --- a/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c +++ b/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.c @@ -93,19 +93,19 @@ MvPhyM88e1111sConfig ( { UINT32 Reg;
- if ((PhyDev->Connection == PHY_INTERFACE_MODE_RGMII) || - (PhyDev->Connection == PHY_INTERFACE_MODE_RGMII_ID) || - (PhyDev->Connection == PHY_INTERFACE_MODE_RGMII_RXID) || - (PhyDev->Connection == PHY_INTERFACE_MODE_RGMII_TXID)) { + if ((PhyDev->Connection == PHY_CONNECTION_RGMII) || + (PhyDev->Connection == PHY_CONNECTION_RGMII_ID) || + (PhyDev->Connection == PHY_CONNECTION_RGMII_RXID) || + (PhyDev->Connection == PHY_CONNECTION_RGMII_TXID)) { Reg = Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR); - if ((PhyDev->Connection == PHY_INTERFACE_MODE_RGMII) || - (PhyDev->Connection == PHY_INTERFACE_MODE_RGMII_ID)) { + if ((PhyDev->Connection == PHY_CONNECTION_RGMII) || + (PhyDev->Connection == PHY_CONNECTION_RGMII_ID)) { Reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); - } else if (PhyDev->Connection == PHY_INTERFACE_MODE_RGMII_RXID) { + } else if (PhyDev->Connection == PHY_CONNECTION_RGMII_RXID) { Reg &= ~MIIM_88E1111_TX_DELAY; Reg |= MIIM_88E1111_RX_DELAY; - } else if (PhyDev->Connection == PHY_INTERFACE_MODE_RGMII_TXID) { + } else if (PhyDev->Connection == PHY_CONNECTION_RGMII_TXID) { Reg &= ~MIIM_88E1111_RX_DELAY; Reg |= MIIM_88E1111_TX_DELAY; } @@ -127,7 +127,7 @@ MvPhyM88e1111sConfig ( MIIM_88E1111_PHY_EXT_SR, Reg); }
- if (PhyDev->Connection == PHY_INTERFACE_MODE_SGMII) { + if (PhyDev->Connection == PHY_CONNECTION_SGMII) { Reg = Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_SR);
@@ -139,7 +139,7 @@ MvPhyM88e1111sConfig ( MIIM_88E1111_PHY_EXT_SR, Reg); }
- if (PhyDev->Connection == PHY_INTERFACE_MODE_RTBI) { + if (PhyDev->Connection == PHY_CONNECTION_RTBI) { Reg = Mdio->Read(Mdio, PhyDev->Addr, MIIM_88E1111_PHY_EXT_CR); Reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); @@ -249,6 +249,30 @@ MvPhyParseStatus ( }
STATIC +VOID +MvPhy1518WriteBits ( + IN UINT32 PhyAddr, + IN UINT8 RegNum, + IN UINT16 Offset, + IN UINT16 Len, + IN UINT16 Data) +{ + UINT16 Reg, Mask; + + if ((Len + Offset) >= 16) + Mask = 0 - (1 << Offset); + else + Mask = (1 << (Len + Offset)) - (1 << Offset); + + Reg = Mdio->Read(Mdio, PhyAddr, RegNum); + + Reg &= ~Mask; + Reg |= Data << Offset; + + Mdio->Write(Mdio, PhyAddr, RegNum, Reg); +} + +STATIC EFI_STATUS MvPhyInit1512 ( IN CONST EFI_PHY_PROTOCOL *Snp, @@ -259,6 +283,27 @@ MvPhyInit1512 ( UINT32 Data; INTN i;
+ if (PhyDev->Connection == PHY_CONNECTION_SGMII) { + Mdio->Write(Mdio, PhyAddr, 22, 0x00ff); /* page 0xff */ + Mdio->Write(Mdio, PhyAddr, 17, 0x214B); + Mdio->Write(Mdio, PhyAddr, 16, 0x2144); + Mdio->Write(Mdio, PhyAddr, 17, 0x0C28); + Mdio->Write(Mdio, PhyAddr, 16, 0x2146); + Mdio->Write(Mdio, PhyAddr, 17, 0xB233); + Mdio->Write(Mdio, PhyAddr, 16, 0x214D); + Mdio->Write(Mdio, PhyAddr, 17, 0xCC0C); + Mdio->Write(Mdio, PhyAddr, 16, 0x2159); + Mdio->Write(Mdio, PhyAddr, 22, 0x0000); /* reg page 0 */ + Mdio->Write(Mdio, PhyAddr, 22, 18); /* reg page 18 */ + /* Write HWCFG_MODE = SGMII to Copper */ + MvPhy1518WriteBits(PhyAddr, 20, 0, 3, 1); + + /* Phy reset */ + MvPhy1518WriteBits(PhyAddr, 20, 15, 1, 1); + Mdio->Write(Mdio, PhyAddr, 22, 0); /* reg page 18 */ + gBS->Stall(100); + } + MvPhyM88e1111sConfig (PhyDev);
/* autonegotiation on startup is not always required */ diff --git a/Drivers/Net/Pp2Dxe/Pp2Dxe.c b/Drivers/Net/Pp2Dxe/Pp2Dxe.c new file mode 100644 index 0000000..9287382 --- /dev/null +++ b/Drivers/Net/Pp2Dxe/Pp2Dxe.c @@ -0,0 +1,1191 @@ +/******************************************************************************** +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/DriverBinding.h> +#include <Protocol/SimpleNetwork.h> +#include <Protocol/DevicePath.h> +#include <Protocol/Phy.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/IoLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/NetLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/CacheMaintenanceLib.h> + +#include "Pp2Dxe.h" +#include "mvpp2_lib.h" + +#define ReturnUnlock(tpl, status) do { gBS->RestoreTPL (tpl); return (status); } while(0) +typedef struct { + MAC_ADDR_DEVICE_PATH Pp2Mac; + EFI_DEVICE_PATH_PROTOCOL End; +} PP2_DEVICE_PATH; + +MVPP2_SHARED *Mvpp2Shared; +BUFFER_LOCATION BufferLocation; + +PP2_DEVICE_PATH Pp2DevicePathTemplate = { + { + { + MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, + { (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), (UINT8) ((sizeof(MAC_ADDR_DEVICE_PATH)) >> 8) } + }, + { PP2DXE_DEFAULT_MAC_ADDR }, + 0 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 } + } +}; + +#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 i; + UINT8 *pool_addr; + + for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) { + /* bm_irq_clear */ + mvpp2_bm_irq_clear(Mvpp2Shared, i); + } + + Mvpp2Shared->bm_pools = AllocateZeroPool (sizeof(struct mvpp2_bm_pool)); + + if (!Mvpp2Shared->bm_pools) + return EFI_OUT_OF_RESOURCES; + + pool_addr = AllocateZeroPool ((sizeof(VOID*) * MVPP2_BM_SIZE)*2 + + MVPP2_BM_POOL_PTR_ALIGN); + + if (!pool_addr) { + return EFI_OUT_OF_RESOURCES; + } + if (IS_NOT_ALIGN((UINT64)pool_addr, + MVPP2_BM_POOL_PTR_ALIGN)) + pool_addr = + (UINT8 *)ALIGN_UP((UINT64)pool_addr, + MVPP2_BM_POOL_PTR_ALIGN); + + Mvpp2Shared->bm_pools->id = MVPP2_BM_POOL; + Mvpp2Shared->bm_pools->virt_addr = (MV_U32*)pool_addr; + Mvpp2Shared->bm_pools->phys_addr = (UINT64)pool_addr; + + mvpp2_bm_pool_hw_create(Mvpp2Shared, Mvpp2Shared->bm_pools, MVPP2_BM_SIZE); + + return EFI_SUCCESS; +} + +/* + * mvpp2_bm_start + * enable and fill BM pool + */ +STATIC +EFI_STATUS +Pp2DxeBmStart ( + VOID + ) +{ + UINT8 *buff, *buff_phys; + INTN i; + + mvpp2_bm_pool_ctrl(Mvpp2Shared, MVPP2_BM_POOL, MVPP2_START); + + mvpp2_bm_pool_bufsize_set(Mvpp2Shared, Mvpp2Shared->bm_pools, RX_BUFFER_SIZE); + + /* fill BM pool with buffers */ + for (i = 0; i < MVPP2_BM_SIZE; i++) { + buff = (UINT8 *)(BufferLocation.rx_buffers + + (i * RX_BUFFER_SIZE)); + if (!buff) + return EFI_OUT_OF_RESOURCES; + + buff_phys = (UINT8 *)ALIGN_UP((UINT64)buff, + BM_ALIGN); + mvpp2_bm_pool_put(Mvpp2Shared, MVPP2_BM_POOL, + (UINT64)buff_phys, (UINT64)buff_phys); + } + + return EFI_SUCCESS; +} + +STATIC +VOID +Pp2DxeStartDev ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + PP2DXE_PORT *Port = &Pp2Context->Port; + + mvpp2_ingress_enable(Port); + + /* Config classifier decoding table */ + mvpp2_cls_port_config(Port); + mvpp2_cls_oversize_rxq_set(Port); + mv_gop110_port_events_mask(Port); + mv_gop110_port_enable(Port); + + gBS->Stall(2000); + mvpp2_egress_enable(Port); +} + +STATIC +EFI_STATUS +Pp2DxeSetupRxqs ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + INTN Queue; + EFI_STATUS Status; + struct mvpp2_rx_queue *rxq; + + for (Queue = 0; Queue < rxq_number; Queue++) { + rxq = &Pp2Context->Port.rxqs[Queue]; + rxq->descs_phys = (dma_addr_t)rxq->descs; + if (!rxq->descs) { + Status = EFI_OUT_OF_RESOURCES; + goto err_cleanup; + } + + mvpp2_rxq_hw_init(&Pp2Context->Port, rxq); + } + + return EFI_SUCCESS; + +err_cleanup: + mvpp2_cleanup_rxqs(&Pp2Context->Port); + return Status; +} + +STATIC +EFI_STATUS +Pp2DxeSetupTxqs ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + INTN Queue; + struct mvpp2_tx_queue *txq; + EFI_STATUS Status; + + for (Queue = 0; Queue < txq_number; Queue++) { + txq = &Pp2Context->Port.txqs[Queue]; + txq->descs_phys = (dma_addr_t) txq->descs; + if (!txq->descs_phys) { + Status = EFI_OUT_OF_RESOURCES; + goto err_cleanup; + } + mvpp2_txq_hw_init(&Pp2Context->Port, txq); + } + + return EFI_SUCCESS; + +err_cleanup: + mvpp2_cleanup_txqs(&Pp2Context->Port); + return Status; +} + +STATIC +EFI_STATUS +Pp2DxeSetupAggrTxqs ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + struct mvpp2_tx_queue *aggr_txq; + + aggr_txq = Mvpp2Shared->aggr_txqs; + aggr_txq->descs_phys = (dma_addr_t)aggr_txq->descs; + if (!aggr_txq->descs) + return EFI_OUT_OF_RESOURCES; + mvpp2_aggr_txq_hw_init(aggr_txq, aggr_txq->size, 0, Mvpp2Shared); + return EFI_SUCCESS; + +} + +STATIC +EFI_STATUS +Pp2DxeOpen ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + PP2DXE_PORT *Port = &Pp2Context->Port; + UINT8 mac_bcast[NET_ETHER_ADDR_LEN] = { 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff }; + UINT8 dev_addr[NET_ETHER_ADDR_LEN]; + INTN ret; + EFI_STATUS Status; + + DEBUG((DEBUG_INFO, "Pp2Dxe: Open\n")); + + CopyMem (dev_addr, Pp2Context->Snp.Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN); + + ret = mvpp2_prs_mac_da_accept(Mvpp2Shared, Port->id, mac_bcast, TRUE); + if (ret) { + return EFI_DEVICE_ERROR; + } + ret = mvpp2_prs_mac_da_accept(Mvpp2Shared, Port->id, dev_addr, TRUE); + if (ret) { + return EFI_DEVICE_ERROR; + } + ret = mvpp2_prs_tag_mode_set(Mvpp2Shared, Port->id, MVPP2_TAG_TYPE_MH); + if (ret) { + return EFI_DEVICE_ERROR; + } + ret = mvpp2_prs_def_flow(Port); + if (ret) { + 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; + + DEBUG((DEBUG_INFO, "Pp2Dxe: LatePortInitialize\n")); + Port->tx_ring_size = MVPP2_MAX_TXD; + Port->rx_ring_size = MVPP2_MAX_RXD; + + mvpp2_egress_disable(Port); + mv_gop110_port_events_mask(Port); + mv_gop110_port_disable(Port); + + Port->txqs = AllocateZeroPool (sizeof(struct mvpp2_tx_queue) * txq_number); + 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.tx_descs; + + for (Queue = 0; Queue < txq_number; Queue++) { + struct mvpp2_tx_queue *txq = &Port->txqs[Queue]; + + txq->id = mvpp2_txq_phys(Port->id, Queue); + txq->log_id = Queue; + txq->size = Port->tx_ring_size; + } + + Port->rxqs = AllocateZeroPool (sizeof(struct mvpp2_rx_queue) * rxq_number); + if (Port->rxqs == NULL) { + DEBUG((DEBUG_ERROR, "Failed to allocate rxqs\n")); + return EFI_OUT_OF_RESOURCES; + } + + Port->rxqs[0].descs = BufferLocation.rx_descs; + + for (Queue = 0; Queue < txq_number; Queue++) { + struct mvpp2_rx_queue *rxq = &Port->rxqs[Queue]; + + rxq->id = Queue + Port->first_rxq; + rxq->size = Port->rx_ring_size; + } + + mvpp2_ingress_disable(Port); + + mvpp2_defaults_set(Port); + + return Pp2DxeOpen(Pp2Context); +} + +STATIC +EFI_STATUS +Pp2DxeLateInitialize ( + IN PP2DXE_CONTEXT *Pp2Context + ) +{ + PP2DXE_PORT *Port = &Pp2Context->Port; + EFI_STATUS Status; + + DEBUG((DEBUG_INFO, "Pp2Dxe: Pp2DxeLateInitialize\n")); + + 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 */ + mvpp2_rxq_long_pool_set(Port, 0, MVPP2_BM_POOL); + mvpp2_rxq_short_pool_set(Port, 0, MVPP2_BM_POOL); + /* mark this port being fully inited, + * 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 */ + mv_gop110_port_events_mask(Port); + mv_gop110_port_enable(Port); + } + return 0; +} + +EFI_STATUS +Pp2DxePhyInitialize ( + PP2DXE_CONTEXT *Pp2Context + ) +{ + EFI_STATUS Status; + UINT8 *PhyAddresses; + + PhyAddresses = PcdGetPtr (PcdPhySmiAddresses); + Status = gBS->LocateProtocol ( + &gEfiPhyProtocolGuid, + 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.phy_interface, + &Pp2Context->PhyDev + ); + if (EFI_ERROR(Status) && Status != EFI_TIMEOUT) + return Status; + Pp2Context->Phy->Status(Pp2Context->Phy, Pp2Context->PhyDev); + DEBUG((DEBUG_INFO, + "PHY%d: ", + Pp2Context->PhyDev->Addr)); + DEBUG((DEBUG_INFO, + Pp2Context->PhyDev->LinkUp ? "link up, " : "link down, ")); + DEBUG((DEBUG_INFO, + Pp2Context->PhyDev->FullDuplex ? "full duplex, " : "half duplex, ")); + DEBUG((DEBUG_INFO, + Pp2Context->PhyDev->Speed == SPEED_10 ? "speed 10\n" : (Pp2Context->PhyDev->Speed == SPEED_100 ? "speed 100\n" : "speed 1000\n"))); + + mvpp2_smi_phy_addr_cfg(&Pp2Context->Port, Pp2Context->Port.gop_index, 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); + EFI_TPL SavedTpl; + + DEBUG((DEBUG_INFO, "Pp2Dxe%d: initialize\n", Pp2Context->Instance)); + 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); + + switch (This->Mode->State) { + case EfiSimpleNetworkStarted: + DEBUG((DEBUG_INFO, "Pp2Dxe%d: started state\n", Pp2Context->Instance)); + break; + case EfiSimpleNetworkInitialized: + DEBUG((DEBUG_INFO, "Pp2Dxe%d: already initialized\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_SUCCESS); + case EfiSimpleNetworkStopped: + DEBUG((DEBUG_INFO, "Pp2Dxe%d: network stopped\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_NOT_STARTED); + default: + DEBUG((DEBUG_INFO, "Pp2Dxe%d: wrong state\n", Pp2Context->Instance)); + ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR); + } + + This->Mode->State = EfiSimpleNetworkInitialized; + + if (Pp2Context->Initialized) + ReturnUnlock(SavedTpl, EFI_SUCCESS); + + Pp2Context->Initialized = TRUE; + + Status = Pp2DxePhyInitialize(Pp2Context); + if (EFI_ERROR(Status)) + ReturnUnlock (SavedTpl, Status); + + ReturnUnlock (SavedTpl, Pp2DxeLateInitialize(Pp2Context)); +} + +EFI_STATUS +EFIAPI +Pp2SnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ) +{ + PP2DXE_CONTEXT *Pp2Context; + EFI_TPL SavedTpl; + + SavedTpl = gBS->RaiseTPL (TPL_CALLBACK); + Pp2Context = INSTANCE_FROM_SNP(This); + + DEBUG((DEBUG_INFO, "Pp2Dxe%d: started\n", Pp2Context->Instance)); + switch (This->Mode->State) { + case EfiSimpleNetworkStopped: + DEBUG((DEBUG_INFO, "Pp2Dxe%d: stopped state\n", Pp2Context->Instance)); + break; + case EfiSimpleNetworkStarted: + case EfiSimpleNetworkInitialized: + DEBUG((DEBUG_INFO, "Pp2Dxe: Driver already started\n")); + ReturnUnlock (SavedTpl, EFI_ALREADY_STARTED); + default: + DEBUG((DEBUG_ERROR, "Pp2Dxe: Driver in an invalid state: %u\n", + (UINTN)This->Mode->State)); + 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); + + DEBUG((DEBUG_INFO, "Pp2SnpStop \n")); + switch (This->Mode->State) { + case EfiSimpleNetworkStarted: + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStopped: + ReturnUnlock (SavedTpl, EFI_NOT_STARTED); + default: + 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 + ) +{ + DEBUG((DEBUG_INFO, "Pp2SnpReset \n")); + 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) { + mvpp2_bm_stop(Mvpp2Shared, MVPP2_BM_POOL); + CommonPartHalted = TRUE; + } + mvpp2_txq_drain_set(Port, 0, TRUE); + mvpp2_ingress_disable(Port); + mvpp2_egress_disable(Port); + + mv_gop110_port_events_mask(Port); + mv_gop110_port_disable(Port); +} + +EFI_STATUS +EFIAPI +Pp2SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ) +{ + EFI_TPL SavedTpl; + SavedTpl = gBS->RaiseTPL (TPL_CALLBACK); + + switch (This->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + ReturnUnlock (SavedTpl, EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + ReturnUnlock (SavedTpl, EFI_NOT_STARTED); + default: + 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 + ) +{ + DEBUG((DEBUG_INFO, "Pp2SnpReceiveFilt \n")); + 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 + ) +{ + DEBUG((DEBUG_INFO, "Pp2SnpNetStat \n")); + 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 + ) +{ + DEBUG((DEBUG_INFO, "Pp2SnpIpToMac \n")); + 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 + ) +{ + DEBUG((DEBUG_INFO, "Pp2SnpNvData \n")); + 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->always_up ? TRUE : mv_gop110_port_is_link_up(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 *ProtocolPtr OPTIONAL + ) +{ + PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This); + PP2DXE_PORT *Port = &Pp2Context->Port; + struct mvpp2_tx_queue *aggr_txq = Mvpp2Shared->aggr_txqs; + struct mvpp2_tx_desc *tx_desc; + INTN timeout = 0; + INTN tx_done; + UINT8 *DataPtr = Buffer; + UINT16 Protocol; + 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 (ProtocolPtr != NULL); + ASSERT (DestAddr != NULL); + } + + SavedTpl = gBS->RaiseTPL (TPL_CALLBACK); + + switch (This->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG((DEBUG_WARN, "Pp2Dxe: Driver not yet initialized\n")); + ReturnUnlock(SavedTpl, EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG((DEBUG_WARN, "Pp2Dxe: Driver not started\n")); + ReturnUnlock(SavedTpl, EFI_NOT_STARTED); + default: + DEBUG((DEBUG_ERROR, "Pp2Dxe: Driver in an invalid state\n")); + ReturnUnlock(SavedTpl, EFI_DEVICE_ERROR); + } + + if (!This->Mode->MediaPresent) { + DEBUG((DEBUG_ERROR, "Pp2Dxe: link not ready\n")); + ReturnUnlock(SavedTpl, EFI_NOT_READY); + } + + Protocol = HTONS(*ProtocolPtr); + + tx_desc = mvpp2_txq_next_desc_get(aggr_txq); + + if (!tx_desc) { + 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, &Protocol, 2); + } + + /* set descriptor fields */ + tx_desc->command = MVPP2_TXD_IP_CSUM_DISABLE | + MVPP2_TXD_L4_CSUM_NOT | MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC; + tx_desc->data_size = BufferSize; + + tx_desc->packet_offset = (phys_addr_t)DataPtr & MVPP2_TX_DESC_ALIGN; + + mvpp2x2_txdesc_phys_addr_set( + (phys_addr_t)DataPtr & ~MVPP2_TX_DESC_ALIGN, tx_desc); + tx_desc->phys_txq = mvpp2_txq_phys(Port->id, 0); + + InvalidateDataCacheRange (DataPtr, BufferSize); + + /* iowmb */ + __asm__ __volatile__ ("" : : : "memory"); + /* send */ + mvpp2_aggr_txq_pend_desc_add(Port, 1); + + /* Tx done processing */ + /* wait for agrregated to physical TXQ transfer */ + tx_done = mvpp2_aggr_txq_pend_desc_num_get(Mvpp2Shared, 0); + do { + if (timeout++ > MVPP2_TX_SEND_TIMEOUT) { + DEBUG((DEBUG_ERROR, "Pp2Dxe: transmit timeout\n")); + ReturnUnlock(SavedTpl, EFI_TIMEOUT); + } + tx_done = mvpp2_aggr_txq_pend_desc_num_get(Mvpp2Shared, 0); + } while (tx_done); + + timeout = 0; + tx_done = mvpp2_txq_sent_desc_proc(Port, &Port->txqs[0]); + /* wait for packet to be transmitted */ + while (!tx_done) { + if (timeout++ > MVPP2_TX_SEND_TIMEOUT) { + DEBUG((DEBUG_ERROR, "Pp2Dxe: transmit timeout\n")); + ReturnUnlock(SavedTpl, EFI_TIMEOUT); + } + tx_done = mvpp2_txq_sent_desc_proc(Port, &Port->txqs[0]); + } + /* tx_done has increased - hw sent packet */ + + /* add buffer to completion queue and return */ + ReturnUnlock (SavedTpl, QueueInsert (Pp2Context, Buffer)); +} + +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 *Protocol OPTIONAL + ) +{ + INTN ReceivedPackets; + PP2DXE_CONTEXT *Pp2Context = INSTANCE_FROM_SNP(This); + PP2DXE_PORT *Port = &Pp2Context->Port; + UINT64 PhysAddr, VirtAddr; + EFI_STATUS Status = EFI_SUCCESS; + EFI_TPL SavedTpl; + UINT32 StatusReg; + INTN PoolId; + UINTN PktLength; + UINT8 *DataPtr; + struct mvpp2_rx_desc *RxDesc; + struct mvpp2_rx_queue *Rxq = &Port->rxqs[0]; + + SavedTpl = gBS->RaiseTPL (TPL_CALLBACK); + ReceivedPackets = mvpp2_rxq_received(Port, Rxq->id); + + if (ReceivedPackets == 0) { + ReturnUnlock(SavedTpl, EFI_NOT_READY); + } + + /* process one packet per call */ + RxDesc = mvpp2_rxq_next_desc_get(Rxq); + + StatusReg = RxDesc->status; + + /* extract addresses from descriptor */ + PhysAddr = RxDesc->buf_phys_addr_key_hash & + MVPP22_ADDR_MASK; + VirtAddr = RxDesc->buf_cookie_bm_qset_cls_info & + 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->data_size - 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 = (UINT8 *)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); + } + + /* get the protocol */ + if (Protocol != NULL) { + *Protocol = 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; + mvpp2_bm_pool_put(Mvpp2Shared, PoolId, PhysAddr, VirtAddr); + + /* iowmb */ + __asm__ __volatile__ ("" : : : "memory"); + + ASSERT (Port != NULL); + ASSERT (Rxq != NULL); + mvpp2_rxq_status_update(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; + + DEBUG((DEBUG_INFO, "Pp2Dxe%d: Installing protocols\n", Pp2Context->Instance)); + Pp2Context->Snp.Mode = AllocateZeroPool (sizeof (EFI_SIMPLE_NETWORK_MODE)); + Pp2DevicePath = AllocateCopyPool (sizeof (PP2_DEVICE_PATH), &Pp2DevicePathTemplate); + /* change MAC address depending on interface */ + Pp2DevicePath->Pp2Mac.MacAddress.Addr[5] += Pp2Context->Instance; + Pp2Context->Signature = PP2DXE_SIGNATURE; + Pp2Context->Snp.Initialize = Pp2DxeSnpInitialize; + Pp2Context->Snp.Start = Pp2SnpStart; + Pp2Context->Snp.Stop = Pp2SnpStop; + Pp2Context->Snp.Reset = Pp2SnpReset; + Pp2Context->Snp.Shutdown = Pp2SnpShutdown; + Pp2Context->Snp.ReceiveFilters = Pp2SnpReceiveFilters; + Pp2Context->Snp.Statistics = Pp2SnpNetStat; + Pp2Context->Snp.MCastIpToMac = Pp2SnpIpToMac; + Pp2Context->Snp.NvData = Pp2SnpNvData; + Pp2Context->Snp.GetStatus = Pp2SnpGetStatus; + Pp2Context->Snp.Transmit = Pp2SnpTransmit; + Pp2Context->Snp.Receive = Pp2SnpReceive; + Pp2Context->Snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; + + Pp2Context->Snp.Mode->CurrentAddress = Pp2DevicePath->Pp2Mac.MacAddress; + Pp2Context->Snp.Mode->PermanentAddress = Pp2DevicePath->Pp2Mac.MacAddress; + Pp2Context->Snp.Mode->State = EfiSimpleNetworkStopped; + Pp2Context->Snp.Mode->IfType = NET_IFTYPE_ETHERNET; + Pp2Context->Snp.Mode->HwAddressSize = NET_ETHER_ADDR_LEN; + Pp2Context->Snp.Mode->MediaHeaderSize = sizeof (ETHER_HEAD); + Pp2Context->Snp.Mode->MaxPacketSize = EFI_PAGE_SIZE; + Pp2Context->Snp.Mode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; + Pp2Context->Snp.Mode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + Pp2Context->Snp.Mode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT; + Pp2Context->Snp.Mode->MCastFilterCount = 0; + Pp2Context->Snp.Mode->MediaPresentSupported = TRUE; + Pp2Context->Snp.Mode->MediaPresent = FALSE; + ZeroMem (&Pp2Context->Snp.Mode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_ADDRESS)); + SetMem (&Pp2Context->Snp.Mode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF); + + Pp2DevicePath->Pp2Mac.IfType = Pp2Context->Snp.Mode->IfType; + 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.gop_index = GopIndexes[Pp2Context->Instance]; + Pp2Context->Port.phy_interface = PhyConnectionTypes[Pp2Context->Instance]; + Pp2Context->Port.always_up = AlwaysUp[Pp2Context->Instance]; + Pp2Context->Port.speed = Speed[Pp2Context->Instance]; + Pp2Context->Port.gmac_base = PcdGet64 (PcdPp2GmacBaseAddress) + + PcdGet32 (PcdPp2GmacObjSize) * Pp2Context->Port.gop_index; + Pp2Context->Port.xlg_base = PcdGet64 (PcdPp2XlgBaseAddress) + + PcdGet32 (PcdPp2XlgObjSize) * Pp2Context->Port.gop_index; +} + +EFI_STATUS +EFIAPI +Pp2DxeInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + PP2DXE_CONTEXT *Pp2Context = NULL; + EFI_STATUS Status; + INTN i; + VOID *BufferSpace; + UINT32 NetCompConfig = 0; + + Mvpp2Shared = AllocateZeroPool (sizeof (MVPP2_SHARED)); + if (Mvpp2Shared == NULL) { + DEBUG((DEBUG_ERROR, "Allocation fail.\n")); + return EFI_OUT_OF_RESOURCES; + } + + Mvpp2Shared->base = PcdGet64 (PcdPp2SharedAddress); + Mvpp2Shared->rfu1_base = PcdGet64 (PcdPp2Rfu1BaseAddress); + Mvpp2Shared->smi_base = PcdGet64 (PcdPp2SmiBaseAddress); + Mvpp2Shared->tclk = PcdGet32 (PcdPp2ClockFrequency); + DEBUG((DEBUG_INFO, "Pp2Dxe: shared base is 0x%lx\n", Mvpp2Shared->base)); + DEBUG((DEBUG_INFO, "Pp2Dxe: RFU1 base is 0x%lx\n", Mvpp2Shared->rfu1_base)); + DEBUG((DEBUG_INFO, "Pp2Dxe: SMI base is 0x%lx\n", Mvpp2Shared->smi_base)); + + BufferSpace = UncachedAllocateAlignedPool (BD_SPACE, MVPP2_BUFFER_ALIGN_SIZE); + if (BufferSpace == NULL) { + DEBUG((DEBUG_ERROR, "Failed to allocate buffer space\n")); + return EFI_OUT_OF_RESOURCES; + } + SetMem (BufferSpace, BD_SPACE, 0x0); + + BufferLocation.tx_descs = (struct mvpp2_tx_desc *)BufferSpace; + + BufferLocation.aggr_tx_descs = (struct mvpp2_tx_desc *) + ((UINT64)BufferSpace + MVPP2_MAX_TXD + * sizeof(struct mvpp2_tx_desc)); + + BufferLocation.rx_descs = (struct mvpp2_rx_desc *) + ((UINT64)BufferSpace + + (MVPP2_MAX_TXD + MVPP2_AGGR_TXQ_SIZE) + * sizeof(struct mvpp2_tx_desc)); + + BufferLocation.rx_buffers = (UINT64) + (BufferSpace + (MVPP2_MAX_TXD + MVPP2_AGGR_TXQ_SIZE) + * sizeof(struct mvpp2_tx_desc) + + MVPP2_MAX_RXD * sizeof(struct mvpp2_rx_desc)); + + mvpp2_axi_config(Mvpp2Shared); + Pp2DxeBmPoolInit(); + mvpp2_rx_fifo_init(Mvpp2Shared); + + Mvpp2Shared->prs_shadow = AllocateZeroPool (sizeof(struct mvpp2_prs_shadow) + * MVPP2_PRS_TCAM_SRAM_SIZE); + if (Mvpp2Shared->prs_shadow == NULL) { + DEBUG((DEBUG_ERROR, "Failed to allocate prs_shadow\n")); + return EFI_OUT_OF_RESOURCES; + } + + if (mvpp2_prs_default_init(Mvpp2Shared)) { + DEBUG((DEBUG_ERROR, "Failed to intialize prs\n")); + return EFI_DEVICE_ERROR; + } + + mvpp2_cls_init(Mvpp2Shared); + + Status = Pp2DxeBmStart(); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Pp2Dxe: bm start error\n")); + return Status; + } + + mvpp2_write(Mvpp2Shared, MVPP22_AXI_BM_WR_ATTR_REG, + MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + mvpp2_write(Mvpp2Shared, MVPP22_AXI_BM_RD_ATTR_REG, + MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + mvpp2_write(Mvpp2Shared, MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG, + MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + mvpp2_write(Mvpp2Shared, MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG, + MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + mvpp2_write(Mvpp2Shared, MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG, + MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + mvpp2_write(Mvpp2Shared, MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG, + MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + mvpp2_write(Mvpp2Shared, MVPP22_AXI_RX_DATA_WR_ATTR_REG, + MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + mvpp2_write(Mvpp2Shared, MVPP22_AXI_TX_DATA_RD_ATTR_REG, + MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT); + + Mvpp2Shared->aggr_txqs = AllocateZeroPool (sizeof(struct mvpp2_tx_queue)); + if (Mvpp2Shared->aggr_txqs == NULL) { + DEBUG((DEBUG_ERROR, "Failed to allocate aggregated txqs\n")); + return EFI_OUT_OF_RESOURCES; + } + + Mvpp2Shared->aggr_txqs->descs = BufferLocation.aggr_tx_descs; + Mvpp2Shared->aggr_txqs->id = 0; + Mvpp2Shared->aggr_txqs->log_id = 0; + Mvpp2Shared->aggr_txqs->size = MVPP2_AGGR_TXQ_SIZE; + + if (PcdGet32 (PcdPp2PortNumber) == 0) { + DEBUG((DEBUG_ERROR, "Pp2Dxe: port number set to 0\n")); + return EFI_INVALID_PARAMETER; + } + + for (i = 0; i < PcdGet32 (PcdPp2PortNumber); i++) { + + 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 = i; + + /* Install SNP protocol */ + Status = Pp2DxeSnpInstall(Pp2Context); + + if (EFI_ERROR(Status)) + return Status; + + Pp2DxeParsePortPcd(Pp2Context); + Pp2Context->Port.txp_num = 1; + Pp2Context->Port.priv = Mvpp2Shared; + Pp2Context->Port.first_rxq = 4 * Pp2Context->Instance; + DEBUG((DEBUG_INFO, "Pp2Dxe%d: port%d - gmac at 0x%lx, xlg at 0x%lx\n", Pp2Context->Instance, Pp2Context->Port.id, + Pp2Context->Port.gmac_base, Pp2Context->Port.xlg_base)); + + NetCompConfig |= mvp_pp2x_gop110_netc_cfg_create(&Pp2Context->Port); + + mv_gop110_port_init(&Pp2Context->Port); + mv_gop110_fl_cfg(&Pp2Context->Port); + + Status = gBS->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, + TPL_NOTIFY, + Pp2DxeHalt, + Pp2Context, + &Pp2Context->EfiExitBootServicesEvent); + + if (EFI_ERROR(Status)) + return Status; + } + + mv_gop110_netc_init(&Pp2Context->Port, NetCompConfig, + MV_NETC_FIRST_PHASE); + mv_gop110_netc_init(&Pp2Context->Port, NetCompConfig, + MV_NETC_SECOND_PHASE); + + return EFI_SUCCESS; +} diff --git a/Drivers/Net/Pp2Dxe/Pp2Dxe.h b/Drivers/Net/Pp2Dxe/Pp2Dxe.h new file mode 100644 index 0000000..00c79cc --- /dev/null +++ b/Drivers/Net/Pp2Dxe/Pp2Dxe.h @@ -0,0 +1,530 @@ +/******************************************************************************** +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. + +*******************************************************************************/ + +#ifndef __PP2_DXE_H__ +#define __PP2_DXE_H__ + +#include <Protocol/Cpu.h> +#include <Protocol/DriverBinding.h> +#include <Protocol/SimpleNetwork.h> +#include <Protocol/DevicePath.h> +#include <Protocol/Phy.h> +#include <Protocol/Ip4.h> +#include <Protocol/Ip6.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UncachedMemoryAllocationLib.h> +#include <Library/IoLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/NetLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiBootServicesTableLib.h> + +#define PP2DXE_MAX_PHY 2 + +#define PP2DXE_DEFAULT_MAC_ADDR { 0x0, 0xaf, 0x1c, 0xdd, 0xe, 0x2 } + +#define MVPP2_TX_SEND_TIMEOUT 10000 + +#define NET_SKB_PAD 0 +#define PP2DXE_SIGNATURE SIGNATURE_32('P', 'P', '2', 'D') +#define INSTANCE_FROM_SNP(a) CR((a), PP2DXE_CONTEXT, Snp, PP2DXE_SIGNATURE) + +/* RX buffer constants */ +#define MVPP2_SKB_SHINFO_SIZE \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + +#define MVPP2_RX_PKT_SIZE(mtu) \ + ALIGN((mtu) + MVPP2_MH_SIZE + MVPP2_VLAN_TAG_LEN + \ + ETH_HLEN + ETH_FCS_LEN, MVPP2_CPU_D_CACHE_LINE_SIZE) + +#define MVPP2_RX_BUF_SIZE(pkt_size) ((pkt_size) + NET_SKB_PAD) +#define MVPP2_RX_TOTAL_SIZE(buf_size) ((buf_size) + MVPP2_SKB_SHINFO_SIZE) +#define MVPP2_RX_MAX_PKT_SIZE(total_size) \ + ((total_size) - NET_SKB_PAD - MVPP2_SKB_SHINFO_SIZE) +#define MVPP2_RXQ_OFFSET NET_SKB_PAD + +#define IS_NOT_ALIGN(number, align) ((number) & ((align) - 1)) +/* Macro for alignment up. For example, ALIGN_UP(0x0330, 0x20) = 0x0340 */ +#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) +#define ALIGN_UP(number, align) (((number) & ((align) - 1)) ? \ + (((number) + (align)) & ~((align)-1)) : (number)) + +/* Linux API */ +#define mvpp2_alloc(v) AllocateZeroPool(v) +#define mvpp2_free(p) FreePool(p) +#define mvpp2_memset(a, v, s) SetMem((a), (s), (v)) +#define mvpp2_mdelay(t) gBS->Stall((t)*1000) +#define mvpp2_prefetch(v) do {} while(0); +#define mvpp2_fls(v) 1 +#define mvpp2_is_broadcast_ether_addr(da) \ + 1 +#define mvpp2_is_multicast_ether_addr(da) \ + 1 +#define mvpp2_printf(...) do {} while(0); +#define mvpp2_swap(a,b) do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) +#define mvpp2_swab16(x) \ + ((UINT16)( \ + (((UINT16)(x) & (UINT16)0x00ffU) << 8) | \ + (((UINT16)(x) & (UINT16)0xff00U) >> 8) )) +#define mvpp2_iphdr EFI_IP4_HEADER +#define mvpp2_ipv6hdr EFI_IP6_HEADER +#define MVPP2_ALIGN(x, m) ALIGN((x), (m)) +#define MVPP2_ALIGN_UP(number, align) ALIGN_UP((number), (align)) +#define MVPP2_NULL NULL +#define MVPP2_ENOMEM -1 +#define MVPP2_EINVAL -2 +#define MVPP2_ERANGE -3 +#define MVPP2_USEC_PER_SEC 1000000L + +#define dma_addr_t UINT64 +#define phys_addr_t UINT64 + +#define upper_32_bits(n) ((MV_U32)(((n) >> 16) >> 16)) +#define lower_32_bits(n) ((MV_U32)(n)) + +/* Port speeds */ +#define MV_PORT_SPEED_10 SPEED_10 +#define MV_PORT_SPEED_100 SPEED_100 +#define MV_PORT_SPEED_1000 SPEED_1000 +#define MV_PORT_SPEED_2500 SPEED_2500 +#define MV_PORT_SPEED_10000 SPEED_10000 + +/* L2 and L3 protocol macros */ +#define MV_IPPR_TCP 0 +#define MV_IPPR_UDP 1 +#define MV_IPPR_IPIP 2 +#define MV_IPPR_ICMPV6 3 +#define MV_IPPR_IGMP 4 +#define MV_ETH_P_IP 5 +#define MV_ETH_P_IPV6 6 +#define MV_ETH_P_PPP_SES 7 +#define MV_ETH_P_ARP 8 +#define MV_ETH_P_8021Q 9 +#define MV_ETH_P_8021AD 10 +#define MV_ETH_P_EDSA 11 +#define MV_PPP_IP 12 +#define MV_PPP_IPV6 13 +#define MV_ETH_ALEN 6 + +/* PHY modes */ +#define MV_MODE_SGMII PHY_CONNECTION_SGMII +#define MV_MODE_RGMII PHY_CONNECTION_RGMII +#define MV_MODE_XAUI PHY_CONNECTION_XAUI +#define MV_MODE_RXAUI PHY_CONNECTION_RXAUI +#define MV_MODE_QSGMII 100 + +/* AXI Bridge Registers */ +#define MVPP22_AXI_BM_WR_ATTR_REG 0x4100 +#define MVPP22_AXI_BM_RD_ATTR_REG 0x4104 +#define MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG 0x4110 +#define MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG 0x4114 +#define MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG 0x4118 +#define MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG 0x411c +#define MVPP22_AXI_RX_DATA_WR_ATTR_REG 0x4120 +#define MVPP22_AXI_TX_DATA_RD_ATTR_REG 0x4130 +#define MVPP22_AXI_RD_NORMAL_CODE_REG 0x4150 +#define MVPP22_AXI_RD_SNP_CODE_REG 0x4154 +#define MVPP22_AXI_WR_NORMAL_CODE_REG 0x4160 +#define MVPP22_AXI_WR_SNP_CODE_REG 0x4164 + +#define MVPP22_AXI_RD_CODE_MASK 0x33 +#define MVPP22_AXI_WR_CODE_MASK 0x33 + +#define MVPP22_AXI_ATTR_CACHE_OFFS 0 +#define MVPP22_AXI_ATTR_CACHE_SIZE 4 +#define MVPP22_AXI_ATTR_CACHE_MASK 0x0000000F + +#define MVPP22_AXI_ATTR_QOS_OFFS 4 +#define MVPP22_AXI_ATTR_QOS_SIZE 4 +#define MVPP22_AXI_ATTR_QOS_MASK 0x000000F0 + +#define MVPP22_AXI_ATTR_TC_OFFS 8 +#define MVPP22_AXI_ATTR_TC_SIZE 4 +#define MVPP22_AXI_ATTR_TC_MASK 0x00000F00 + +#define MVPP22_AXI_ATTR_DOMAIN_OFFS 12 +#define MVPP22_AXI_ATTR_DOMAIN_SIZE 2 +#define MVPP22_AXI_ATTR_DOMAIN_MASK 0x00003000 + +#define MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT BIT(16) + +/* Gop related define */ +/* Sets the field located at the specified in data. */ +#define U32_SET_FIELD(data, mask, val) \ + ((data) = (((data) & ~(mask)) | (val))) +#define MV_RGMII_TX_FIFO_MIN_TH (0x41) +#define MV_SGMII_TX_FIFO_MIN_TH (0x5) +#define MV_SGMII2_5_TX_FIFO_MIN_TH (0xB) + +/* BM configuration */ +#define MVPP2_BM_POOL 0 +#define MVPP2_BM_SIZE 32 + +/* BM constants */ +#define MVPP2_BM_POOLS_NUM 8 +#define MVPP2_BM_LONG_BUF_NUM 1024 +#define MVPP2_BM_SHORT_BUF_NUM 2048 +#define MVPP2_BM_POOL_SIZE_MAX (16*1024 - MVPP2_BM_POOL_PTR_ALIGN/4) +#define MVPP2_BM_POOL_PTR_ALIGN 128 +#define MVPP2_BM_SWF_LONG_POOL(port) ((port > 2) ? 2 : port) +#define MVPP2_BM_SWF_SHORT_POOL 3 + +/* BM cookie (32 bits) definition */ +#define MVPP2_BM_COOKIE_POOL_OFFS 8 +#define MVPP2_BM_COOKIE_CPU_OFFS 24 + +/* + * Page table entries are set to 1MB, or multiples of 1MB + * (not < 1MB). driver uses less bd's so use 1MB bdspace. + */ +#define BD_SPACE (1 << 20) + +/* buffer has to be aligned to 1M */ +#define MVPP2_BUFFER_ALIGN_SIZE (1 << 20) +/* Types */ +typedef INT8 MV_8; +typedef UINT8 MV_U8; + +typedef INT16 MV_16; +typedef UINT16 MV_U16; + +typedef INT32 MV_32; +typedef UINT32 MV_U32; + +typedef INT64 MV_64; +typedef UINT64 MV_U64; + +typedef INTN MV_LONG; /* 32/64 */ +typedef UINTN MV_ULONG; /* 32/64 */ + +typedef BOOLEAN MV_BOOL; +typedef VOID MV_VOID; + +typedef EFI_STATUS MV_STATUS; + +#define MV_TRUE TRUE +#define MV_FALSE FALSE + +#define __iomem + +enum mvpp2_command { + MVPP2_START, /* Start */ + MVPP2_STOP, /* Stop */ + MVPP2_PAUSE, /* Pause */ + MVPP2_RESTART /* Restart */ +}; + +#define ARCH_DMA_MINALIGN 64 + +/* rx buffer size */ +#define BUFF_HDR_OFFS 32 +#define BM_ALIGN 32 +#define ETH_HLEN 14 +#define ETH_ALEN 6 +/* 2(HW hdr) 14(MAC hdr) 4(CRC) 32(extra for cache prefetch) */ +#define WRAP (2 + ETH_HLEN + 4 + 32) +#define MTU 1500 +#define RX_BUFFER_SIZE (ALIGN(MTU + WRAP, ARCH_DMA_MINALIGN)) + +/* Structures */ + +/* Individual port structure */ +struct mvpp2_port { + MV_U8 id; + MV_U8 gop_index; + + MV_32 irq; + + struct mvpp2 *priv; + + /* Per-port registers' base address */ + UINT64 gmac_base; + UINT64 xlg_base; + + struct mvpp2_rx_queue *rxqs; + struct mvpp2_tx_queue *txqs; + + MV_32 pkt_size; + + MV_U32 pending_cause_rx; + + /* Per-CPU port control */ + + /* Flags */ + MV_ULONG flags; + + MV_U16 tx_ring_size; + MV_U16 rx_ring_size; + + MV_32 phy_interface; + BOOLEAN link; + BOOLEAN duplex; + BOOLEAN always_up; + PHY_SPEED speed; + + struct mvpp2_bm_pool *pool_long; + struct mvpp2_bm_pool *pool_short; + + MV_U8 txp_num; + + /* Index of first port's physical RXQ */ + MV_U8 first_rxq; +}; + +typedef struct mvpp2_port PP2DXE_PORT; + +/* Shared Packet Processor resources */ +struct mvpp2 { + /* Shared registers' base addresses */ + UINT64 __iomem base; + UINT64 __iomem rfu1_base; + UINT64 __iomem smi_base; + MV_VOID __iomem *lms_base; + + /* List of pointers to port structures */ + struct mvpp2_port **port_list; + + /* Aggregated TXQs */ + struct mvpp2_tx_queue *aggr_txqs; + + /* BM pools */ + struct mvpp2_bm_pool *bm_pools; + + /* PRS shadow table */ + struct mvpp2_prs_shadow *prs_shadow; + /* PRS auxiliary table for double vlan entries control */ + MV_BOOL *prs_double_vlans; + + /* Tclk value */ + MV_U32 tclk; +}; + +typedef struct mvpp2 MVPP2_SHARED; + +struct mvpp2_tx_queue { + /* Physical number of this Tx queue */ + MV_U8 id; + + /* Logical number of this Tx queue */ + MV_U8 log_id; + + /* Number of Tx DMA descriptors in the descriptor ring */ + MV_32 size; + + /* Number of currently used Tx DMA descriptor in the descriptor ring */ + MV_32 count; + + MV_U32 done_pkts_coal; + + /* Virtual address of thex Tx DMA descriptors array */ + struct mvpp2_tx_desc *descs; + + /* DMA address of the Tx DMA descriptors array */ + dma_addr_t descs_phys; + + /* Index of the last Tx DMA descriptor */ + MV_32 last_desc; + + /* Index of the next Tx DMA descriptor to process */ + MV_32 next_desc_to_proc; +}; + +struct mvpp2_rx_queue { + /* RX queue number, in the range 0-31 for physical RXQs */ + MV_U8 id; + + /* Num of rx descriptors in the rx descriptor ring */ + MV_32 size; + + MV_U32 pkts_coal; + MV_U32 time_coal; + + /* Virtual address of the RX DMA descriptors array */ + struct mvpp2_rx_desc *descs; + + /* DMA address of the RX DMA descriptors array */ + dma_addr_t descs_phys; + + /* Index of the last RX DMA descriptor */ + MV_32 last_desc; + + /* Index of the next RX DMA descriptor to process */ + MV_32 next_desc_to_proc; + + /* ID of port to which physical RXQ is mapped */ + MV_32 port; + + /* Port's logic RXQ number to which physical RXQ is mapped */ + MV_32 logic_rxq; +}; + +enum mvpp2_bm_type { + MVPP2_BM_FREE, + MVPP2_BM_SWF_LONG, + MVPP2_BM_SWF_SHORT +}; + +struct mvpp2_bm_pool { + /* Pool number in the range 0-7 */ + MV_32 id; + enum mvpp2_bm_type type; + + /* Buffer Pointers Pool External (BPPE) size */ + MV_32 size; + /* Number of buffers for this pool */ + MV_32 buf_num; + /* Pool buffer size */ + MV_32 buf_size; + /* Packet size */ + MV_32 pkt_size; + + /* BPPE virtual base address */ + MV_U32 *virt_addr; + /* BPPE physical base address */ + dma_addr_t phys_addr; + + /* Ports using BM pool */ + MV_U32 port_map; + +}; + +/* Structure for preallocation for buffer */ +struct buffer_location { + struct mvpp2_tx_desc *tx_descs; + struct mvpp2_tx_desc *aggr_tx_descs; + struct mvpp2_rx_desc *rx_descs; + dma_addr_t rx_buffers; +}; +typedef struct buffer_location BUFFER_LOCATION; + +#define QUEUE_DEPTH 64 +typedef struct { + UINT32 Signature; + INTN Instance; + EFI_HANDLE Controller; + EFI_LOCK Lock; + EFI_SIMPLE_NETWORK_PROTOCOL Snp; + EFI_PHY_PROTOCOL *Phy; + PHY_DEVICE *PhyDev; + PP2DXE_PORT Port; + BOOLEAN Initialized; + BOOLEAN LateInitialized; + VOID *CompletionQueue[QUEUE_DEPTH]; + UINTN CompletionQueueHead; + UINTN CompletionQueueTail; + EFI_EVENT EfiExitBootServicesEvent; +} PP2DXE_CONTEXT; + +static inline MV_VOID mvpp2_write(struct mvpp2 *priv, MV_U32 offset, + MV_U32 data) +{ + ASSERT (priv->base != 0); + MmioWrite32 (priv->base + offset, data); +} + +static inline MV_U32 mvpp2_read(struct mvpp2 *priv, MV_U32 offset) +{ + ASSERT (priv->base != 0); + return MmioRead32 (priv->base + offset); +} + +static inline MV_U32 mvpp2_rfu1_read(struct mvpp2 *priv, MV_U32 offset) +{ + ASSERT (priv->rfu1_base != 0); + return MmioRead32 (priv->rfu1_base + offset); +} + +static inline MV_U32 mvpp2_rfu1_write(struct mvpp2 *priv, MV_U32 offset, + MV_U32 data) +{ + ASSERT (priv->rfu1_base != 0); + return MmioWrite32 (priv->rfu1_base + offset, data); +} + +static inline MV_U32 mvpp2_smi_read(struct mvpp2 *priv, MV_U32 offset) +{ + ASSERT (priv->smi_base != 0); + return MmioRead32 (priv->smi_base + offset); +} + +static inline MV_U32 mvpp2_smi_write(struct mvpp2 *priv, MV_U32 offset, + MV_U32 data) +{ + ASSERT (priv->smi_base != 0); + return MmioWrite32 (priv->smi_base + offset, data); +} + +static inline MV_VOID mvpp2_gmac_write(struct mvpp2_port *port, MV_U32 offset, + MV_U32 data) +{ + ASSERT (port->priv->base != 0); + MmioWrite32 (port->priv->base + offset, data); +} + +static inline MV_U32 mvpp2_gmac_read(struct mvpp2_port *port, MV_U32 offset) +{ + ASSERT (port->priv->base != 0); + return MmioRead32 (port->priv->base + offset); +} + +static inline MV_VOID mv_gop110_gmac_write(struct mvpp2_port *port, MV_U32 offset, + MV_U32 data) +{ + ASSERT (port->gmac_base != 0); + MmioWrite32 (port->gmac_base + offset, data); +} + +static inline MV_U32 mv_gop110_gmac_read(struct mvpp2_port *port, MV_U32 offset) +{ + ASSERT (port->gmac_base != 0); + return MmioRead32 (port->gmac_base + offset); +} + +static inline MV_VOID mvpp2_xlg_write(struct mvpp2_port *port, MV_U32 offset, + MV_U32 data) +{ + ASSERT (port->xlg_base != 0); + MmioWrite32 (port->xlg_base + offset, data); +} + +static inline MV_U32 mvpp2_xlg_read(struct mvpp2_port *port, MV_U32 offset) +{ + ASSERT (port->xlg_base != 0); + return MmioRead32 (port->xlg_base + offset); +} +#endif diff --git a/Drivers/Net/Pp2Dxe/Pp2Dxe.inf b/Drivers/Net/Pp2Dxe/Pp2Dxe.inf new file mode 100644 index 0000000..33e4641 --- /dev/null +++ b/Drivers/Net/Pp2Dxe/Pp2Dxe.inf @@ -0,0 +1,91 @@ +# 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. +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MdioDxe + FILE_GUID = 5ffc3843-d8d4-40ba-ae07-38967138509c + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = Pp2DxeInitialise + +[Sources.common] + Pp2Dxe.c + mvpp2_lib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + ArmPkg/ArmPkg.dec + OpenPlatformPkg/Platforms/Marvell/Marvell.dec + +[LibraryClasses] + IoLib + PcdLib + BaseLib + BaseMemoryLib + DebugLib + UefiLib + NetLib + UefiDriverEntryPoint + UefiBootServicesTableLib + MemoryAllocationLib + UncachedMemoryAllocationLib + CacheMaintenanceLib + +[Protocols] + gEfiSimpleNetworkProtocolGuid + gEfiDevicePathProtocolGuid + gEfiPhyProtocolGuid + gEfiMdioProtocolGuid + gEfiCpuArchProtocolGuid + +[Pcd] + gMarvellTokenSpaceGuid.PcdPhyConnectionTypes + gMarvellTokenSpaceGuid.PcdPp2PortNumber + gMarvellTokenSpaceGuid.PcdPhySmiAddresses + gMarvellTokenSpaceGuid.PcdPp2PortIds + gMarvellTokenSpaceGuid.PcdPp2GopIndexes + gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp + gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed + gMarvellTokenSpaceGuid.PcdPp2SharedAddress + gMarvellTokenSpaceGuid.PcdPp2GmacObjSize + gMarvellTokenSpaceGuid.PcdPp2GmacBaseAddress + gMarvellTokenSpaceGuid.PcdPp2XlgObjSize + gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress + gMarvellTokenSpaceGuid.PcdPp2Rfu1BaseAddress + gMarvellTokenSpaceGuid.PcdPp2SmiBaseAddress + gMarvellTokenSpaceGuid.PcdPp2ClockFrequency + +[Depex] + TRUE diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index 201456d..f12f46e 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -210,7 +210,23 @@ gMarvellTokenSpaceGuid.PcdPhyConnectionTypes|{ 0 }|VOID*|0x3000044 gMarvellTokenSpaceGuid.PcdPhyDeviceIds|{ 0 }|VOID*|0x3000095 gMarvellTokenSpaceGuid.PcdPhyStartupAutoneg|FALSE|BOOLEAN|0x3000070 -# + +#NET + gMarvellTokenSpaceGuid.PcdPhySmiAddresses|{ 0 }|VOID*|0x3000024 + gMarvellTokenSpaceGuid.PcdPp2SharedAddress|0|UINT64|0x40000026 + gMarvellTokenSpaceGuid.PcdPp2PortNumber|0|UINT32|0x40000013 + gMarvellTokenSpaceGuid.PcdPp2PortIds|{ 0 }|VOID*|0x3000025 + gMarvellTokenSpaceGuid.PcdPp2GopIndexes|{ 0 }|VOID*|0x3000041 + gMarvellTokenSpaceGuid.PcdPp2InterfaceAlwaysUp|{ 0 }|VOID*|0x3000075 + gMarvellTokenSpaceGuid.PcdPp2InterfaceSpeed|{ 0 }|VOID*|0x3000076 + gMarvellTokenSpaceGuid.PcdPp2GmacBaseAddress|0|UINT64|0x40000028 + gMarvellTokenSpaceGuid.PcdPp2GmacObjSize|0|UINT32|0x3000026 + gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress|0|UINT64|0x40000031 + gMarvellTokenSpaceGuid.PcdPp2XlgObjSize|0|UINT32|0x3000030 + gMarvellTokenSpaceGuid.PcdPp2Rfu1BaseAddress|0|UINT64|0x40000029 + gMarvellTokenSpaceGuid.PcdPp2SmiBaseAddress|0|UINT64|0x40000030 + gMarvellTokenSpaceGuid.PcdPp2ClockFrequency|0|UINT32|0x3000042 + [Protocols] gEfiEepromProtocolGuid = { 0xcd728a1f, 0x45b5, 0x4feb, { 0x98, 0xc8, 0x31, 0x3d, 0xa8, 0x11, 0x74, 0x62 }} gEfiSpiMasterProtocolGuid = { 0x23de66a3, 0xf666, 0x4b3e, { 0xaa, 0xa2, 0x68, 0x9b, 0x18, 0xae, 0x2e, 0x19 }}