Commit 5397c94c authored by Antoine Kaufmann's avatar Antoine Kaufmann
Browse files

initial i40e checkpoint

parent 2f6e1d50
CPPFLAGS += -I../nicsim_common/include -I../proto
CPPFLAGS += -I../libnicbm/include/
CFLAGS += -Wall -Wextra -Wno-unused-parameter -O3 -g
LDFLGAS = -g
OBJS := i40e_bm.o i40e_queues.o
all: i40e_bm
i40e_bm: $(OBJS) ../libnicbm/libnicbm.a ../nicsim_common/libnicsim_common.a
i40e_bm: CC=$(CXX)
clean:
rm -f *.o i40e_bm
This diff is collapsed.
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2001-2020 Intel Corporation
*/
#ifndef _I40E_DEVIDS_H_
#define _I40E_DEVIDS_H_
/* Vendor ID */
#define I40E_INTEL_VENDOR_ID 0x8086
/* Device IDs */
#define I40E_DEV_ID_SFP_XL710 0x1572
#define I40E_DEV_ID_QEMU 0x1574
#define I40E_DEV_ID_KX_B 0x1580
#define I40E_DEV_ID_KX_C 0x1581
#define I40E_DEV_ID_QSFP_A 0x1583
#define I40E_DEV_ID_QSFP_B 0x1584
#define I40E_DEV_ID_QSFP_C 0x1585
#define I40E_DEV_ID_10G_BASE_T 0x1586
#define I40E_DEV_ID_20G_KR2 0x1587
#define I40E_DEV_ID_20G_KR2_A 0x1588
#define I40E_DEV_ID_10G_BASE_T4 0x1589
#define I40E_DEV_ID_25G_B 0x158A
#define I40E_DEV_ID_25G_SFP28 0x158B
#define I40E_DEV_ID_X710_N3000 0x0CF8
#define I40E_DEV_ID_XXV710_N3000 0x0D58
#define I40E_DEV_ID_10G_BASE_T_BC 0x15FF
#define I40E_DEV_ID_5G_BASE_T_BC 0x101F
#if defined(INTEGRATED_VF) || defined(VF_DRIVER) || defined(I40E_NDIS_SUPPORT)
#define I40E_DEV_ID_VF 0x154C
#define I40E_DEV_ID_VF_HV 0x1571
#define I40E_DEV_ID_ADAPTIVE_VF 0x1889
#endif /* VF_DRIVER */
#ifdef X722_A0_SUPPORT
#define I40E_DEV_ID_X722_A0 0x374C
#if defined(INTEGRATED_VF) || defined(VF_DRIVER)
#define I40E_DEV_ID_X722_A0_VF 0x374D
#endif
#endif
#define I40E_DEV_ID_10G_B 0x104F
#define I40E_DEV_ID_10G_SFP 0x104E
#define I40E_IS_X710TL_DEVICE(d) \
(((d) == I40E_DEV_ID_10G_BASE_T_BC) || \
((d) == I40E_DEV_ID_5G_BASE_T_BC))
#define I40E_DEV_ID_KX_X722 0x37CE
#define I40E_DEV_ID_QSFP_X722 0x37CF
#define I40E_DEV_ID_SFP_X722 0x37D0
#define I40E_DEV_ID_1G_BASE_T_X722 0x37D1
#define I40E_DEV_ID_10G_BASE_T_X722 0x37D2
#define I40E_DEV_ID_SFP_I_X722 0x37D3
#if defined(INTEGRATED_VF) || defined(VF_DRIVER) || defined(I40E_NDIS_SUPPORT)
#define I40E_DEV_ID_X722_VF 0x37CD
#endif /* VF_DRIVER */
#define i40e_is_40G_device(d) ((d) == I40E_DEV_ID_QSFP_A || \
(d) == I40E_DEV_ID_QSFP_B || \
(d) == I40E_DEV_ID_QSFP_C)
#define i40e_is_25G_device(d) ((d) == I40E_DEV_ID_25G_B || \
(d) == I40E_DEV_ID_25G_SFP28)
#endif /* _I40E_DEVIDS_H_ */
This diff is collapsed.
#include <stdint.h>
#define PF_DRIVER
#define I40E_MASK(mask, shift) (mask << shift)
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint16_t __le16;
typedef uint32_t __le32;
#include "base/i40e_devids.h"
#include "base/i40e_register.h"
#include "base/i40e_adminq_cmd.h"
/* from i40e_types.h */
/* Checksum and Shadow RAM pointers */
#define I40E_SR_NVM_CONTROL_WORD 0x00
#define I40E_SR_PCIE_ANALOG_CONFIG_PTR 0x03
#define I40E_SR_PHY_ANALOG_CONFIG_PTR 0x04
#define I40E_SR_OPTION_ROM_PTR 0x05
#define I40E_SR_RO_PCIR_REGS_AUTO_LOAD_PTR 0x06
#define I40E_SR_AUTO_GENERATED_POINTERS_PTR 0x07
#define I40E_SR_PCIR_REGS_AUTO_LOAD_PTR 0x08
#define I40E_SR_EMP_GLOBAL_MODULE_PTR 0x09
#define I40E_SR_RO_PCIE_LCB_PTR 0x0A
#define I40E_SR_EMP_IMAGE_PTR 0x0B
#define I40E_SR_PE_IMAGE_PTR 0x0C
#define I40E_SR_CSR_PROTECTED_LIST_PTR 0x0D
#define I40E_SR_MNG_CONFIG_PTR 0x0E
#define I40E_EMP_MODULE_PTR 0x0F
#define I40E_SR_EMP_MODULE_PTR 0x48
#define I40E_SR_PBA_FLAGS 0x15
#define I40E_SR_PBA_BLOCK_PTR 0x16
#define I40E_SR_BOOT_CONFIG_PTR 0x17
#define I40E_NVM_OEM_VER_OFF 0x83
#define I40E_SR_NVM_DEV_STARTER_VERSION 0x18
#define I40E_SR_NVM_WAKE_ON_LAN 0x19
#define I40E_SR_ALTERNATE_SAN_MAC_ADDRESS_PTR 0x27
#define I40E_SR_PERMANENT_SAN_MAC_ADDRESS_PTR 0x28
#define I40E_SR_NVM_MAP_VERSION 0x29
#define I40E_SR_NVM_IMAGE_VERSION 0x2A
#define I40E_SR_NVM_STRUCTURE_VERSION 0x2B
#define I40E_SR_NVM_EETRACK_LO 0x2D
#define I40E_SR_NVM_EETRACK_HI 0x2E
#define I40E_SR_VPD_PTR 0x2F
#define I40E_SR_PXE_SETUP_PTR 0x30
#define I40E_SR_PXE_CONFIG_CUST_OPTIONS_PTR 0x31
#define I40E_SR_NVM_ORIGINAL_EETRACK_LO 0x34
#define I40E_SR_NVM_ORIGINAL_EETRACK_HI 0x35
#define I40E_SR_SW_ETHERNET_MAC_ADDRESS_PTR 0x37
#define I40E_SR_POR_REGS_AUTO_LOAD_PTR 0x38
#define I40E_SR_EMPR_REGS_AUTO_LOAD_PTR 0x3A
#define I40E_SR_GLOBR_REGS_AUTO_LOAD_PTR 0x3B
#define I40E_SR_CORER_REGS_AUTO_LOAD_PTR 0x3C
#define I40E_SR_PHY_ACTIVITY_LIST_PTR 0x3D
#define I40E_SR_PCIE_ALT_AUTO_LOAD_PTR 0x3E
#define I40E_SR_SW_CHECKSUM_WORD 0x3F
#define I40E_SR_1ST_FREE_PROVISION_AREA_PTR 0x40
#define I40E_SR_4TH_FREE_PROVISION_AREA_PTR 0x42
#define I40E_SR_3RD_FREE_PROVISION_AREA_PTR 0x44
#define I40E_SR_2ND_FREE_PROVISION_AREA_PTR 0x46
#define I40E_SR_EMP_SR_SETTINGS_PTR 0x48
#define I40E_SR_FEATURE_CONFIGURATION_PTR 0x49
#define I40E_SR_CONFIGURATION_METADATA_PTR 0x4D
#define I40E_SR_IMMEDIATE_VALUES_PTR 0x4E
/* Auxiliary field, mask and shift definition for Shadow RAM and NVM Flash */
#define I40E_SR_VPD_MODULE_MAX_SIZE 1024
#define I40E_SR_PCIE_ALT_MODULE_MAX_SIZE 1024
#define I40E_SR_CONTROL_WORD_1_SHIFT 0x06
#define I40E_SR_CONTROL_WORD_1_MASK (0x03 << I40E_SR_CONTROL_WORD_1_SHIFT)
#define I40E_SR_CONTROL_WORD_1_NVM_BANK_VALID BIT(5)
#define I40E_SR_NVM_MAP_STRUCTURE_TYPE BIT(12)
#define I40E_PTR_TYPE BIT(15)
#define I40E_SR_OCP_CFG_WORD0 0x2B
#define I40E_SR_OCP_ENABLED BIT(15)
/* Shadow RAM related */
#define I40E_SR_SECTOR_SIZE_IN_WORDS 0x800
#define I40E_SR_BUF_ALIGNMENT 4096
#define I40E_SR_WORDS_IN_1KB 512
/* Checksum should be calculated such that after adding all the words,
* including the checksum word itself, the sum should be 0xBABA.
*/
#define I40E_SR_SW_CHECKSUM_BASE 0xBABA
#define I40E_SRRD_SRCTL_ATTEMPTS 100000
#include <stdlib.h>
#include <string.h>
#include <cassert>
#include <iostream>
#include "i40e_bm.h"
#include "i40e_base_wrapper.h"
nicbm::Runner *runner;
namespace i40e {
i40e_bm::i40e_bm()
: pf_atq(*this, regs.pf_atqba, regs.pf_atqlen, regs.pf_atqh, regs.pf_atqt),
shram(*this)
{
memset(&regs, 0, sizeof(regs));
}
i40e_bm::~i40e_bm()
{
}
void i40e_bm::setup_intro(struct cosim_pcie_proto_dev_intro &di)
{
di.bars[BAR_REGS].len = 4 * 1024 * 1024;
di.bars[BAR_REGS].flags = COSIM_PCIE_PROTO_BAR_64;
di.bars[BAR_IO].len = 32;
di.bars[BAR_IO].flags = COSIM_PCIE_PROTO_BAR_IO;
di.pci_vendor_id = I40E_INTEL_VENDOR_ID;
di.pci_device_id = I40E_DEV_ID_QSFP_A;
di.pci_class = 0x02;
di.pci_subclass = 0x00;
di.pci_revision = 0x01;
di.pci_msi_nvecs = 32;
}
void i40e_bm::dma_complete(nicbm::DMAOp &op)
{
dma_base &dma = dynamic_cast<dma_base &>(op);
std::cerr << "dma_complete(" << &op << ")" << std::endl;
dma.done();
}
void i40e_bm::eth_rx(uint8_t port, const void *data, size_t len)
{
}
void i40e_bm::reg_read(uint8_t bar, uint64_t addr, void *dest, size_t len)
{
uint32_t val32 = 0;
if (len != 4) {
std::cerr << "currently we only support 4B reads (got " << len << ")"
<< std::endl;
abort();
}
if (bar == BAR_REGS) {
val32 = reg_mem_read32(addr);
} else if (bar == BAR_IO) {
val32 = reg_io_read(addr);
} else {
std::cerr << "invalid BAR " << (int) bar << std::endl;
abort();
}
*(uint32_t *) dest = val32;
}
void i40e_bm::reg_write(uint8_t bar, uint64_t addr, const void *src, size_t len)
{
uint32_t val32 = 0;
if (len != 4) {
std::cerr << "currently we only support 4B writes (got " << len << ")"
<< std::endl;
abort();
}
val32 = *(const uint32_t *) src;
if (bar == BAR_REGS) {
reg_mem_write32(addr, val32);
} else if (bar == BAR_IO) {
reg_io_write(addr, val32);
} else {
std::cerr << "invalid BAR " << (int) bar << std::endl;
abort();
}
}
uint32_t i40e_bm::reg_io_read(uint64_t addr)
{
std::cerr << "unhandled io read addr=" << std::hex << addr << std::endl;
return 0;
}
void i40e_bm::reg_io_write(uint64_t addr, uint32_t val)
{
std::cerr << "unhandled io write addr=" << std::hex << addr << " val="
<< val << std::endl;
}
uint32_t i40e_bm::reg_mem_read32(uint64_t addr)
{
uint32_t val = 0;
if (addr >= I40E_PFINT_DYN_CTLN(0) &&
addr < I40E_PFINT_DYN_CTLN(NUM_PFINTS - 1))
{
val = regs.pfint_dyn_ctln[(addr - I40E_PFINT_DYN_CTLN(0)) / 4];
} else if (addr >= I40E_PFINT_LNKLSTN(0) &&
addr <= I40E_PFINT_LNKLSTN(NUM_PFINTS - 1))
{
val = regs.pfint_lnklstn[(addr - I40E_PFINT_LNKLSTN(0)) / 4];
} else if (addr >= I40E_PFINT_RATEN(0) &&
addr <= I40E_PFINT_RATEN(NUM_PFINTS - 1))
{
val = regs.pfint_raten[(addr - I40E_PFINT_RATEN(0)) / 4];
} else if (addr >= I40E_GLLAN_TXPRE_QDIS(0) &&
addr < I40E_GLLAN_TXPRE_QDIS(12))
{
val = regs.gllan_txpre_qdis[(addr - I40E_GLLAN_TXPRE_QDIS(0)) / 4];
} else if (addr >= I40E_QINT_TQCTL(0) &&
addr <= I40E_QINT_TQCTL(NUM_QUEUES - 1))
{
val = regs.qint_tqctl[(addr - I40E_QINT_TQCTL(0)) / 4];
} else if (addr >= I40E_QTX_ENA(0) &&
addr <= I40E_QTX_ENA(NUM_QUEUES - 1))
{
val = regs.qtx_ena[(addr - I40E_QTX_ENA(0)) / 4];
} else if (addr >= I40E_QINT_RQCTL(0) &&
addr <= I40E_QINT_RQCTL(NUM_QUEUES - 1))
{
val = regs.qint_rqctl[(addr - I40E_QINT_RQCTL(0)) / 4];
} else if (addr >= I40E_QRX_ENA(0) &&
addr <= I40E_QRX_ENA(NUM_QUEUES - 1))
{
val = regs.qrx_ena[(addr - I40E_QRX_ENA(0)) / 4] = val;
} else {
switch (addr) {
case I40E_PFGEN_CTRL:
val = 0; /* we always simulate immediate reset */
break;
case I40E_GL_FWSTS:
val = 0;
break;
case I40E_GLPCI_CAPSUP:
val = 0;
break;
case I40E_GLNVM_ULD:
val = 0xffffffff;
break;
case I40E_GLNVM_GENS:
val = I40E_GLNVM_GENS_NVM_PRES_MASK |
(6 << I40E_GLNVM_GENS_SR_SIZE_SHIFT); // shadow ram 64kb
break;
case I40E_GLNVM_FLA:
val = I40E_GLNVM_FLA_LOCKED_MASK; /* normal flash programming
mode */
break;
case I40E_GLGEN_RSTCTL:
val = regs.glgen_rstctl;
break;
case I40E_PFINT_LNKLST0:
val = regs.pfint_lnklst0;
break;
case I40E_PFINT_ICR0_ENA:
val = regs.pfint_icr0_ena;
break;
case I40E_GLPCI_CNF2:
val = ((NUM_PFINTS - 2) << I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT) |
(2 << I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT); /* that is ugly,
but linux
driver needs
this not to
crash. */
break;
case I40E_GLNVM_SRCTL:
val = regs.glnvm_srctl;
break;
case I40E_GLNVM_SRDATA:
val = regs.glnvm_srdata;
break;
case I40E_PFLAN_QALLOC:
val = (0 << I40E_PFLAN_QALLOC_FIRSTQ_SHIFT) |
((NUM_QUEUES - 1) << I40E_PFLAN_QALLOC_LASTQ_SHIFT) |
(1 << I40E_PFLAN_QALLOC_VALID_SHIFT);
break;
case I40E_PF_VT_PFALLOC:
val = 0; // we don't currently support VFs
break;
case I40E_PFGEN_PORTNUM:
val = (0 << I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT);
break;
case I40E_GLLAN_RCTL_0:
val = regs.gllan_rctl_0;
break;
case I40E_PF_ATQBAL:
val = regs.pf_atqba;
break;
case I40E_PF_ATQBAH:
val = regs.pf_atqba >> 32;
break;
case I40E_PF_ATQLEN:
val = regs.pf_atqlen;
break;
case I40E_PF_ATQH:
val = regs.pf_atqh;
break;
case I40E_PF_ATQT:
val = regs.pf_atqt;
break;
case I40E_PF_ARQBAL:
val = regs.pf_arqba;
break;
case I40E_PF_ARQBAH:
val = regs.pf_arqba >> 32;
break;
case I40E_PF_ARQLEN:
val = regs.pf_arqlen;
break;
case I40E_PF_ARQH:
val = regs.pf_arqh;
break;
case I40E_PF_ARQT:
val = regs.pf_arqt;
break;
default:
std::cerr << "unhandled mem read addr=" << std::hex << addr
<< std::endl;
break;
}
}
return val;
}
void i40e_bm::reg_mem_write32(uint64_t addr, uint32_t val)
{
if (addr >= I40E_PFINT_DYN_CTLN(0) &&
addr <= I40E_PFINT_DYN_CTLN(NUM_PFINTS - 1))
{
regs.pfint_dyn_ctln[(addr - I40E_PFINT_DYN_CTLN(0)) / 4] = val;
} else if (addr >= I40E_PFINT_LNKLSTN(0) &&
addr <= I40E_PFINT_LNKLSTN(NUM_PFINTS - 1))
{
regs.pfint_lnklstn[(addr - I40E_PFINT_LNKLSTN(0)) / 4] = val;
} else if (addr >= I40E_PFINT_RATEN(0) &&
addr <= I40E_PFINT_RATEN(NUM_PFINTS - 1))
{
regs.pfint_raten[(addr - I40E_PFINT_RATEN(0)) / 4] = val;
} else if (addr >= I40E_GLLAN_TXPRE_QDIS(0) &&
addr <= I40E_GLLAN_TXPRE_QDIS(11))
{
regs.gllan_txpre_qdis[(addr - I40E_GLLAN_TXPRE_QDIS(0)) / 4] = val;
} else if (addr >= I40E_QINT_TQCTL(0) &&
addr <= I40E_QINT_TQCTL(NUM_QUEUES - 1))
{
regs.qint_tqctl[(addr - I40E_QINT_TQCTL(0)) / 4] = val;
} else if (addr >= I40E_QTX_ENA(0) &&
addr <= I40E_QTX_ENA(NUM_QUEUES - 1))
{
regs.qtx_ena[(addr - I40E_QTX_ENA(0)) / 4] = val;
} else if (addr >= I40E_QINT_RQCTL(0) &&
addr <= I40E_QINT_RQCTL(NUM_QUEUES - 1))
{
regs.qint_rqctl[(addr - I40E_QINT_RQCTL(0)) / 4] = val;
} else if (addr >= I40E_QRX_ENA(0) &&
addr <= I40E_QRX_ENA(NUM_QUEUES - 1))
{
regs.qrx_ena[(addr - I40E_QRX_ENA(0)) / 4] = val;
} else {
switch (addr) {
case I40E_PFGEN_CTRL:
if ((val & I40E_PFGEN_CTRL_PFSWR_MASK) ==
I40E_PFGEN_CTRL_PFSWR_MASK)
reset();
break;
case I40E_GL_FWSTS:
break;
case I40E_GLGEN_RSTCTL:
regs.glgen_rstctl = val;
break;
case I40E_GLLAN_RCTL_0:
if ((val & I40E_GLLAN_RCTL_0_PXE_MODE_MASK))
regs.gllan_rctl_0 &= ~I40E_GLLAN_RCTL_0_PXE_MODE_MASK;
break;
case I40E_GLNVM_SRCTL:
regs.glnvm_srctl = val;
shram.reg_updated();
break;
case I40E_GLNVM_SRDATA:
regs.glnvm_srdata = val;
shram.reg_updated();
break;
case I40E_PFINT_LNKLST0:
regs.pfint_lnklst0 = val;
break;
case I40E_PFINT_ICR0_ENA:
regs.pfint_icr0_ena = val;
break;
case I40E_PF_ATQBAL:
regs.pf_atqba = val | (regs.pf_atqba & 0xffffffff00000000ULL);
pf_atq.reg_updated();
break;
case I40E_PF_ATQBAH:
regs.pf_atqba = ((uint64_t ) val << 32) |
(regs.pf_atqba & 0xffffffffULL);
pf_atq.reg_updated();
break;
case I40E_PF_ATQLEN:
regs.pf_atqlen = val;
pf_atq.reg_updated();
break;
case I40E_PF_ATQH:
regs.pf_atqh = val;
pf_atq.reg_updated();
break;
case I40E_PF_ATQT:
regs.pf_atqt = val;
pf_atq.reg_updated();
break;
case I40E_PF_ARQBAL:
regs.pf_arqba = val | (regs.pf_atqba & 0xffffffff00000000ULL);
break;
case I40E_PF_ARQBAH:
regs.pf_arqba = ((uint64_t ) val << 32) |
(regs.pf_arqba & 0xffffffffULL);
break;
case I40E_PF_ARQLEN:
regs.pf_arqlen = val;
break;
case I40E_PF_ARQH:
regs.pf_arqh = val;
break;
case I40E_PF_ARQT:
regs.pf_arqt = val;
break;
default:
std::cerr << "unhandled mem write addr=" << std::hex << addr
<< " val=" << val << std::endl;
break;
}
}
}
void i40e_bm::reset()
{
std::cout << "reset triggered" << std::endl;
regs.glnvm_srctl = I40E_GLNVM_SRCTL_DONE_MASK;
}
shadow_ram::shadow_ram(i40e_bm &dev_)
: dev(dev_)
{
}
void shadow_ram::reg_updated()
{
uint32_t val = dev.regs.glnvm_srctl;
uint32_t addr;
bool is_write;
if (!(val & I40E_GLNVM_SRCTL_START_MASK))
return;
addr = (val & I40E_GLNVM_SRCTL_ADDR_MASK)
>> I40E_GLNVM_SRCTL_ADDR_SHIFT;
is_write = (val & I40E_GLNVM_SRCTL_WRITE_MASK);
std::cerr << "shadow ram op addr=" << std::hex << addr << " w=" << is_write
<< std::endl;
if (is_write) {
write(addr,
(dev.regs.glnvm_srdata & I40E_GLNVM_SRDATA_WRDATA_MASK)
>> I40E_GLNVM_SRDATA_WRDATA_SHIFT);
} else {
dev.regs.glnvm_srdata &= ~I40E_GLNVM_SRDATA_RDDATA_MASK;
dev.regs.glnvm_srdata |= ((uint32_t) read(addr)) <<
I40E_GLNVM_SRDATA_RDDATA_SHIFT;
}
dev.regs.glnvm_srctl &= ~I40E_GLNVM_SRCTL_START_MASK;
dev.regs.glnvm_srctl |= I40E_GLNVM_SRCTL_DONE_MASK;
}
uint16_t shadow_ram::read(uint16_t addr)
{
switch (addr) {
/* for any of these hopefully return 0 should be fine */
/* they are read by drivers but not used */
case I40E_SR_NVM_DEV_STARTER_VERSION:
case I40E_SR_NVM_EETRACK_LO:
case I40E_SR_NVM_EETRACK_HI:
case I40E_SR_BOOT_CONFIG_PTR:
return 0;
default:
std::cerr << "TODO shadow memory read addr=" << std::hex << addr
<< std::endl;
break;
}
return 0;
}
void shadow_ram::write(uint16_t addr, uint16_t val)
{
std::cerr << "TODO shadow memory write addr=" << std::hex << addr <<
" val=" << val << std::endl;
}
} //namespace i40e
using namespace i40e;
int main(int argc, char *argv[])
{
i40e_bm dev;
runner = new nicbm::Runner(dev);
return runner->runMain(argc, argv);
}
#pragma once
#include <list>
#include <vector>
#include <stdint.h>
extern "C" {
#include <cosim_pcie_proto.h>
}
#include <nicbm.h>
namespace i40e {
class i40e_bm;
class dma_base : public nicbm::DMAOp {
public:
/** i40e_bm will call this when dma is done */
virtual void done() = 0;
};
class queue_base {
protected:
class dma_fetch : public dma_base {
protected:
queue_base &queue;
public:
uint32_t index;
dma_fetch(queue_base &queue_, size_t len);
virtual ~dma_fetch();
virtual void done();
};
class dma_wb : public dma_base {
protected:
queue_base &queue;
public:
uint32_t index;
dma_wb(queue_base &queue_, size_t len);
virtual ~dma_wb();
virtual void done();
};
uint64_t base;
uint32_t len;
uint32_t fetch_head;
uint32_t &reg_head;
uint32_t &reg_tail;
bool enabled;
size_t desc_len;
void trigger_fetch();
void desc_writeback(const void *desc, uint32_t idx);
/** called when a descriptor is fetched */
virtual void desc_fetched(void *desc, uint32_t idx) = 0;
virtual void desc_written_back(uint32_t idx);
public:
queue_base(uint32_t &reg_head_, uint32_t &reg_tail_);
void reg_updated();
};
class queue_admin_tx : public queue_base {
protected:
i40e_bm &dev;
virtual void desc_fetched(void *desc, uint32_t idx);
uint64_t &reg_base;
uint32_t &reg_len;
public:
queue_admin_tx(i40e_bm &dev_, uint64_t &reg_base_,
uint32_t &reg_len_, uint32_t &reg_head_, uint32_t &reg_tail_);
void reg_updated();
};
class shadow_ram {
protected:
i40e_bm &dev;
public:
shadow_ram(i40e_bm &dev);
void reg_updated();
uint16_t read(uint16_t addr);
void write(uint16_t addr, uint16_t val);
};
class i40e_bm : public nicbm::Runner::Device {
protected:
friend class shadow_ram;
friend class queue_admin_tx;
static const unsigned BAR_REGS = 0;
static const unsigned BAR_IO = 2;
static const uint32_t NUM_QUEUES = 1536;
static const uint32_t NUM_PFINTS = 512;
struct i40e_regs {
uint32_t glgen_rstctl;
uint32_t gllan_rctl_0;
uint32_t pfint_lnklst0;
uint32_t pfint_icr0_ena;
uint32_t pfint_dyn_ctln[NUM_PFINTS - 1];
uint32_t pfint_lnklstn[NUM_PFINTS - 1];
uint32_t pfint_raten[NUM_PFINTS - 1];
uint32_t gllan_txpre_qdis[12];
uint32_t glnvm_srctl;
uint32_t glnvm_srdata;
uint32_t qint_tqctl[NUM_QUEUES];
uint32_t qtx_ena[NUM_QUEUES];
uint32_t qint_rqctl[NUM_QUEUES];
uint32_t qrx_ena[NUM_QUEUES];
uint64_t pf_atqba;
uint32_t pf_atqlen;
uint32_t pf_atqh;
uint32_t pf_atqt;
uint64_t pf_arqba;
uint32_t pf_arqlen;
uint32_t pf_arqh;
uint32_t pf_arqt;
};
public:
nicbm::Runner *runner;
i40e_bm();
~i40e_bm();
virtual void setup_intro(struct cosim_pcie_proto_dev_intro &di);
virtual void reg_read(uint8_t bar, uint64_t addr, void *dest, size_t len);
virtual void reg_write(uint8_t bar, uint64_t addr, const void *src,
size_t len);
virtual void dma_complete(nicbm::DMAOp &op);
virtual void eth_rx(uint8_t port, const void *data, size_t len);
protected:
i40e_regs regs;
queue_admin_tx pf_atq;
shadow_ram shram;
/** Read from the I/O bar */
virtual uint32_t reg_io_read(uint64_t addr);
/** Write to the I/O bar */
virtual void reg_io_write(uint64_t addr, uint32_t val);
/** 32-bit read from the memory bar (should be the default) */
virtual uint32_t reg_mem_read32(uint64_t addr);
/** 32-bit write to the memory bar (should be the default) */
virtual void reg_mem_write32(uint64_t addr, uint32_t val);
void reset();
};
} // namespace corundum
#include <stdlib.h>
#include <string.h>
#include <cassert>
#include <iostream>
#include "i40e_bm.h"
#include "i40e_base_wrapper.h"
using namespace i40e;
extern nicbm::Runner *runner;
queue_base::queue_base(uint32_t &reg_head_, uint32_t &reg_tail_)
: base(0), len(0), fetch_head(0), reg_head(reg_head_), reg_tail(reg_tail_),
enabled(false), desc_len(0)
{
}
void queue_base::trigger_fetch()
{
if (fetch_head == reg_tail)
return;
dma_fetch *dma = new dma_fetch(*this, desc_len);
dma->write = false;
dma->dma_addr = base + fetch_head * desc_len;
dma->index = fetch_head;
std::cerr << "fetching " << (reg_tail - fetch_head) % len <<
" descriptors from " << dma->dma_addr << std::endl;
std::cerr << "dma = " << dma << std::endl;
runner->issue_dma(*dma);
fetch_head = (fetch_head + 1) % len;
}
void queue_base::reg_updated()
{
if (!enabled)
return;
trigger_fetch();
}
void queue_base::desc_writeback(const void *desc, uint32_t idx)
{
dma_wb *dma = new dma_wb(*this, desc_len);
dma->write = true;
dma->dma_addr = base + idx * desc_len;
dma->index = idx;
memcpy(dma->data, desc, desc_len);
runner->issue_dma(*dma);
}
void queue_base::desc_written_back(uint32_t idx)
{
std::cerr << "descriptor " << idx << " written back" << std::endl;
reg_head = (idx + 1) % len;
}
queue_base::dma_fetch::dma_fetch(queue_base &queue_, size_t len_)
: queue(queue_)
{
data = new char[len_];
len = len_;
}
queue_base::dma_fetch::~dma_fetch()
{
delete[] ((char *) data);
}
void queue_base::dma_fetch::done()
{
queue.desc_fetched(data, index);
delete this;
}
queue_base::dma_wb::dma_wb(queue_base &queue_, size_t len_)
: queue(queue_)
{
data = new char[len_];
len = len_;
}
queue_base::dma_wb::~dma_wb()
{
delete[] ((char *) data);
}
void queue_base::dma_wb::done()
{
queue.desc_written_back(index);
queue.trigger_fetch();
delete this;
}
/******************************************************************************/
queue_admin_tx::queue_admin_tx(i40e_bm &dev_, uint64_t &reg_base_,
uint32_t &reg_len_, uint32_t &reg_head_, uint32_t &reg_tail_)
: queue_base(reg_head_, reg_tail_), dev(dev_), reg_base(reg_base_),
reg_len(reg_len_)
{
desc_len = 32;
}
void queue_admin_tx::desc_fetched(void *desc, uint32_t idx)
{
struct i40e_aq_desc *d = reinterpret_cast<struct i40e_aq_desc *>(desc);
std::cerr << "descriptor " << idx << " fetched" << std::endl;
if (d->opcode == i40e_aqc_opc_get_version) {
std::cerr << " get version" << std::endl;
struct i40e_aqc_get_version *gv =
reinterpret_cast<struct i40e_aqc_get_version *>(d->params.raw);
gv->rom_ver = 0;
gv->fw_build = 0;
gv->fw_major = 0;
gv->fw_minor = 0;
gv->api_major = I40E_FW_API_VERSION_MAJOR;
gv->api_minor = I40E_FW_API_VERSION_MINOR_X710;
d->flags |= I40E_AQ_FLAG_DD | I40E_AQ_FLAG_CMP;
desc_writeback(d, idx);
} else if (d->opcode == i40e_aqc_opc_request_resource) {
std::cerr << " request resource" << std::endl;
struct i40e_aqc_request_resource *rr =
reinterpret_cast<struct i40e_aqc_request_resource *>(
d->params.raw);
rr->timeout = 180000;
std::cerr << " res_id=" << rr->resource_id << std::endl;
std::cerr << " res_nu=" << rr->resource_number << std::endl;
} else if (d->opcode == i40e_aqc_opc_release_resource) {
std::cerr << " release resource" << std::endl;
struct i40e_aqc_request_resource *rr =
reinterpret_cast<struct i40e_aqc_request_resource *>(
d->params.raw);
std::cerr << " res_id=" << rr->resource_id << std::endl;
std::cerr << " res_nu=" << rr->resource_number << std::endl;
} else if (d->opcode == i40e_aqc_opc_clear_pxe_mode) {
std::cerr << " clear PXE mode" << std::endl;
dev.regs.gllan_rctl_0 &= ~I40E_GLLAN_RCTL_0_PXE_MODE_MASK;
} else {
std::cerr << " uknown opcode=" << d->opcode << std::endl;
}
}
void queue_admin_tx::reg_updated()
{
base = reg_base;
len = (reg_len & I40E_GL_ATQLEN_ATQLEN_MASK) >> I40E_GL_ATQLEN_ATQLEN_SHIFT;
if (!enabled && (reg_len & I40E_GL_ATQLEN_ATQENABLE_MASK)) {
std::cerr << "enable atq base=" << base << " len=" << len << std::endl;
enabled = true;
} else if (enabled && !(reg_len & I40E_GL_ATQLEN_ATQENABLE_MASK)) {
std::cerr << "disable atq" << std::endl;
enabled = false;
}
queue_base::reg_updated();
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment