Commit 5201df73 authored by Jialin Li's avatar Jialin Li
Browse files

Merge branch 'corundum-bm'

parents 521ce665 a01d9bb1
corundum_bm
tester
CPPFLAGS += -I../nicsim_common/include -I../netsim_common/include -I../proto
CFLAGS += -Wall -Wextra -Wno-unused-parameter -O3
all: corundum_bm tester
corundum.o: corundum.cc
g++ $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
corundum_bm: corundum_bm.o ../nicsim_common/libnicsim_common.a
g++ $^ -o $@
tester: tester.o ../nicsim_common/libnicsim_common.a
clean:
rm -f *.o corundum_bm tester
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <cassert>
#include "corundum_bm.h"
extern "C" {
#include <nicsim.h>
#include <netsim.h>
}
static void issue_dma_op(corundum::DMAOp *op);
static void msi_issue(uint8_t vec);
static void eth_send(void *data, size_t len);
namespace corundum {
DescRing::DescRing()
: _dmaAddr(0), _sizeLog(0), _size(0), _sizeMask(0),
_index(0), _headPtr(0), _tailPtr(0),
_currHead(0), _currTail(0), active(false)
{
}
DescRing::~DescRing()
{
}
addr_t
DescRing::dmaAddr()
{
return this->_dmaAddr;
}
size_t
DescRing::sizeLog()
{
return this->_sizeLog;
}
unsigned
DescRing::index()
{
return this->_index;
}
ptr_t
DescRing::headPtr()
{
return this->_headPtr;
}
ptr_t
DescRing::tailPtr()
{
return this->_tailPtr;
}
void
DescRing::setDMALower(uint32_t addr)
{
this->_dmaAddr &= 0xFFFFFFFF00000000;
this->_dmaAddr |= (addr_t)addr;
}
void
DescRing::setDMAUpper(uint32_t addr)
{
this->_dmaAddr &= 0xFFFFFFFF;
this->_dmaAddr |= ((addr_t)addr << 32);
}
void
DescRing::setSizeLog(size_t size_log)
{
if (size_log & QUEUE_ACTIVE_MASK) {
this->active = true;
} else {
this->active = false;
}
this->_sizeLog = size_log & 0xFF;
this->_size = 1 << this->_sizeLog;
this->_sizeMask = this->_size - 1;
}
void
DescRing::setIndex(unsigned index)
{
assert(!(index & QUEUE_CONT_MASK));
this->_index = index & 0xFF;
}
void
DescRing::setHeadPtr(ptr_t ptr)
{
this->_headPtr = ptr;
}
void
DescRing::setTailPtr(ptr_t ptr)
{
this->_tailPtr = ptr;
}
bool
DescRing::empty()
{
return (this->_headPtr == this->_currTail);
}
bool
DescRing::full()
{
return (this->_currHead - this->_tailPtr >= this->_size);
}
EventRing::EventRing()
{
}
EventRing::~EventRing()
{
}
void
EventRing::dmaDone(DMAOp *op)
{
assert(op->write);
switch (op->type) {
case DMA_TYPE_EVENT:
// TODO: assume in order transmission
assert(this->_headPtr == op->tag);
this->_headPtr++;
msi_issue(0);
delete op;
break;
default:
fprintf(stderr, "Unknown DMA type %u\n", op->type);
abort();
}
}
void
EventRing::issueEvent(unsigned type, unsigned source)
{
assert(type == EVENT_TYPE_TX_CPL || type == EVENT_TYPE_RX_CPL);
if (full()) {
fprintf(stderr, "Event ring is rull\n");
abort();
}
addr_t dma_addr = this->_dmaAddr + (this->_currHead & this->_sizeMask) * EVENT_SIZE;
/* Issue DMA write */
DMAOp *op = new DMAOp;
op->type = DMA_TYPE_EVENT;
op->dma_addr = dma_addr;
op->len = EVENT_SIZE;
op->ring = this;
op->tag = this->_currHead;
op->write = true;
Event *event = (Event *)op->data;
memset(event, 0, sizeof(Event));
event->type = type;
event->source = source;
issue_dma_op(op);
this->_currHead++;
}
CplRing::CplRing(EventRing *eventRing)
: eventRing(eventRing)
{
}
CplRing::~CplRing()
{
}
void
CplRing::dmaDone(DMAOp *op)
{
assert(op->write);
switch (op->type) {
case DMA_TYPE_TX_CPL:
case DMA_TYPE_RX_CPL: {
// TODO: assume in order transmission
assert(this->_headPtr == op->tag);
this->_headPtr++;
unsigned type = op->type == DMA_TYPE_TX_CPL ? EVENT_TYPE_TX_CPL :
EVENT_TYPE_RX_CPL;
this->eventRing->issueEvent(type, 0);
delete op;
break;
}
default:
fprintf(stderr, "Unknown DMA type %u\n", op->type);
abort();
}
}
void
CplRing::complete(unsigned index, size_t len, bool tx)
{
if (full()) {
fprintf(stderr, "Completion ring is full\n");
abort();
}
addr_t dma_addr = this->_dmaAddr + (this->_currHead & this->_sizeMask) * CPL_SIZE;
/* Issue DMA write */
DMAOp *op = new DMAOp;
op->type = tx ? DMA_TYPE_TX_CPL : DMA_TYPE_RX_CPL;
op->dma_addr = dma_addr;
op->len = CPL_SIZE;
op->ring = this;
op->tag = this->_currHead;
op->write = true;
Cpl *cpl = (Cpl *)op->data;
memset(cpl, 0, sizeof(Cpl));
cpl->index = index;
cpl->len = len;
issue_dma_op(op);
this->_currHead++;
}
TxRing::TxRing(CplRing *cplRing)
: txCplRing(cplRing)
{
}
TxRing::~TxRing()
{
}
void
TxRing::setHeadPtr(ptr_t ptr)
{
DescRing::setHeadPtr(ptr);
while (this->_currTail != this->_headPtr) {
unsigned index = this->_currTail & this->_sizeMask;
addr_t dma_addr = this->_dmaAddr + index * DESC_SIZE;
/* Issue DMA read */
DMAOp *op = new DMAOp;
op->type = DMA_TYPE_DESC;
op->dma_addr = dma_addr;
op->len = DESC_SIZE;
op->ring = this;
op->tag = this->_currTail;
op->write = false;
issue_dma_op(op);
this->_currTail++;
}
}
void
TxRing::dmaDone(DMAOp *op)
{
switch (op->type) {
case DMA_TYPE_DESC: {
assert(!op->write);
Desc *desc = (Desc *)op->data;
op->type = DMA_TYPE_MEM;
op->dma_addr = desc->addr;
op->len = desc->len;
op->write = false;
issue_dma_op(op);
break;
}
case DMA_TYPE_MEM:
assert(!op->write);
eth_send(op->data, op->len);
// TODO: assume in order transmission
assert(this->_tailPtr == op->tag);
this->_tailPtr++;
this->txCplRing->complete(op->tag, op->len, true);
delete op;
break;
default:
fprintf(stderr, "Unknown DMA type %u\n", op->type);
abort();
}
}
RxRing::RxRing(CplRing *cplRing)
: rxCplRing(cplRing)
{
}
RxRing::~RxRing()
{
}
void
RxRing::dmaDone(DMAOp *op)
{
switch (op->type) {
case DMA_TYPE_DESC: {
assert(!op->write);
Desc *desc = (Desc *)op->data;
op->type = DMA_TYPE_MEM;
op->dma_addr = desc->addr;
op->len = op->rx_data->len;
memcpy((void *)op->data, (void *)op->rx_data->data, op->len);
delete op->rx_data;
op->write = true;
issue_dma_op(op);
break;
}
case DMA_TYPE_MEM:
assert(op->write);
// TODO: assume in order transmission
assert(this->_tailPtr == op->tag);
this->_tailPtr++;
this->rxCplRing->complete(op->tag, op->len, false);
delete op;
break;
default:
fprintf(stderr, "Unknown DMA type %u\n", op->type);
abort();
}
}
void
RxRing::rx(RxData *rx_data)
{
if (empty()) {
delete rx_data;
return;
}
addr_t dma_addr = this->_dmaAddr + (this->_currTail & this->_sizeMask) * DESC_SIZE;
/* Issue DMA read */
DMAOp *op = new DMAOp;
op->type = DMA_TYPE_DESC;
op->dma_addr = dma_addr;
op->len = DESC_SIZE;
op->ring = this;
op->rx_data = rx_data;
op->tag = this->_currTail;
op->write = false;
issue_dma_op(op);
this->_currTail++;
}
Port::Port()
: _id(0), _features(0), _mtu(0),
_schedCount(0), _schedOffset(0), _schedStride(0),
_schedType(0), _rssMask(0), _schedEnable(false),
_queueEnable(false)
{
}
Port::~Port()
{
}
unsigned
Port::id()
{
return this->_id;
}
unsigned
Port::features()
{
return this->_features;
}
size_t
Port::mtu()
{
return this->_mtu;
}
size_t
Port::schedCount()
{
return this->_schedCount;
}
addr_t
Port::schedOffset()
{
return this->_schedOffset;
}
addr_t
Port::schedStride()
{
return this->_schedStride;
}
unsigned
Port::schedType()
{
return this->_schedType;
}
unsigned
Port::rssMask()
{
return this->_rssMask;
}
void
Port::setId(unsigned id)
{
this->_id = id;
}
void
Port::setFeatures(unsigned features)
{
this->_features = features & (IF_FEATURE_RSS |
IF_FEATURE_PTP_TS |
IF_FEATURE_TX_CSUM |
IF_FEATURE_RX_CSUM |
IF_FEATURE_RX_HASH);
}
void
Port::setMtu(size_t mtu)
{
this->_mtu = mtu;
}
void
Port::setSchedCount(size_t count)
{
this->_schedCount = count;
}
void
Port::setSchedOffset(addr_t offset)
{
this->_schedOffset = offset;
}
void
Port::setSchedStride(addr_t stride)
{
this->_schedStride = stride;
}
void
Port::setSchedType(unsigned type)
{
this->_schedType = type;
}
void
Port::setRssMask(unsigned mask)
{
this->_rssMask = mask;
}
void
Port::schedEnable()
{
this->_schedEnable = true;
}
void
Port::schedDisable()
{
this->_schedEnable = false;
}
void
Port::queueEnable()
{
this->_queueEnable = true;
}
void
Port::queueDisable()
{
this->_queueEnable = false;
}
Corundum::Corundum()
: txCplRing(&this->eventRing), rxCplRing(&this->eventRing),
txRing(&this->txCplRing), rxRing(&this->rxCplRing)
{
this->port.setId(0);
this->port.setFeatures(0x711);
this->port.setMtu(2048);
this->port.setSchedCount(1);
this->port.setSchedOffset(0x100000);
this->port.setSchedStride(0x100000);
this->port.setSchedType(0);
this->port.setRssMask(0);
this->port.schedDisable();
}
Corundum::~Corundum()
{
}
reg_t
Corundum::readReg(addr_t addr)
{
switch (addr) {
case REG_FW_ID:
return 32;
case REG_FW_VER:
return 1;
case REG_BOARD_ID:
return 0x43215678;
case REG_BOARD_VER:
return 1;
case REG_PHC_COUNT:
return 1;
case REG_PHC_OFFSET:
return 0x200;
case REG_PHC_STRIDE:
return 0x80;
case REG_IF_COUNT:
return 1;
case REG_IF_STRIDE:
return 0x80000;
case REG_IF_CSR_OFFSET:
return 0x80000;
case PHC_REG_FEATURES:
return 0x1;
case PHC_REG_PTP_CUR_SEC_L:
return 0x0;
case PHC_REG_PTP_CUR_SEC_H:
return 0x0;
case IF_REG_IF_ID:
return 0;
case IF_REG_IF_FEATURES:
return 0x711;
case IF_REG_EVENT_QUEUE_COUNT:
return 1;
case IF_REG_EVENT_QUEUE_OFFSET:
return 0x100000;
case IF_REG_TX_QUEUE_COUNT:
return 1;
case IF_REG_TX_QUEUE_OFFSET:
return 0x200000;
case IF_REG_TX_CPL_QUEUE_COUNT:
return 1;
case IF_REG_TX_CPL_QUEUE_OFFSET:
return 0x400000;
case IF_REG_RX_QUEUE_COUNT:
return 1;
case IF_REG_RX_QUEUE_OFFSET:
return 0x600000;
case IF_REG_RX_CPL_QUEUE_COUNT:
return 1;
case IF_REG_RX_CPL_QUEUE_OFFSET:
return 0x700000;
case IF_REG_PORT_COUNT:
return 1;
case IF_REG_PORT_OFFSET:
return 0x800000;
case IF_REG_PORT_STRIDE:
return 0x200000;
case EVENT_QUEUE_HEAD_PTR_REG:
return this->eventRing.headPtr();
case TX_QUEUE_ACTIVE_LOG_SIZE_REG:
return this->txRing.sizeLog();
case TX_QUEUE_TAIL_PTR_REG:
return this->txRing.tailPtr();
case TX_CPL_QUEUE_HEAD_PTR_REG:
return this->txCplRing.headPtr();
case RX_QUEUE_TAIL_PTR_REG:
return this->rxRing.tailPtr();
case RX_CPL_QUEUE_HEAD_PTR_REG:
return this->rxCplRing.headPtr();
case PORT_REG_PORT_ID:
return this->port.id();
case PORT_REG_PORT_FEATURES:
return this->port.features();
case PORT_REG_PORT_MTU:
return this->port.mtu();
case PORT_REG_SCHED_COUNT:
return this->port.schedCount();
case PORT_REG_SCHED_OFFSET:
return this->port.schedOffset();
case PORT_REG_SCHED_STRIDE:
return this->port.schedStride();
case PORT_REG_SCHED_TYPE:
return this->port.schedType();
default:
fprintf(stderr, "Unknown register read %lx\n", addr);
abort();
}
}
void
Corundum::writeReg(addr_t addr, reg_t val)
{
switch (addr) {
case REG_FW_ID:
case REG_FW_VER:
case REG_BOARD_ID:
case REG_BOARD_VER:
case REG_PHC_COUNT:
case REG_PHC_OFFSET:
case REG_PHC_STRIDE:
case REG_IF_COUNT:
case REG_IF_STRIDE:
case REG_IF_CSR_OFFSET:
case PHC_REG_FEATURES:
case PHC_REG_PTP_SET_FNS:
case PHC_REG_PTP_SET_NS:
case PHC_REG_PTP_SET_SEC_L:
case PHC_REG_PTP_SET_SEC_H:
break;
case EVENT_QUEUE_BASE_ADDR_REG:
this->eventRing.setDMALower(val);
break;
case EVENT_QUEUE_BASE_ADDR_REG + 4:
this->eventRing.setDMAUpper(val);
break;
case EVENT_QUEUE_ACTIVE_LOG_SIZE_REG:
this->eventRing.setSizeLog(val);
break;
case EVENT_QUEUE_INTERRUPT_INDEX_REG:
this->eventRing.setIndex(val);
break;
case EVENT_QUEUE_HEAD_PTR_REG:
this->eventRing.setHeadPtr(val);
break;
case EVENT_QUEUE_TAIL_PTR_REG:
this->eventRing.setTailPtr(val);
break;
case TX_QUEUE_BASE_ADDR_REG:
this->txRing.setDMALower(val);
break;
case TX_QUEUE_BASE_ADDR_REG + 4:
this->txRing.setDMAUpper(val);
break;
case TX_QUEUE_ACTIVE_LOG_SIZE_REG:
this->txRing.setSizeLog(val);
break;
case TX_QUEUE_CPL_QUEUE_INDEX_REG:
this->txRing.setIndex(val);
break;
case TX_QUEUE_HEAD_PTR_REG:
this->txRing.setHeadPtr(val);
break;
case TX_QUEUE_TAIL_PTR_REG:
this->txRing.setTailPtr(val);
break;
case TX_CPL_QUEUE_BASE_ADDR_REG:
this->txCplRing.setDMALower(val);
break;
case TX_CPL_QUEUE_BASE_ADDR_REG + 4:
this->txCplRing.setDMAUpper(val);
break;
case TX_CPL_QUEUE_ACTIVE_LOG_SIZE_REG:
this->txCplRing.setSizeLog(val);
break;
case TX_CPL_QUEUE_INTERRUPT_INDEX_REG:
this->txCplRing.setIndex(val);
break;
case TX_CPL_QUEUE_HEAD_PTR_REG:
this->txCplRing.setHeadPtr(val);
break;
case TX_CPL_QUEUE_TAIL_PTR_REG:
this->txCplRing.setTailPtr(val);
break;
case RX_QUEUE_BASE_ADDR_REG:
this->rxRing.setDMALower(val);
break;
case RX_QUEUE_BASE_ADDR_REG + 4:
this->rxRing.setDMAUpper(val);
break;
case RX_QUEUE_ACTIVE_LOG_SIZE_REG:
this->rxRing.setSizeLog(val);
break;
case RX_QUEUE_CPL_QUEUE_INDEX_REG:
this->rxRing.setIndex(val);
break;
case RX_QUEUE_HEAD_PTR_REG:
this->rxRing.setHeadPtr(val);
break;
case RX_QUEUE_TAIL_PTR_REG:
this->rxRing.setTailPtr(val);
break;
case RX_CPL_QUEUE_BASE_ADDR_REG:
this->rxCplRing.setDMALower(val);
break;
case RX_CPL_QUEUE_BASE_ADDR_REG + 4:
this->rxCplRing.setDMAUpper(val);
break;
case RX_CPL_QUEUE_ACTIVE_LOG_SIZE_REG:
this->rxCplRing.setSizeLog(val);
break;
case RX_CPL_QUEUE_INTERRUPT_INDEX_REG:
this->rxCplRing.setIndex(val);
break;
case RX_CPL_QUEUE_HEAD_PTR_REG:
this->rxCplRing.setHeadPtr(val);
break;
case RX_CPL_QUEUE_TAIL_PTR_REG:
this->rxCplRing.setTailPtr(val);
break;
case PORT_REG_SCHED_ENABLE:
if (val) {
this->port.schedEnable();
} else {
this->port.schedDisable();
}
break;
case PORT_REG_RSS_MASK:
this->port.setRssMask(val);
break;
case PORT_QUEUE_ENABLE:
if (val) {
this->port.queueEnable();
} else {
this->port.queueDisable();
}
break;
default:
fprintf(stderr, "Unknown register write %lx\n", addr);
abort();
}
}
void
Corundum::rx(uint8_t port, RxData *rx_data)
{
this->rxRing.rx(rx_data);
}
} //namespace corundum
using namespace corundum;
static volatile int exiting = 0;
static void
sigint_handler(int dummy)
{
exiting = 1;
}
static volatile union cosim_pcie_proto_d2h *
d2h_alloc(void)
{
volatile union cosim_pcie_proto_d2h *msg = nicsim_d2h_alloc();
if (msg == NULL) {
fprintf(stderr, "d2h_alloc: no entry available\n");
abort();
}
return msg;
}
static volatile union cosim_eth_proto_d2n *
d2n_alloc(void)
{
volatile union cosim_eth_proto_d2n *msg = nicsim_d2n_alloc();
if (msg == NULL) {
fprintf(stderr, "d2n_alloc: no entry available\n");
abort();
}
return msg;
}
static void
issue_dma_op(DMAOp *op)
{
volatile union cosim_pcie_proto_d2h *msg = d2h_alloc();
//printf("issue dma op %p addr %lx len %u\n", op, op->dma_addr, op->len);
if (op->write) {
volatile struct cosim_pcie_proto_d2h_write *write = &msg->write;
write->req_id = (uintptr_t)op;
write->offset = op->dma_addr;
write->len = op->len;
memcpy((void *)write->data, (void *)op->data, op->len);
// WMB();
write->own_type = COSIM_PCIE_PROTO_D2H_MSG_WRITE |
COSIM_PCIE_PROTO_D2H_OWN_HOST;
} else {
volatile struct cosim_pcie_proto_d2h_read *read = &msg->read;
read->req_id = (uintptr_t)op;
read->offset = op->dma_addr;
read->len = op->len;
// WMB();
read->own_type = COSIM_PCIE_PROTO_D2H_MSG_READ |
COSIM_PCIE_PROTO_D2H_OWN_HOST;
}
}
static void
msi_issue(uint8_t vec)
{
volatile union cosim_pcie_proto_d2h *msg = d2h_alloc();
//printf("issue MSI interrupt vec %u\n", vec);
volatile struct cosim_pcie_proto_d2h_interrupt *intr = &msg->interrupt;
intr->vector = vec;
intr->inttype = COSIM_PCIE_PROTO_INT_MSI;
// WMB();
intr->own_type = COSIM_PCIE_PROTO_D2H_MSG_INTERRUPT |
COSIM_PCIE_PROTO_D2H_OWN_HOST;
}
static void
h2d_read(Corundum &nic, volatile struct cosim_pcie_proto_h2d_read *read)
{
reg_t val = nic.readReg(read->offset);
//printf("read(off=0x%lx, len=%u, val=0x%x)\n", read->offset, read->len, val);
volatile union cosim_pcie_proto_d2h *msg;
volatile struct cosim_pcie_proto_d2h_readcomp *rc;
msg = d2h_alloc();
rc = &msg->readcomp;
memcpy((void *)rc->data, &val, read->len);
rc->req_id = read->req_id;
//WMB();
rc->own_type = COSIM_PCIE_PROTO_D2H_MSG_READCOMP |
COSIM_PCIE_PROTO_D2H_OWN_HOST;
}
static void
h2d_write(Corundum &nic, volatile struct cosim_pcie_proto_h2d_write *write)
{
reg_t val = 0;
memcpy(&val, (void *)write->data, write->len);
volatile union cosim_pcie_proto_d2h *msg;
volatile struct cosim_pcie_proto_d2h_writecomp *wc;
msg = d2h_alloc();
wc = &msg->writecomp;
//printf("write(off=0x%lx, len=%u, val=0x%x)\n", write->offset, write->len, val);
nic.writeReg(write->offset, val);
wc->req_id = write->req_id;
//WMB();
wc->own_type = COSIM_PCIE_PROTO_D2H_MSG_WRITECOMP |
COSIM_PCIE_PROTO_D2H_OWN_HOST;
}
static void h2d_readcomp(volatile struct cosim_pcie_proto_h2d_readcomp *rc)
{
DMAOp *op = (DMAOp *)(uintptr_t)rc->req_id;
memcpy(op->data, (void *)rc->data, op->len);
op->ring->dmaDone(op);
}
static void h2d_writecomp(volatile struct cosim_pcie_proto_h2d_writecomp *wc)
{
DMAOp *op = (DMAOp *)(uintptr_t)wc->req_id;
op->ring->dmaDone(op);
}
static void eth_recv(Corundum &nic,
volatile struct cosim_eth_proto_n2d_recv *recv)
{
//printf("RX recv(port=%u, len=%u)\n", recv->port, recv->len);
RxData *rx_data = new RxData;
memcpy((void *)rx_data->data, (void *)recv->data, recv->len);
rx_data->len = recv->len;
nic.rx(recv->port, rx_data);
}
static void eth_send(void *data, size_t len)
{
volatile union cosim_eth_proto_d2n *msg = d2n_alloc();
volatile struct cosim_eth_proto_d2n_send *send = &msg->send;
send->port = 0; // single port
send->len = len;
memcpy((void *)send->data, data, len);
send->own_type = COSIM_ETH_PROTO_D2N_MSG_SEND |
COSIM_ETH_PROTO_D2N_OWN_NET;
}
static void poll_h2d(Corundum &nic)
{
volatile union cosim_pcie_proto_h2d *msg = nicif_h2d_poll();
uint8_t type;
if (msg == NULL)
return;
type = msg->dummy.own_type & COSIM_PCIE_PROTO_H2D_MSG_MASK;
switch (type) {
case COSIM_PCIE_PROTO_H2D_MSG_READ:
h2d_read(nic, &msg->read);
break;
case COSIM_PCIE_PROTO_H2D_MSG_WRITE:
h2d_write(nic, &msg->write);
break;
case COSIM_PCIE_PROTO_H2D_MSG_READCOMP:
h2d_readcomp(&msg->readcomp);
break;
case COSIM_PCIE_PROTO_H2D_MSG_WRITECOMP:
h2d_writecomp(&msg->writecomp);
break;
default:
fprintf(stderr, "poll_h2d: unsupported type=%u\n", type);
}
nicif_h2d_done(msg);
nicif_h2d_next();
}
static void poll_n2d(Corundum &nic)
{
volatile union cosim_eth_proto_n2d *msg = nicif_n2d_poll();
uint8_t t;
if (msg == NULL)
return;
t = msg->dummy.own_type & COSIM_ETH_PROTO_N2D_MSG_MASK;
switch (t) {
case COSIM_ETH_PROTO_N2D_MSG_RECV:
eth_recv(nic, &msg->recv);
break;
default:
fprintf(stderr, "poll_n2d: unsupported type=%u", t);
}
nicif_n2d_done(msg);
nicif_n2d_next();
}
int main(int argc, char *argv[])
{
signal(SIGINT, sigint_handler);
struct cosim_pcie_proto_dev_intro di;
memset(&di, 0, sizeof(di));
di.bars[0].len = 1 << 24;
di.bars[0].flags = COSIM_PCIE_PROTO_BAR_64;
di.pci_vendor_id = 0x5543;
di.pci_device_id = 0x1001;
di.pci_class = 0x02;
di.pci_subclass = 0x00;
di.pci_revision = 0x00;
di.pci_msi_nvecs = 32;
int sync_pci_en = 0, sync_eth_en = 0;
if (nicsim_init(&di, "/tmp/cosim-pci", &sync_pci_en,
"/tmp/cosim-eth", &sync_eth_en,
"/dev/shm/dummy_nic_shm")) {
return EXIT_FAILURE;
}
Corundum nic;
while (!exiting) {
poll_h2d(nic);
poll_n2d(nic);
}
nicsim_cleanup();
return 0;
}
#pragma once
#include <stdint.h>
typedef uint32_t reg_t;
typedef uint64_t addr_t;
typedef uint16_t ptr_t;
#define REG_FW_ID 0x0000
#define REG_FW_VER 0x0004
#define REG_BOARD_ID 0x0008
#define REG_BOARD_VER 0x000C
#define REG_PHC_COUNT 0x0010
#define REG_PHC_OFFSET 0x0014
#define REG_PHC_STRIDE 0x0018
#define REG_IF_COUNT 0x0020
#define REG_IF_STRIDE 0x0024
#define REG_IF_CSR_OFFSET 0x002C
#define IF_FEATURE_RSS (1 << 0)
#define IF_FEATURE_PTP_TS (1 << 4)
#define IF_FEATURE_TX_CSUM (1 << 8)
#define IF_FEATURE_RX_CSUM (1 << 9)
#define IF_FEATURE_RX_HASH (1 << 10)
#define PHC_REG_FEATURES 0x0200
#define PHC_REG_PTP_CUR_SEC_L 0x0218
#define PHC_REG_PTP_CUR_SEC_H 0x021C
#define PHC_REG_PTP_SET_FNS 0x0230
#define PHC_REG_PTP_SET_NS 0x0234
#define PHC_REG_PTP_SET_SEC_L 0x0238
#define PHC_REG_PTP_SET_SEC_H 0x023C
#define IF_REG_IF_ID 0x80000
#define IF_REG_IF_FEATURES 0x80004
#define IF_REG_EVENT_QUEUE_COUNT 0x80010
#define IF_REG_EVENT_QUEUE_OFFSET 0x80014
#define IF_REG_TX_QUEUE_COUNT 0x80020
#define IF_REG_TX_QUEUE_OFFSET 0x80024
#define IF_REG_TX_CPL_QUEUE_COUNT 0x80028
#define IF_REG_TX_CPL_QUEUE_OFFSET 0x8002C
#define IF_REG_RX_QUEUE_COUNT 0x80030
#define IF_REG_RX_QUEUE_OFFSET 0x80034
#define IF_REG_RX_CPL_QUEUE_COUNT 0x80038
#define IF_REG_RX_CPL_QUEUE_OFFSET 0x8003C
#define IF_REG_PORT_COUNT 0x80040
#define IF_REG_PORT_OFFSET 0x80044
#define IF_REG_PORT_STRIDE 0x80048
#define QUEUE_ACTIVE_MASK 0x80000000
#define QUEUE_ARM_MASK 0x80000000
#define QUEUE_CONT_MASK 0x40000000
#define EVENT_QUEUE_BASE_ADDR_REG 0x100000
#define EVENT_QUEUE_ACTIVE_LOG_SIZE_REG 0x100008
#define EVENT_QUEUE_INTERRUPT_INDEX_REG 0x10000C
#define EVENT_QUEUE_HEAD_PTR_REG 0x100010
#define EVENT_QUEUE_TAIL_PTR_REG 0x100018
#define TX_QUEUE_BASE_ADDR_REG 0x200000
#define TX_QUEUE_ACTIVE_LOG_SIZE_REG 0x200008
#define TX_QUEUE_CPL_QUEUE_INDEX_REG 0x20000C
#define TX_QUEUE_HEAD_PTR_REG 0x200010
#define TX_QUEUE_TAIL_PTR_REG 0x200018
#define TX_CPL_QUEUE_BASE_ADDR_REG 0x400000
#define TX_CPL_QUEUE_ACTIVE_LOG_SIZE_REG 0x400008
#define TX_CPL_QUEUE_INTERRUPT_INDEX_REG 0x40000C
#define TX_CPL_QUEUE_HEAD_PTR_REG 0x400010
#define TX_CPL_QUEUE_TAIL_PTR_REG 0x400018
#define RX_QUEUE_BASE_ADDR_REG 0x600000
#define RX_QUEUE_ACTIVE_LOG_SIZE_REG 0x600008
#define RX_QUEUE_CPL_QUEUE_INDEX_REG 0x60000C
#define RX_QUEUE_HEAD_PTR_REG 0x600010
#define RX_QUEUE_TAIL_PTR_REG 0x600018
#define RX_CPL_QUEUE_BASE_ADDR_REG 0x700000
#define RX_CPL_QUEUE_ACTIVE_LOG_SIZE_REG 0x700008
#define RX_CPL_QUEUE_INTERRUPT_INDEX_REG 0x70000C
#define RX_CPL_QUEUE_HEAD_PTR_REG 0x700010
#define RX_CPL_QUEUE_TAIL_PTR_REG 0x700018
#define PORT_REG_PORT_ID 0x800000
#define PORT_REG_PORT_FEATURES 0x800004
#define PORT_REG_PORT_MTU 0x800008
#define PORT_REG_SCHED_COUNT 0x800010
#define PORT_REG_SCHED_OFFSET 0x800014
#define PORT_REG_SCHED_STRIDE 0x800018
#define PORT_REG_SCHED_TYPE 0x80001C
#define PORT_REG_SCHED_ENABLE 0x800040
#define PORT_REG_RSS_MASK 0x800080
#define PORT_QUEUE_ENABLE 0x900000
namespace corundum {
#define DESC_SIZE 16
#define CPL_SIZE 32
#define EVENT_SIZE 32
#define MAX_DMA_LEN 2048
class DescRing;
struct Desc {
uint16_t rsvd0;
uint16_t tx_csum_cmd;
uint32_t len;
uint64_t addr;
} __attribute__((packed)) ;
struct Cpl {
uint16_t queue;
uint16_t index;
uint16_t len;
uint16_t rsvd0;
uint32_t ts_ns;
uint16_t ts_s;
uint16_t rx_csum;
uint32_t rx_hash;
uint8_t rx_hash_type;
uint8_t rsvd1;
uint8_t rsvd2;
uint8_t rsvd3;
uint32_t rsvd4;
uint32_t rsvd5;
} __attribute__((packed)) ;
#define EVENT_TYPE_TX_CPL 0x0000
#define EVENT_TYPE_RX_CPL 0x0001
struct Event {
uint16_t type;
uint16_t source;
} __attribute__((packed)) ;
struct RxData {
size_t len;
uint8_t data[MAX_DMA_LEN];
};
#define DMA_TYPE_DESC 0
#define DMA_TYPE_MEM 1
#define DMA_TYPE_TX_CPL 2
#define DMA_TYPE_RX_CPL 3
#define DMA_TYPE_EVENT 4
struct DMAOp {
uint8_t type;
addr_t dma_addr;
size_t len;
DescRing *ring;
RxData *rx_data;
uint64_t tag;
bool write;
uint8_t data[MAX_DMA_LEN];
};
class DescRing {
public:
DescRing();
~DescRing();
addr_t dmaAddr();
size_t sizeLog();
unsigned index();
ptr_t headPtr();
ptr_t tailPtr();
void setDMALower(uint32_t addr);
void setDMAUpper(uint32_t addr);
void setSizeLog(size_t size_log);
void setIndex(unsigned index);
virtual void setHeadPtr(ptr_t ptr);
void setTailPtr(ptr_t ptr);
virtual void dmaDone(DMAOp *op) = 0;
protected:
bool empty();
bool full();
addr_t _dmaAddr;
size_t _sizeLog;
size_t _size;
size_t _sizeMask;
unsigned _index;
ptr_t _headPtr;
ptr_t _tailPtr;
ptr_t _currHead;
ptr_t _currTail;
bool active;
};
class EventRing : public DescRing {
public:
EventRing();
~EventRing();
virtual void dmaDone(DMAOp *op) override;
void issueEvent(unsigned type, unsigned source);
};
class CplRing : public DescRing {
public:
CplRing(EventRing *eventRing);
~CplRing();
virtual void dmaDone(DMAOp *op) override;
void complete(unsigned index, size_t len, bool tx);
private:
EventRing *eventRing;
};
class TxRing : public DescRing {
public:
TxRing(CplRing *cplRing);
~TxRing();
virtual void setHeadPtr(ptr_t ptr) override;
virtual void dmaDone(DMAOp *op) override;
private:
CplRing *txCplRing;
};
class RxRing : public DescRing {
public:
RxRing(CplRing *cplRing);
~RxRing();
virtual void dmaDone(DMAOp *op) override;
void rx(RxData *rx_data);
private:
CplRing *rxCplRing;
};
class Port {
public:
Port();
~Port();
unsigned id();
unsigned features();
size_t mtu();
size_t schedCount();
addr_t schedOffset();
addr_t schedStride();
unsigned schedType();
unsigned rssMask();
void setId(unsigned id);
void setFeatures(unsigned features);
void setMtu(size_t mtu);
void setSchedCount(size_t count);
void setSchedOffset(addr_t offset);
void setSchedStride(addr_t stride);
void setSchedType(unsigned type);
void setRssMask(unsigned mask);
void schedEnable();
void schedDisable();
void queueEnable();
void queueDisable();
private:
unsigned _id;
unsigned _features;
size_t _mtu;
size_t _schedCount;
addr_t _schedOffset;
addr_t _schedStride;
unsigned _schedType;
unsigned _rssMask;
bool _schedEnable;
bool _queueEnable;
};
class Corundum {
public:
Corundum();
~Corundum();
reg_t readReg(addr_t addr);
void writeReg(addr_t addr, reg_t val);
void rx(uint8_t port, RxData *rx_data);
private:
EventRing eventRing;
TxRing txRing;
CplRing txCplRing;
RxRing rxRing;
CplRing rxCplRing;
Port port;
};
} // namespace corundum
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <assert.h>
#include <nicsim.h>
#include <cosim_pcie_proto.h>
static uint8_t *d2h_queue;
static size_t d2h_pos;
static size_t d2h_elen;
static size_t d2h_enum;
static uint8_t *h2d_queue;
static size_t h2d_pos;
static size_t h2d_elen;
static size_t h2d_enum;
static void sigint_handler(int dummy)
{
exit(1);
}
static int uxsocket_init()
{
int cfd;
if ((cfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
return -1;
}
struct sockaddr_un saun;
memset(&saun, 0, sizeof(saun));
saun.sun_family = AF_UNIX;
memcpy(saun.sun_path, "/tmp/cosim-pci", strlen("/tmp/cosim-pci"));
if (connect(cfd, (struct sockaddr *)&saun, sizeof(saun)) == -1) {
close(cfd);
return -1;
}
return cfd;
}
static int queue_create(const struct cosim_pcie_proto_dev_intro di)
{
int fd = -1;
if ((fd = open("/dev/shm/dummy_nic_shm", O_RDWR)) == -1) {
perror("Failed to open shm file");
goto error;
}
void *addr;
if ((addr = mmap(NULL, 32 * 1024 * 1024, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_POPULATE, fd, 0)) == (void *)-1) {
perror("mmap failed");
goto error;
}
d2h_queue = (uint8_t *)addr + di.d2h_offset;
d2h_pos = 0;
d2h_elen = di.d2h_elen;
d2h_enum = di.d2h_nentries;
h2d_queue = (uint8_t *)addr + di.h2d_offset;
h2d_pos = 0;
h2d_elen = di.h2d_elen;
h2d_enum = di.h2d_nentries;
return 0;
error:
if (fd > 0) {
close(fd);
}
return -1;
}
volatile union cosim_pcie_proto_h2d *h2d_alloc()
{
volatile union cosim_pcie_proto_h2d *msg =
(volatile union cosim_pcie_proto_h2d *)
(h2d_queue + h2d_pos * h2d_elen);
if ((msg->dummy.own_type & COSIM_PCIE_PROTO_H2D_OWN_MASK) !=
COSIM_PCIE_PROTO_H2D_OWN_HOST) {
fprintf(stderr, "cosim: failed to allocate h2d message\n");
exit(1);
}
h2d_pos = (h2d_pos + 1) % h2d_enum;
return msg;
}
volatile union cosim_pcie_proto_d2h *d2h_poll()
{
volatile union cosim_pcie_proto_d2h *msg;
msg = (volatile union cosim_pcie_proto_d2h *)
(d2h_queue + d2h_pos * d2h_elen);
if ((msg->dummy.own_type & COSIM_PCIE_PROTO_D2H_OWN_MASK) ==
COSIM_PCIE_PROTO_D2H_OWN_DEV) {
return NULL;
}
return msg;
}
void d2h_done(volatile union cosim_pcie_proto_d2h *msg)
{
msg->dummy.own_type = (msg->dummy.own_type & COSIM_PCIE_PROTO_D2H_MSG_MASK) |
COSIM_PCIE_PROTO_D2H_OWN_DEV;
d2h_pos = (d2h_pos + 1) % d2h_enum;
}
static void dev_read(uint64_t offset, uint16_t len)
{
volatile union cosim_pcie_proto_h2d *h2d_msg = h2d_alloc();
volatile struct cosim_pcie_proto_h2d_read *read = &h2d_msg->read;
read->req_id = 0xF;
read->offset = offset;
read->len = len;
read->bar = 0;
read->own_type = COSIM_PCIE_PROTO_H2D_MSG_READ | COSIM_PCIE_PROTO_H2D_OWN_DEV;
volatile union cosim_pcie_proto_d2h *d2h_msg = NULL;
while (d2h_msg == NULL) {
d2h_msg = d2h_poll();
}
volatile struct cosim_pcie_proto_d2h_readcomp *rc;
rc = &d2h_msg->readcomp;
assert(rc->req_id == 0xF);
printf("received readcomp with data ");
for (int i = 0; i < read->len; i++) {
printf("%x ", ((const uint8_t *)rc->data)[i]);
}
printf("\n");
d2h_done(d2h_msg);
}
int main(int argc, char *argv[])
{
signal(SIGINT, sigint_handler);
int cfd;
if ((cfd = uxsocket_init()) < 0) {
fprintf(stderr, "Failed to open unix socket\n");
return -1;
}
struct cosim_pcie_proto_dev_intro di;
if (recv(cfd, &di, sizeof(di), 0) != sizeof(di)) {
perror("Failed to receive dev_intro");
close(cfd);
return -1;
}
if (queue_create(di) != 0) {
fprintf(stderr, "Failed to create shm queues\n");
close(cfd);
return -1;
}
struct cosim_pcie_proto_host_intro hi;
hi.flags = COSIM_PCIE_PROTO_FLAGS_HI_SYNC;
if (send(cfd, &hi, sizeof(hi), 0) != sizeof(hi)) {
perror("Failed to send host_intro");
close(cfd);
return -1;
}
while (1) {
int op_type;
uint64_t offset;
uint16_t len;
printf("op type (0-read): ");
scanf("%d", &op_type);
printf("offset: ");
scanf("%lx", &offset);
printf("len: ");
scanf("%hu", &len);
switch (op_type) {
case 0:
dev_read(offset, len);
break;
default:
fprintf(stderr, "Unimplemented type %u\n", op_type);
}
}
close(cfd);
return 0;
}
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