mirror of
https://github.com/fpganinja/taxi.git
synced 2026-04-09 05:18:44 -07:00
Compare commits
8 Commits
0d4a030e3f
...
f8f73ea570
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8f73ea570 | ||
|
|
9f56b9febd | ||
|
|
6bf7240686 | ||
|
|
8494e734a8 | ||
|
|
4d8f0cfece | ||
|
|
191f7940b3 | ||
|
|
0ab7538e24 | ||
|
|
902996e3bd |
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: CERN-OHL-S-2.0
|
||||
/*
|
||||
|
||||
Copyright (c) 2018-2025 FPGA Ninja, LLC
|
||||
Copyright (c) 2018-2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
@@ -19,6 +19,8 @@ module taxi_axis_demux #
|
||||
(
|
||||
// Number of AXI stream outputs
|
||||
parameter M_COUNT = 4,
|
||||
// route via tid
|
||||
parameter logic TID_ROUTE = 1'b0,
|
||||
// route via tdest
|
||||
parameter logic TDEST_ROUTE = 1'b0
|
||||
)
|
||||
@@ -53,6 +55,8 @@ localparam logic LAST_EN = s_axis.LAST_EN && m_axis[0].LAST_EN;
|
||||
localparam logic ID_EN = s_axis.ID_EN && m_axis[0].ID_EN;
|
||||
localparam ID_W = s_axis.ID_W;
|
||||
localparam logic DEST_EN = s_axis.DEST_EN && m_axis[0].DEST_EN;
|
||||
localparam S_ID_W = s_axis.ID_W;
|
||||
localparam M_ID_W = m_axis[0].ID_W;
|
||||
localparam S_DEST_W = s_axis.DEST_W;
|
||||
localparam M_DEST_W = m_axis[0].DEST_W;
|
||||
localparam logic USER_EN = s_axis.USER_EN && m_axis[0].USER_EN;
|
||||
@@ -61,6 +65,7 @@ localparam USER_W = s_axis.USER_W;
|
||||
localparam CL_M_COUNT = $clog2(M_COUNT);
|
||||
|
||||
localparam M_DEST_W_INT = M_DEST_W > 0 ? M_DEST_W : 1;
|
||||
localparam M_ID_W_INT = M_ID_W > 0 ? M_ID_W : 1;
|
||||
|
||||
// check configuration
|
||||
if (m_axis[0].DATA_W != DATA_W)
|
||||
@@ -69,6 +74,17 @@ if (m_axis[0].DATA_W != DATA_W)
|
||||
if (KEEP_EN && m_axis[0].KEEP_W != KEEP_W)
|
||||
$fatal(0, "Error: Interface KEEP_W parameter mismatch (instance %m)");
|
||||
|
||||
if (TID_ROUTE) begin
|
||||
if (!ID_EN)
|
||||
$fatal(0, "Error: TID_ROUTE set requires ID_EN set (instance %m)");
|
||||
|
||||
if (S_ID_W < CL_M_COUNT)
|
||||
$fatal(0, "Error: S_ID_W too small for port count (instance %m)");
|
||||
|
||||
if (TDEST_ROUTE)
|
||||
$fatal(0, "Error: Cannot enable both TID_ROUTE and TDEST_ROUTE (instance %m)");
|
||||
end
|
||||
|
||||
if (TDEST_ROUTE) begin
|
||||
if (!DEST_EN)
|
||||
$fatal(0, "Error: TDEST_ROUTE set requires DEST_EN set (instance %m)");
|
||||
@@ -90,7 +106,7 @@ logic [KEEP_W-1:0] m_axis_tstrb_int;
|
||||
logic [M_COUNT-1:0] m_axis_tvalid_int;
|
||||
logic m_axis_tready_int_reg = 1'b0;
|
||||
logic m_axis_tlast_int;
|
||||
logic [ID_W-1:0] m_axis_tid_int;
|
||||
logic [M_ID_W-1:0] m_axis_tid_int;
|
||||
logic [M_DEST_W-1:0] m_axis_tdest_int;
|
||||
logic [USER_W-1:0] m_axis_tuser_int;
|
||||
wire m_axis_tready_int_early;
|
||||
@@ -115,7 +131,15 @@ always_comb begin
|
||||
|
||||
if (!frame_reg && s_axis.tvalid && s_axis.tready) begin
|
||||
// start of frame, grab select value
|
||||
if (TDEST_ROUTE) begin
|
||||
if (TID_ROUTE) begin
|
||||
if (M_COUNT > 1) begin
|
||||
select_ctl = s_axis.tid[S_ID_W-1:S_ID_W-CL_M_COUNT];
|
||||
drop_ctl = (CL_M_COUNT+1)'(select_ctl) >= (CL_M_COUNT+1)'(M_COUNT);
|
||||
end else begin
|
||||
select_ctl = '0;
|
||||
drop_ctl = 1'b0;
|
||||
end
|
||||
end else if (TDEST_ROUTE) begin
|
||||
if (M_COUNT > 1) begin
|
||||
select_ctl = s_axis.tdest[S_DEST_W-1:S_DEST_W-CL_M_COUNT];
|
||||
drop_ctl = (CL_M_COUNT+1)'(select_ctl) >= (CL_M_COUNT+1)'(M_COUNT);
|
||||
@@ -141,7 +165,7 @@ always_comb begin
|
||||
m_axis_tvalid_int = '0;
|
||||
m_axis_tvalid_int[select_ctl] = s_axis.tvalid && s_axis.tready && !drop_ctl;
|
||||
m_axis_tlast_int = s_axis.tlast;
|
||||
m_axis_tid_int = s_axis.tid;
|
||||
m_axis_tid_int = M_ID_W'(s_axis.tid);
|
||||
m_axis_tdest_int = M_DEST_W'(s_axis.tdest);
|
||||
m_axis_tuser_int = s_axis.tuser;
|
||||
end
|
||||
@@ -170,7 +194,7 @@ logic [KEEP_W-1:0] m_axis_tkeep_reg = '0;
|
||||
logic [KEEP_W-1:0] m_axis_tstrb_reg = '0;
|
||||
logic [M_COUNT-1:0] m_axis_tvalid_reg = '0, m_axis_tvalid_next;
|
||||
logic m_axis_tlast_reg = 1'b0;
|
||||
logic [ID_W-1:0] m_axis_tid_reg = '0;
|
||||
logic [M_ID_W-1:0] m_axis_tid_reg = '0;
|
||||
logic [M_DEST_W-1:0] m_axis_tdest_reg = '0;
|
||||
logic [USER_W-1:0] m_axis_tuser_reg = '0;
|
||||
|
||||
@@ -179,7 +203,7 @@ logic [KEEP_W-1:0] temp_m_axis_tkeep_reg = '0;
|
||||
logic [KEEP_W-1:0] temp_m_axis_tstrb_reg = '0;
|
||||
logic [M_COUNT-1:0] temp_m_axis_tvalid_reg = '0, temp_m_axis_tvalid_next;
|
||||
logic temp_m_axis_tlast_reg = 1'b0;
|
||||
logic [ID_W-1:0] temp_m_axis_tid_reg = '0;
|
||||
logic [M_ID_W-1:0] temp_m_axis_tid_reg = '0;
|
||||
logic [M_DEST_W-1:0] temp_m_axis_tdest_reg = '0;
|
||||
logic [USER_W-1:0] temp_m_axis_tuser_reg = '0;
|
||||
|
||||
|
||||
@@ -40,12 +40,14 @@ export PARAM_KEEP_W := $(shell expr \( $(PARAM_DATA_W) + 7 \) / 8 )
|
||||
export PARAM_STRB_EN := 0
|
||||
export PARAM_LAST_EN := 1
|
||||
export PARAM_ID_EN := 1
|
||||
export PARAM_ID_W := 8
|
||||
export PARAM_M_ID_W := 8
|
||||
export PARAM_S_ID_W := $(shell python -c "print($(PARAM_M_ID_W) + ($(PARAM_M_COUNT)-1).bit_length())")
|
||||
export PARAM_DEST_EN := 1
|
||||
export PARAM_M_DEST_W := 8
|
||||
export PARAM_S_DEST_W := $(shell python -c "print($(PARAM_M_DEST_W) + ($(PARAM_M_COUNT)-1).bit_length())")
|
||||
export PARAM_USER_EN := 1
|
||||
export PARAM_USER_W := 1
|
||||
export PARAM_TID_ROUTE := 0
|
||||
export PARAM_TDEST_ROUTE := 1
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
|
||||
@@ -65,11 +65,11 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
id_width = len(tb.source.bus.tid)
|
||||
id_width = len(tb.sink[0].bus.tid)
|
||||
id_count = 2**id_width
|
||||
id_mask = id_count-1
|
||||
|
||||
dest_width = len(tb.sink[0].bus.tid)
|
||||
dest_width = len(tb.sink[0].bus.tdest)
|
||||
dest_count = 2**dest_width
|
||||
dest_mask = dest_count-1
|
||||
|
||||
@@ -183,12 +183,14 @@ def test_taxi_axis_demux(request, m_count, data_w, tdest_route):
|
||||
parameters['STRB_EN'] = 0
|
||||
parameters['LAST_EN'] = 1
|
||||
parameters['ID_EN'] = 1
|
||||
parameters['ID_W'] = 8
|
||||
parameters['M_ID_W'] = 8
|
||||
parameters['S_ID_W'] = parameters['M_ID_W'] + (m_count-1).bit_length()
|
||||
parameters['DEST_EN'] = 1
|
||||
parameters['M_DEST_W'] = 8
|
||||
parameters['S_DEST_W'] = parameters['M_DEST_W'] + (m_count-1).bit_length()
|
||||
parameters['USER_EN'] = 1
|
||||
parameters['USER_W'] = 1
|
||||
parameters['TID_ROUTE'] = 0
|
||||
parameters['TDEST_ROUTE'] = tdest_route
|
||||
|
||||
extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}
|
||||
|
||||
@@ -25,12 +25,14 @@ module test_taxi_axis_demux #
|
||||
parameter logic STRB_EN = 1'b0,
|
||||
parameter logic LAST_EN = 1'b1,
|
||||
parameter logic ID_EN = 1'b0,
|
||||
parameter ID_W = 8,
|
||||
parameter M_ID_W = 8,
|
||||
parameter S_ID_W = M_ID_W+$clog2(M_COUNT),
|
||||
parameter logic DEST_EN = 1'b0,
|
||||
parameter M_DEST_W = 8,
|
||||
parameter S_DEST_W = M_DEST_W+$clog2(M_COUNT),
|
||||
parameter logic USER_EN = 1'b1,
|
||||
parameter USER_W = 1,
|
||||
parameter logic TID_ROUTE = 1'b0,
|
||||
parameter logic TDEST_ROUTE = 1'b0
|
||||
/* verilator lint_on WIDTHTRUNC */
|
||||
)
|
||||
@@ -46,7 +48,7 @@ taxi_axis_if #(
|
||||
.STRB_EN(STRB_EN),
|
||||
.LAST_EN(LAST_EN),
|
||||
.ID_EN(ID_EN),
|
||||
.ID_W(ID_W),
|
||||
.ID_W(S_ID_W),
|
||||
.DEST_EN(DEST_EN),
|
||||
.DEST_W(S_DEST_W),
|
||||
.USER_EN(USER_EN),
|
||||
@@ -60,7 +62,7 @@ taxi_axis_if #(
|
||||
.STRB_EN(STRB_EN),
|
||||
.LAST_EN(LAST_EN),
|
||||
.ID_EN(ID_EN),
|
||||
.ID_W(ID_W),
|
||||
.ID_W(M_ID_W),
|
||||
.DEST_EN(DEST_EN),
|
||||
.DEST_W(M_DEST_W),
|
||||
.USER_EN(USER_EN),
|
||||
@@ -73,6 +75,7 @@ logic [$clog2(M_COUNT)-1:0] select;
|
||||
|
||||
taxi_axis_demux #(
|
||||
.M_COUNT(M_COUNT),
|
||||
.TID_ROUTE(TID_ROUTE),
|
||||
.TDEST_ROUTE(TDEST_ROUTE)
|
||||
)
|
||||
uut (
|
||||
|
||||
@@ -12,8 +12,9 @@ cndm-y += cndm_dev.o
|
||||
cndm-y += cndm_netdev.o
|
||||
cndm-y += cndm_ethtool.o
|
||||
cndm-y += cndm_ptp.o
|
||||
cndm-y += cndm_tx.o
|
||||
cndm-y += cndm_rx.o
|
||||
cndm-y += cndm_cq.o
|
||||
cndm-y += cndm_sq.o
|
||||
cndm-y += cndm_rq.o
|
||||
|
||||
ifneq ($(DEBUG),)
|
||||
ccflags-y += -DDEBUG
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL */
|
||||
/*
|
||||
|
||||
Copyright (c) 2025 FPGA Ninja, LLC
|
||||
Copyright (c) 2025-2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
@@ -73,6 +73,71 @@ struct cndm_rx_info {
|
||||
u32 len;
|
||||
};
|
||||
|
||||
struct cndm_ring {
|
||||
// written on enqueue
|
||||
u32 prod_ptr;
|
||||
u64 bytes;
|
||||
u64 packet;
|
||||
u64 dropped_packets;
|
||||
struct netdev_queue *tx_queue;
|
||||
|
||||
// written from completion
|
||||
u32 cons_ptr ____cacheline_aligned_in_smp;
|
||||
u64 ts_s;
|
||||
u8 ts_valid;
|
||||
|
||||
// mostly constant
|
||||
u32 size;
|
||||
u32 full_size;
|
||||
u32 size_mask;
|
||||
u32 stride;
|
||||
|
||||
u32 mtu;
|
||||
|
||||
size_t buf_size;
|
||||
u8 *buf;
|
||||
dma_addr_t buf_dma_addr;
|
||||
|
||||
union {
|
||||
struct cndm_tx_info *tx_info;
|
||||
struct cndm_rx_info *rx_info;
|
||||
};
|
||||
|
||||
struct device *dev;
|
||||
struct cndm_dev *cdev;
|
||||
struct cndm_priv *priv;
|
||||
int index;
|
||||
int enabled;
|
||||
|
||||
struct cndm_cq *cq;
|
||||
|
||||
u32 db_offset;
|
||||
u8 __iomem *db_addr;
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
struct cndm_cq {
|
||||
u32 cons_ptr;
|
||||
|
||||
u32 size;
|
||||
u32 size_mask;
|
||||
u32 stride;
|
||||
|
||||
size_t buf_size;
|
||||
u8 *buf;
|
||||
dma_addr_t buf_dma_addr;
|
||||
|
||||
struct device *dev;
|
||||
struct cndm_dev *cdev;
|
||||
struct cndm_priv *priv;
|
||||
struct napi_struct napi;
|
||||
int cqn;
|
||||
int enabled;
|
||||
|
||||
struct cndm_ring *src_ring;
|
||||
|
||||
void (*handler)(struct cndm_cq *cq);
|
||||
};
|
||||
|
||||
struct cndm_priv {
|
||||
struct device *dev;
|
||||
struct net_device *ndev;
|
||||
@@ -83,62 +148,18 @@ struct cndm_priv {
|
||||
|
||||
void __iomem *hw_addr;
|
||||
|
||||
size_t txq_region_len;
|
||||
void *txq_region;
|
||||
dma_addr_t txq_region_addr;
|
||||
|
||||
struct cndm_irq *irq;
|
||||
struct notifier_block irq_nb;
|
||||
|
||||
struct hwtstamp_config hwts_config;
|
||||
u64 ts_s;
|
||||
u8 ts_valid;
|
||||
|
||||
struct cndm_tx_info *tx_info;
|
||||
struct cndm_rx_info *rx_info;
|
||||
int rxq_count;
|
||||
int txq_count;
|
||||
|
||||
struct netdev_queue *tx_queue;
|
||||
|
||||
struct napi_struct tx_napi;
|
||||
struct napi_struct rx_napi;
|
||||
|
||||
u32 txq_log_size;
|
||||
u32 txq_size;
|
||||
u32 txq_mask;
|
||||
u32 txq_prod;
|
||||
u32 txq_cons;
|
||||
u32 txq_db_offs;
|
||||
|
||||
size_t rxq_region_len;
|
||||
void *rxq_region;
|
||||
dma_addr_t rxq_region_addr;
|
||||
|
||||
u32 rxq_log_size;
|
||||
u32 rxq_size;
|
||||
u32 rxq_mask;
|
||||
u32 rxq_prod;
|
||||
u32 rxq_cons;
|
||||
u32 rxq_db_offs;
|
||||
|
||||
size_t txcq_region_len;
|
||||
void *txcq_region;
|
||||
dma_addr_t txcq_region_addr;
|
||||
|
||||
u32 txcq_log_size;
|
||||
u32 txcq_size;
|
||||
u32 txcq_mask;
|
||||
u32 txcq_prod;
|
||||
u32 txcq_cons;
|
||||
|
||||
size_t rxcq_region_len;
|
||||
void *rxcq_region;
|
||||
dma_addr_t rxcq_region_addr;
|
||||
|
||||
u32 rxcq_log_size;
|
||||
u32 rxcq_size;
|
||||
u32 rxcq_mask;
|
||||
u32 rxcq_prod;
|
||||
u32 rxcq_cons;
|
||||
struct cndm_ring *txq;
|
||||
struct cndm_cq *txcq;
|
||||
struct cndm_ring *rxq;
|
||||
struct cndm_cq *rxcq;
|
||||
};
|
||||
|
||||
// cndm_cmd.c
|
||||
@@ -165,18 +186,32 @@ extern const struct file_operations cndm_fops;
|
||||
extern const struct ethtool_ops cndm_ethtool_ops;
|
||||
|
||||
// cndm_ptp.c
|
||||
ktime_t cndm_read_cpl_ts(struct cndm_priv *priv, const struct cndm_cpl *cpl);
|
||||
ktime_t cndm_read_cpl_ts(struct cndm_ring *ring, const struct cndm_cpl *cpl);
|
||||
void cndm_register_phc(struct cndm_dev *cdev);
|
||||
void cndm_unregister_phc(struct cndm_dev *cdev);
|
||||
|
||||
// cndm_tx.c
|
||||
int cndm_free_tx_buf(struct cndm_priv *priv);
|
||||
// cndm_cq.c
|
||||
struct cndm_cq *cndm_create_cq(struct cndm_priv *priv);
|
||||
void cndm_destroy_cq(struct cndm_cq *cq);
|
||||
int cndm_open_cq(struct cndm_cq *cq, int irqn, int size);
|
||||
void cndm_close_cq(struct cndm_cq *cq);
|
||||
|
||||
// cndm_sq.c
|
||||
struct cndm_ring *cndm_create_sq(struct cndm_priv *priv);
|
||||
void cndm_destroy_sq(struct cndm_ring *sq);
|
||||
int cndm_open_sq(struct cndm_ring *sq, struct cndm_priv *priv, struct cndm_cq *cq, int size);
|
||||
void cndm_close_sq(struct cndm_ring *sq);
|
||||
int cndm_free_tx_buf(struct cndm_ring *sq);
|
||||
int cndm_poll_tx_cq(struct napi_struct *napi, int budget);
|
||||
int cndm_start_xmit(struct sk_buff *skb, struct net_device *ndev);
|
||||
|
||||
// cndm_rx.c
|
||||
int cndm_free_rx_buf(struct cndm_priv *priv);
|
||||
int cndm_refill_rx_buffers(struct cndm_priv *priv);
|
||||
// cndm_rq.c
|
||||
struct cndm_ring *cndm_create_rq(struct cndm_priv *priv);
|
||||
void cndm_destroy_rq(struct cndm_ring *rq);
|
||||
int cndm_open_rq(struct cndm_ring *rq, struct cndm_priv *priv, struct cndm_cq *cq, int size);
|
||||
void cndm_close_rq(struct cndm_ring *rq);
|
||||
int cndm_free_rx_buf(struct cndm_ring *rq);
|
||||
int cndm_refill_rx_buffers(struct cndm_ring *rq);
|
||||
int cndm_poll_rx_cq(struct napi_struct *napi, int budget);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,6 +24,9 @@ int cndm_exec_mbox_cmd(struct cndm_dev *cdev, void *cmd, void *rsp)
|
||||
iowrite32(*((u32 *)(cmd + k*4)), cdev->hw_addr + 0x10000 + k*4);
|
||||
}
|
||||
|
||||
// ensure the command is completely written
|
||||
wmb();
|
||||
|
||||
// execute it
|
||||
iowrite32(0x00000001, cdev->hw_addr + 0x0200);
|
||||
|
||||
|
||||
112
src/cndm/modules/cndm/cndm_cq.c
Normal file
112
src/cndm/modules/cndm/cndm_cq.c
Normal file
@@ -0,0 +1,112 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#include "cndm.h"
|
||||
|
||||
struct cndm_cq *cndm_create_cq(struct cndm_priv *priv)
|
||||
{
|
||||
struct cndm_cq *cq;
|
||||
|
||||
cq = kzalloc(sizeof(*cq), GFP_KERNEL);
|
||||
if (!cq)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
cq->cdev = priv->cdev;
|
||||
cq->dev = priv->dev;
|
||||
cq->priv = priv;
|
||||
|
||||
cq->cqn = -1;
|
||||
cq->enabled = 0;
|
||||
|
||||
cq->cons_ptr = 0;
|
||||
|
||||
return cq;
|
||||
}
|
||||
|
||||
void cndm_destroy_cq(struct cndm_cq *cq)
|
||||
{
|
||||
cndm_close_cq(cq);
|
||||
|
||||
kfree(cq);
|
||||
}
|
||||
|
||||
int cndm_open_cq(struct cndm_cq *cq, int irqn, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct cndm_cmd_queue cmd;
|
||||
struct cndm_cmd_queue rsp;
|
||||
|
||||
if (cq->enabled || cq->buf)
|
||||
return -EINVAL;
|
||||
|
||||
cq->size = roundup_pow_of_two(size);
|
||||
cq->size_mask = cq->size - 1;
|
||||
cq->stride = 16;
|
||||
|
||||
cq->buf_size = cq->size * cq->stride;
|
||||
cq->buf = dma_alloc_coherent(cq->dev, cq->buf_size, &cq->buf_dma_addr, GFP_KERNEL);
|
||||
if (!cq->buf)
|
||||
return -ENOMEM;
|
||||
|
||||
cq->cons_ptr = 0;
|
||||
|
||||
// clear all phase tag bits
|
||||
memset(cq->buf, 0, cq->buf_size);
|
||||
|
||||
cmd.opcode = CNDM_CMD_OP_CREATE_CQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = cq->priv->ndev->dev_port;
|
||||
cmd.qn = 0;
|
||||
cmd.qn2 = irqn; // TODO
|
||||
cmd.pd = 0;
|
||||
cmd.size = ilog2(cq->size);
|
||||
cmd.dboffs = 0;
|
||||
cmd.ptr1 = cq->buf_dma_addr;
|
||||
cmd.ptr2 = 0;
|
||||
|
||||
cndm_exec_cmd(cq->cdev, &cmd, &rsp);
|
||||
|
||||
cq->cqn = rsp.qn;
|
||||
|
||||
cq->enabled = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
cndm_close_cq(cq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cndm_close_cq(struct cndm_cq *cq)
|
||||
{
|
||||
struct cndm_dev *cdev = cq->cdev;
|
||||
struct cndm_cmd_queue cmd;
|
||||
struct cndm_cmd_queue rsp;
|
||||
|
||||
cq->enabled = 0;
|
||||
|
||||
if (cq->cqn != -1) {
|
||||
cmd.opcode = CNDM_CMD_OP_DESTROY_CQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = cq->priv->ndev->dev_port;
|
||||
cmd.qn = cq->cqn;
|
||||
|
||||
cndm_exec_cmd(cdev, &cmd, &rsp);
|
||||
|
||||
cq->cqn = -1;
|
||||
}
|
||||
|
||||
if (cq->buf) {
|
||||
dma_free_coherent(cq->dev, cq->buf_size, cq->buf, cq->buf_dma_addr);
|
||||
cq->buf = NULL;
|
||||
cq->buf_dma_addr = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2025 FPGA Ninja, LLC
|
||||
Copyright (c) 2025-2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
@@ -17,14 +17,14 @@ static int cndm_open(struct net_device *ndev)
|
||||
{
|
||||
struct cndm_priv *priv = netdev_priv(ndev);
|
||||
|
||||
cndm_refill_rx_buffers(priv);
|
||||
cndm_refill_rx_buffers(priv->rxq);
|
||||
|
||||
priv->tx_queue = netdev_get_tx_queue(ndev, 0);
|
||||
priv->txq->tx_queue = netdev_get_tx_queue(ndev, 0);
|
||||
|
||||
netif_napi_add_tx(ndev, &priv->tx_napi, cndm_poll_tx_cq);
|
||||
napi_enable(&priv->tx_napi);
|
||||
netif_napi_add(ndev, &priv->rx_napi, cndm_poll_rx_cq);
|
||||
napi_enable(&priv->rx_napi);
|
||||
netif_napi_add_tx(ndev, &priv->txcq->napi, cndm_poll_tx_cq);
|
||||
napi_enable(&priv->txcq->napi);
|
||||
netif_napi_add(ndev, &priv->rxcq->napi, cndm_poll_rx_cq);
|
||||
napi_enable(&priv->rxcq->napi);
|
||||
|
||||
netif_tx_start_all_queues(ndev);
|
||||
netif_carrier_on(ndev);
|
||||
@@ -39,12 +39,19 @@ static int cndm_close(struct net_device *ndev)
|
||||
{
|
||||
struct cndm_priv *priv = netdev_priv(ndev);
|
||||
|
||||
if (!priv->port_up)
|
||||
return 0;
|
||||
|
||||
priv->port_up = 0;
|
||||
|
||||
napi_disable(&priv->tx_napi);
|
||||
netif_napi_del(&priv->tx_napi);
|
||||
napi_disable(&priv->rx_napi);
|
||||
netif_napi_del(&priv->rx_napi);
|
||||
if (priv->txcq) {
|
||||
napi_disable(&priv->txcq->napi);
|
||||
netif_napi_del(&priv->txcq->napi);
|
||||
}
|
||||
if (priv->rxcq) {
|
||||
napi_disable(&priv->rxcq->napi);
|
||||
netif_napi_del(&priv->rxcq->napi);
|
||||
}
|
||||
|
||||
netif_tx_stop_all_queues(ndev);
|
||||
netif_carrier_off(ndev);
|
||||
@@ -164,8 +171,8 @@ static int cndm_netdev_irq(struct notifier_block *nb, unsigned long action, void
|
||||
netdev_dbg(priv->ndev, "Interrupt");
|
||||
|
||||
if (priv->port_up) {
|
||||
napi_schedule_irqoff(&priv->tx_napi);
|
||||
napi_schedule_irqoff(&priv->rx_napi);
|
||||
napi_schedule_irqoff(&priv->txcq->napi);
|
||||
napi_schedule_irqoff(&priv->rxcq->napi);
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
@@ -178,9 +185,6 @@ struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port)
|
||||
struct cndm_priv *priv;
|
||||
int ret = 0;
|
||||
|
||||
struct cndm_cmd_queue cmd;
|
||||
struct cndm_cmd_queue rsp;
|
||||
|
||||
ndev = alloc_etherdev_mqs(sizeof(*priv), 1, 1);
|
||||
if (!ndev) {
|
||||
dev_err(dev, "Failed to allocate net_device");
|
||||
@@ -199,6 +203,9 @@ struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port)
|
||||
|
||||
priv->hw_addr = cdev->hw_addr;
|
||||
|
||||
priv->rxq_count = 1;
|
||||
priv->txq_count = 1;
|
||||
|
||||
netif_set_real_num_tx_queues(ndev, 1);
|
||||
netif_set_real_num_rx_queues(ndev, 1);
|
||||
|
||||
@@ -219,128 +226,54 @@ struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port)
|
||||
ndev->min_mtu = ETH_MIN_MTU;
|
||||
ndev->max_mtu = 1500;
|
||||
|
||||
priv->rxq_log_size = ilog2(256);
|
||||
priv->rxq_size = 1 << priv->rxq_log_size;
|
||||
priv->rxq_mask = priv->rxq_size-1;
|
||||
priv->rxq_prod = 0;
|
||||
priv->rxq_cons = 0;
|
||||
|
||||
priv->txq_log_size = ilog2(256);
|
||||
priv->txq_size = 1 << priv->txq_log_size;
|
||||
priv->txq_mask = priv->txq_size-1;
|
||||
priv->txq_prod = 0;
|
||||
priv->txq_cons = 0;
|
||||
|
||||
priv->rxcq_log_size = ilog2(256);
|
||||
priv->rxcq_size = 1 << priv->rxcq_log_size;
|
||||
priv->rxcq_mask = priv->rxcq_size-1;
|
||||
priv->rxcq_prod = 0;
|
||||
priv->rxcq_cons = 0;
|
||||
|
||||
priv->txcq_log_size = ilog2(256);
|
||||
priv->txcq_size = 1 << priv->txcq_log_size;
|
||||
priv->txcq_mask = priv->txcq_size-1;
|
||||
priv->txcq_prod = 0;
|
||||
priv->txcq_cons = 0;
|
||||
|
||||
// allocate DMA buffers
|
||||
priv->txq_region_len = priv->txq_size*16;
|
||||
priv->txq_region = dma_alloc_coherent(dev, priv->txq_region_len, &priv->txq_region_addr, GFP_KERNEL | __GFP_ZERO);
|
||||
if (!priv->txq_region) {
|
||||
ret = -ENOMEM;
|
||||
priv->rxcq = cndm_create_cq(priv);
|
||||
if (IS_ERR_OR_NULL(priv->rxcq)) {
|
||||
ret = PTR_ERR(priv->rxcq);
|
||||
goto fail;
|
||||
}
|
||||
ret = cndm_open_cq(priv->rxcq, 0, 256);
|
||||
if (ret) {
|
||||
cndm_destroy_cq(priv->rxcq);
|
||||
priv->rxcq = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
priv->rxq_region_len = priv->rxq_size*16;
|
||||
priv->rxq_region = dma_alloc_coherent(dev, priv->rxq_region_len, &priv->rxq_region_addr, GFP_KERNEL | __GFP_ZERO);
|
||||
if (!priv->rxq_region) {
|
||||
ret = -ENOMEM;
|
||||
priv->rxq = cndm_create_rq(priv);
|
||||
if (IS_ERR_OR_NULL(priv->rxq)) {
|
||||
ret = PTR_ERR(priv->rxq);
|
||||
goto fail;
|
||||
}
|
||||
ret = cndm_open_rq(priv->rxq, priv, priv->rxcq, 256);
|
||||
if (ret) {
|
||||
cndm_destroy_rq(priv->rxq);
|
||||
priv->rxq = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
priv->txcq_region_len = priv->txcq_size*16;
|
||||
priv->txcq_region = dma_alloc_coherent(dev, priv->txcq_region_len, &priv->txcq_region_addr, GFP_KERNEL | __GFP_ZERO);
|
||||
if (!priv->txcq_region) {
|
||||
ret = -ENOMEM;
|
||||
priv->txcq = cndm_create_cq(priv);
|
||||
if (IS_ERR_OR_NULL(priv->txcq)) {
|
||||
ret = PTR_ERR(priv->txcq);
|
||||
goto fail;
|
||||
}
|
||||
ret = cndm_open_cq(priv->txcq, 0, 256);
|
||||
if (ret) {
|
||||
cndm_destroy_cq(priv->txcq);
|
||||
priv->txcq = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
priv->rxcq_region_len = priv->rxcq_size*16;
|
||||
priv->rxcq_region = dma_alloc_coherent(dev, priv->rxcq_region_len, &priv->rxcq_region_addr, GFP_KERNEL | __GFP_ZERO);
|
||||
if (!priv->rxcq_region) {
|
||||
ret = -ENOMEM;
|
||||
priv->txq = cndm_create_sq(priv);
|
||||
if (IS_ERR_OR_NULL(priv->txq)) {
|
||||
ret = PTR_ERR(priv->txq);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// allocate info rings
|
||||
priv->tx_info = kvzalloc(sizeof(*priv->tx_info) * priv->txq_size, GFP_KERNEL);
|
||||
if (!priv->tx_info) {
|
||||
ret = -ENOMEM;
|
||||
ret = cndm_open_sq(priv->txq, priv, priv->txcq, 256);
|
||||
if (ret) {
|
||||
cndm_destroy_sq(priv->txq);
|
||||
priv->txq = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
priv->rx_info = kvzalloc(sizeof(*priv->rx_info) * priv->rxq_size, GFP_KERNEL);
|
||||
if (!priv->tx_info) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
cmd.opcode = CNDM_CMD_OP_CREATE_CQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = port;
|
||||
cmd.qn = 0;
|
||||
cmd.qn2 = 0;
|
||||
cmd.pd = 0;
|
||||
cmd.size = priv->rxcq_log_size;
|
||||
cmd.dboffs = 0;
|
||||
cmd.ptr1 = priv->rxcq_region_addr;
|
||||
cmd.ptr2 = 0;
|
||||
|
||||
cndm_exec_cmd(cdev, &cmd, &rsp);
|
||||
|
||||
cmd.opcode = CNDM_CMD_OP_CREATE_RQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = port;
|
||||
cmd.qn = 0;
|
||||
cmd.qn2 = 0;
|
||||
cmd.pd = 0;
|
||||
cmd.size = priv->rxq_log_size;
|
||||
cmd.dboffs = 0;
|
||||
cmd.ptr1 = priv->rxq_region_addr;
|
||||
cmd.ptr2 = 0;
|
||||
|
||||
cndm_exec_cmd(cdev, &cmd, &rsp);
|
||||
|
||||
priv->rxq_db_offs = rsp.dboffs;
|
||||
|
||||
cmd.opcode = CNDM_CMD_OP_CREATE_CQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = port;
|
||||
cmd.qn = 1;
|
||||
cmd.qn2 = 0;
|
||||
cmd.pd = 0;
|
||||
cmd.size = priv->txcq_log_size;
|
||||
cmd.dboffs = 0;
|
||||
cmd.ptr1 = priv->txcq_region_addr;
|
||||
cmd.ptr2 = 0;
|
||||
|
||||
cndm_exec_cmd(cdev, &cmd, &rsp);
|
||||
|
||||
cmd.opcode = CNDM_CMD_OP_CREATE_SQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = port;
|
||||
cmd.qn = 0;
|
||||
cmd.qn2 = 0;
|
||||
cmd.pd = 0;
|
||||
cmd.size = priv->txq_log_size;
|
||||
cmd.dboffs = 0;
|
||||
cmd.ptr1 = priv->txq_region_addr;
|
||||
cmd.ptr2 = 0;
|
||||
|
||||
cndm_exec_cmd(cdev, &cmd, &rsp);
|
||||
|
||||
priv->txq_db_offs = rsp.dboffs;
|
||||
|
||||
netif_carrier_off(ndev);
|
||||
|
||||
ret = register_netdev(ndev);
|
||||
@@ -370,41 +303,33 @@ fail:
|
||||
void cndm_destroy_netdev(struct net_device *ndev)
|
||||
{
|
||||
struct cndm_priv *priv = netdev_priv(ndev);
|
||||
struct cndm_dev *cdev = priv->cdev;
|
||||
struct device *dev = priv->dev;
|
||||
|
||||
struct cndm_cmd_queue cmd;
|
||||
struct cndm_cmd_queue rsp;
|
||||
if (priv->port_up)
|
||||
cndm_close(ndev);
|
||||
|
||||
cmd.opcode = CNDM_CMD_OP_DESTROY_CQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = ndev->dev_port;
|
||||
cmd.qn = 0;
|
||||
if (priv->txq) {
|
||||
cndm_close_sq(priv->txq);
|
||||
cndm_destroy_sq(priv->txq);
|
||||
priv->txq = NULL;
|
||||
}
|
||||
|
||||
cndm_exec_cmd(cdev, &cmd, &rsp);
|
||||
if (priv->txcq) {
|
||||
cndm_close_cq(priv->txcq);
|
||||
cndm_destroy_cq(priv->txcq);
|
||||
priv->txcq = NULL;
|
||||
}
|
||||
|
||||
cmd.opcode = CNDM_CMD_OP_DESTROY_RQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = ndev->dev_port;
|
||||
cmd.qn = 0;
|
||||
if (priv->rxq) {
|
||||
cndm_close_rq(priv->rxq);
|
||||
cndm_destroy_rq(priv->rxq);
|
||||
priv->rxq = NULL;
|
||||
}
|
||||
|
||||
cndm_exec_cmd(cdev, &cmd, &rsp);
|
||||
|
||||
priv->rxq_db_offs = rsp.dboffs;
|
||||
|
||||
cmd.opcode = CNDM_CMD_OP_DESTROY_CQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = ndev->dev_port;
|
||||
cmd.qn = 1;
|
||||
|
||||
cndm_exec_cmd(cdev, &cmd, &rsp);
|
||||
|
||||
cmd.opcode = CNDM_CMD_OP_DESTROY_SQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = ndev->dev_port;
|
||||
cmd.qn = 0;
|
||||
|
||||
cndm_exec_cmd(cdev, &cmd, &rsp);
|
||||
if (priv->rxcq) {
|
||||
cndm_close_cq(priv->rxcq);
|
||||
cndm_destroy_cq(priv->rxcq);
|
||||
priv->rxcq = NULL;
|
||||
}
|
||||
|
||||
if (priv->irq)
|
||||
atomic_notifier_chain_unregister(&priv->irq->nh, &priv->irq_nb);
|
||||
@@ -414,22 +339,5 @@ void cndm_destroy_netdev(struct net_device *ndev)
|
||||
if (priv->registered)
|
||||
unregister_netdev(ndev);
|
||||
|
||||
if (priv->tx_info) {
|
||||
cndm_free_tx_buf(priv);
|
||||
kvfree(priv->tx_info);
|
||||
}
|
||||
if (priv->rx_info) {
|
||||
cndm_free_rx_buf(priv);
|
||||
kvfree(priv->rx_info);
|
||||
}
|
||||
if (priv->txq_region)
|
||||
dma_free_coherent(dev, priv->txq_region_len, priv->txq_region, priv->txq_region_addr);
|
||||
if (priv->rxq_region)
|
||||
dma_free_coherent(dev, priv->rxq_region_len, priv->rxq_region, priv->rxq_region_addr);
|
||||
if (priv->txcq_region)
|
||||
dma_free_coherent(dev, priv->txcq_region_len, priv->txcq_region, priv->txcq_region_addr);
|
||||
if (priv->rxcq_region)
|
||||
dma_free_coherent(dev, priv->rxcq_region_len, priv->rxcq_region, priv->rxcq_region_addr);
|
||||
|
||||
free_netdev(ndev);
|
||||
}
|
||||
|
||||
@@ -11,22 +11,22 @@ Authors:
|
||||
#include "cndm.h"
|
||||
#include <linux/version.h>
|
||||
|
||||
ktime_t cndm_read_cpl_ts(struct cndm_priv *priv, const struct cndm_cpl *cpl)
|
||||
ktime_t cndm_read_cpl_ts(struct cndm_ring *ring, const struct cndm_cpl *cpl)
|
||||
{
|
||||
struct cndm_dev *cdev = priv->cdev;
|
||||
struct cndm_dev *cdev = ring->cdev;
|
||||
|
||||
// u64 ts_s = le16_to_cpu(cpl->ts_s);
|
||||
u64 ts_s = cpl->ts_s;
|
||||
u32 ts_ns = le32_to_cpu(cpl->ts_ns);
|
||||
|
||||
if (unlikely(!priv->ts_valid || (priv->ts_s ^ ts_s) & 0xf0)) {
|
||||
if (unlikely(!ring->ts_valid || (ring->ts_s ^ ts_s) & 0xf0)) {
|
||||
// seconds MSBs do not match, update cached timestamp
|
||||
priv->ts_s = ioread32(cdev->hw_addr + 0x0308);
|
||||
priv->ts_s |= (u64) ioread32(cdev->hw_addr + 0x030C) << 32;
|
||||
priv->ts_valid = 1;
|
||||
ring->ts_s = ioread32(cdev->hw_addr + 0x0308);
|
||||
ring->ts_s |= (u64) ioread32(cdev->hw_addr + 0x030C) << 32;
|
||||
ring->ts_valid = 1;
|
||||
}
|
||||
|
||||
ts_s |= priv->ts_s & 0xfffffffffffffff0;
|
||||
ts_s |= ring->ts_s & 0xfffffffffffffff0;
|
||||
|
||||
dev_dbg(cdev->dev, "%s: Read timestamp: %lld.%09d", __func__, ts_s, ts_ns);
|
||||
|
||||
|
||||
344
src/cndm/modules/cndm/cndm_rq.c
Normal file
344
src/cndm/modules/cndm/cndm_rq.c
Normal file
@@ -0,0 +1,344 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2025-2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#include "cndm.h"
|
||||
|
||||
struct cndm_ring *cndm_create_rq(struct cndm_priv *priv)
|
||||
{
|
||||
struct cndm_ring *rq;
|
||||
|
||||
rq = kzalloc(sizeof(*rq), GFP_KERNEL);
|
||||
if (!rq)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
rq->cdev = priv->cdev;
|
||||
rq->dev = priv->dev;
|
||||
rq->priv = priv;
|
||||
|
||||
rq->index = -1;
|
||||
rq->enabled = 0;
|
||||
|
||||
rq->prod_ptr = 0;
|
||||
rq->cons_ptr = 0;
|
||||
|
||||
rq->db_offset = 0;
|
||||
rq->db_addr = NULL;
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
void cndm_destroy_rq(struct cndm_ring *rq)
|
||||
{
|
||||
cndm_close_rq(rq);
|
||||
|
||||
kfree(rq);
|
||||
}
|
||||
|
||||
int cndm_open_rq(struct cndm_ring *rq, struct cndm_priv *priv, struct cndm_cq *cq, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct cndm_cmd_queue cmd;
|
||||
struct cndm_cmd_queue rsp;
|
||||
|
||||
if (rq->enabled || rq->buf || !priv || !cq)
|
||||
return -EINVAL;
|
||||
|
||||
rq->size = roundup_pow_of_two(size);
|
||||
rq->size_mask = rq->size - 1;
|
||||
rq->stride = 16;
|
||||
|
||||
rq->rx_info = kvzalloc(sizeof(*rq->rx_info) * rq->size, GFP_KERNEL);
|
||||
if (!rq->rx_info)
|
||||
ret = -ENOMEM;
|
||||
|
||||
rq->buf_size = rq->size * rq->stride;
|
||||
rq->buf = dma_alloc_coherent(rq->dev, rq->buf_size, &rq->buf_dma_addr, GFP_KERNEL);
|
||||
if (!rq->buf) {
|
||||
return -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rq->priv = priv;
|
||||
rq->cq = cq;
|
||||
cq->src_ring = rq;
|
||||
// cq->handler = cndm_rx_irq;
|
||||
|
||||
rq->prod_ptr = 0;
|
||||
rq->cons_ptr = 0;
|
||||
|
||||
cmd.opcode = CNDM_CMD_OP_CREATE_RQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = rq->priv->ndev->dev_port;
|
||||
cmd.qn = 0;
|
||||
cmd.qn2 = cq->cqn;
|
||||
cmd.pd = 0;
|
||||
cmd.size = ilog2(rq->size);
|
||||
cmd.dboffs = 0;
|
||||
cmd.ptr1 = rq->buf_dma_addr;
|
||||
cmd.ptr2 = 0;
|
||||
|
||||
cndm_exec_cmd(rq->cdev, &cmd, &rsp);
|
||||
|
||||
rq->index = rsp.qn;
|
||||
rq->db_offset = rsp.dboffs;
|
||||
rq->db_addr = priv->cdev->hw_addr + rsp.dboffs;
|
||||
|
||||
rq->enabled = 1;
|
||||
|
||||
ret = cndm_refill_rx_buffers(rq);
|
||||
if (ret) {
|
||||
netdev_err(priv->ndev, "failed to allocate RX buffer for RX queue index %d (of %u total) entry index %u (of %u total)",
|
||||
rq->index, priv->rxq_count, rq->prod_ptr, rq->size);
|
||||
if (ret == -ENOMEM)
|
||||
netdev_err(priv->ndev, "machine might not have enough DMA-capable RAM; try to decrease number of RX channels (currently %u) and/or RX ring parameters (entries; currently %u)",
|
||||
priv->rxq_count, rq->size);
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
cndm_close_rq(rq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cndm_close_rq(struct cndm_ring *rq)
|
||||
{
|
||||
struct cndm_dev *cdev = rq->cdev;
|
||||
struct cndm_cmd_queue cmd;
|
||||
struct cndm_cmd_queue rsp;
|
||||
|
||||
rq->enabled = 0;
|
||||
|
||||
if (rq->cq) {
|
||||
rq->cq->src_ring = NULL;
|
||||
rq->cq->handler = NULL;
|
||||
}
|
||||
|
||||
rq->cq = NULL;
|
||||
|
||||
if (rq->index != -1) {
|
||||
cmd.opcode = CNDM_CMD_OP_DESTROY_RQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = rq->priv->ndev->dev_port;
|
||||
cmd.qn = rq->index;
|
||||
|
||||
cndm_exec_cmd(cdev, &cmd, &rsp);
|
||||
|
||||
rq->index = -1;
|
||||
}
|
||||
|
||||
if (rq->buf) {
|
||||
cndm_free_rx_buf(rq);
|
||||
|
||||
dma_free_coherent(rq->dev, rq->buf_size, rq->buf, rq->buf_dma_addr);
|
||||
rq->buf = NULL;
|
||||
rq->buf_dma_addr = 0;
|
||||
}
|
||||
|
||||
if (rq->rx_info) {
|
||||
kvfree(rq->rx_info);
|
||||
rq->rx_info = NULL;
|
||||
}
|
||||
|
||||
rq->priv = NULL;
|
||||
}
|
||||
|
||||
static void cndm_free_rx_desc(struct cndm_ring *rq, int index)
|
||||
{
|
||||
struct cndm_priv *priv = rq->priv;
|
||||
struct device *dev = priv->dev;
|
||||
struct cndm_rx_info *rx_info = &rq->rx_info[index];
|
||||
|
||||
netdev_dbg(priv->ndev, "Free RX desc index %d", index);
|
||||
|
||||
if (!rx_info->page)
|
||||
return;
|
||||
|
||||
dma_unmap_page(dev, rx_info->dma_addr, rx_info->len, DMA_FROM_DEVICE);
|
||||
rx_info->dma_addr = 0;
|
||||
__free_pages(rx_info->page, 0);
|
||||
rx_info->page = NULL;
|
||||
}
|
||||
|
||||
int cndm_free_rx_buf(struct cndm_ring *rq)
|
||||
{
|
||||
u32 index;
|
||||
int cnt = 0;
|
||||
|
||||
while (rq->prod_ptr != rq->cons_ptr) {
|
||||
index = rq->cons_ptr & rq->size_mask;
|
||||
cndm_free_rx_desc(rq, index);
|
||||
rq->cons_ptr++;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int cndm_prepare_rx_desc(struct cndm_ring *rq, int index)
|
||||
{
|
||||
struct cndm_priv *priv = rq->priv;
|
||||
struct device *dev = rq->dev;
|
||||
struct cndm_rx_info *rx_info = &rq->rx_info[index];
|
||||
struct cndm_desc *rx_desc = (struct cndm_desc *)(rq->buf + index*16);
|
||||
struct page *page;
|
||||
u32 len = PAGE_SIZE;
|
||||
dma_addr_t dma_addr;
|
||||
|
||||
netdev_dbg(priv->ndev, "Prepare RX desc index %d", index);
|
||||
|
||||
page = dev_alloc_pages(0);
|
||||
if (unlikely(!page)) {
|
||||
netdev_err(priv->ndev, "Failed to allocate page");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dma_addr = dma_map_page(dev, page, 0, len, DMA_FROM_DEVICE);
|
||||
|
||||
if (unlikely(dma_mapping_error(dev, dma_addr))) {
|
||||
netdev_err(priv->ndev, "Mapping failed");
|
||||
__free_pages(page, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rx_desc->len = cpu_to_le32(len);
|
||||
rx_desc->addr = cpu_to_le64(dma_addr);
|
||||
|
||||
rx_info->page = page;
|
||||
rx_info->len = len;
|
||||
rx_info->dma_addr = dma_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cndm_refill_rx_buffers(struct cndm_ring *rq)
|
||||
{
|
||||
u32 missing = 128 - (rq->prod_ptr - rq->cons_ptr); // TODO
|
||||
int ret = 0;
|
||||
|
||||
if (missing < 8)
|
||||
return 0;
|
||||
|
||||
for (; missing-- > 0;) {
|
||||
ret = cndm_prepare_rx_desc(rq, rq->prod_ptr & rq->size_mask);
|
||||
if (ret)
|
||||
break;
|
||||
rq->prod_ptr++;
|
||||
}
|
||||
|
||||
dma_wmb();
|
||||
iowrite32(rq->prod_ptr & 0xffff, rq->db_addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cndm_process_rx_cq(struct cndm_cq *cq, int napi_budget)
|
||||
{
|
||||
struct cndm_priv *priv = cq->priv;
|
||||
struct cndm_ring *rq = cq->src_ring;
|
||||
struct cndm_cpl *cpl;
|
||||
struct cndm_rx_info *rx_info;
|
||||
struct sk_buff *skb;
|
||||
struct page *page;
|
||||
int done = 0;
|
||||
u32 len;
|
||||
|
||||
u32 cq_cons_ptr;
|
||||
u32 cq_index;
|
||||
u32 cons_ptr;
|
||||
u32 index;
|
||||
|
||||
cq_cons_ptr = cq->cons_ptr;
|
||||
cons_ptr = rq->cons_ptr;
|
||||
|
||||
while (done < napi_budget) {
|
||||
cq_index = cq_cons_ptr & cq->size_mask;
|
||||
cpl = (struct cndm_cpl *)(cq->buf + cq_index * 16);
|
||||
|
||||
if (!!(cpl->phase & 0x80) == !!(cq_cons_ptr & cq->size))
|
||||
break;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
index = cons_ptr & rq->size_mask;
|
||||
|
||||
rx_info = &rq->rx_info[index];
|
||||
page = rx_info->page;
|
||||
len = min_t(u32, le16_to_cpu(cpl->len), rx_info->len);
|
||||
|
||||
netdev_dbg(priv->ndev, "Process RX cpl index %d", index);
|
||||
|
||||
if (!page) {
|
||||
netdev_err(priv->ndev, "Null page at index %d", index);
|
||||
break;
|
||||
}
|
||||
|
||||
dma_unmap_page(priv->dev, rx_info->dma_addr, rx_info->len, DMA_FROM_DEVICE);
|
||||
rx_info->dma_addr = 0;
|
||||
rx_info->page = NULL;
|
||||
|
||||
if (len < ETH_HLEN) {
|
||||
netdev_warn(priv->ndev, "Dropping short frame (len %d)", len);
|
||||
__free_pages(page, 0);
|
||||
goto rx_drop;
|
||||
}
|
||||
|
||||
skb = napi_get_frags(&cq->napi);
|
||||
if (!skb) {
|
||||
netdev_err(priv->ndev, "Failed to allocate skb %d", index);
|
||||
__free_pages(page, 0);
|
||||
goto rx_drop;
|
||||
}
|
||||
|
||||
// RX hardware timestamp
|
||||
skb_hwtstamps(skb)->hwtstamp = cndm_read_cpl_ts(rq, cpl);
|
||||
|
||||
__skb_fill_page_desc(skb, 0, page, 0, len);
|
||||
|
||||
skb_shinfo(skb)->nr_frags = 1;
|
||||
skb->len = len;
|
||||
skb->data_len = len;
|
||||
skb->truesize = rx_info->len;
|
||||
|
||||
napi_gro_frags(&cq->napi);
|
||||
|
||||
rx_drop:
|
||||
done++;
|
||||
cq_cons_ptr++;
|
||||
cons_ptr++;
|
||||
}
|
||||
|
||||
cq->cons_ptr = cq_cons_ptr;
|
||||
rq->cons_ptr = cons_ptr;
|
||||
|
||||
cndm_refill_rx_buffers(rq);
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
int cndm_poll_rx_cq(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct cndm_cq *cq = container_of(napi, struct cndm_cq, napi);
|
||||
int done;
|
||||
|
||||
done = cndm_process_rx_cq(cq, budget);
|
||||
|
||||
if (done == budget)
|
||||
return done;
|
||||
|
||||
napi_complete(napi);
|
||||
|
||||
// TODO re-enable interrupts
|
||||
|
||||
return done;
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2025 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#include "cndm.h"
|
||||
|
||||
static void cndm_free_rx_desc(struct cndm_priv *priv, int index)
|
||||
{
|
||||
struct device *dev = priv->dev;
|
||||
struct cndm_rx_info *rx_info = &priv->rx_info[index];
|
||||
|
||||
netdev_dbg(priv->ndev, "Free RX desc index %d", index);
|
||||
|
||||
if (!rx_info->page)
|
||||
return;
|
||||
|
||||
dma_unmap_page(dev, rx_info->dma_addr, rx_info->len, DMA_FROM_DEVICE);
|
||||
rx_info->dma_addr = 0;
|
||||
__free_pages(rx_info->page, 0);
|
||||
rx_info->page = NULL;
|
||||
}
|
||||
|
||||
int cndm_free_rx_buf(struct cndm_priv *priv)
|
||||
{
|
||||
u32 index;
|
||||
int cnt = 0;
|
||||
|
||||
while (priv->rxq_prod != priv->rxq_cons) {
|
||||
index = priv->rxq_cons & priv->rxq_mask;
|
||||
cndm_free_rx_desc(priv, index);
|
||||
priv->rxq_cons++;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int cndm_prepare_rx_desc(struct cndm_priv *priv, int index)
|
||||
{
|
||||
struct device *dev = priv->dev;
|
||||
struct cndm_rx_info *rx_info = &priv->rx_info[index];
|
||||
struct cndm_desc *rx_desc = (struct cndm_desc *)(priv->rxq_region + index*16);
|
||||
struct page *page;
|
||||
u32 len = PAGE_SIZE;
|
||||
dma_addr_t dma_addr;
|
||||
|
||||
netdev_dbg(priv->ndev, "Prepare RX desc index %d", index);
|
||||
|
||||
page = dev_alloc_pages(0);
|
||||
if (unlikely(!page)) {
|
||||
netdev_err(priv->ndev, "Failed to allocate page");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dma_addr = dma_map_page(dev, page, 0, len, DMA_FROM_DEVICE);
|
||||
|
||||
if (unlikely(dma_mapping_error(dev, dma_addr))) {
|
||||
netdev_err(priv->ndev, "Mapping failed");
|
||||
__free_pages(page, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rx_desc->len = cpu_to_le32(len);
|
||||
rx_desc->addr = cpu_to_le64(dma_addr);
|
||||
|
||||
rx_info->page = page;
|
||||
rx_info->len = len;
|
||||
rx_info->dma_addr = dma_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cndm_refill_rx_buffers(struct cndm_priv *priv)
|
||||
{
|
||||
u32 missing = 128 - (priv->rxq_prod - priv->rxq_cons); // TODO
|
||||
int ret = 0;
|
||||
|
||||
if (missing < 8)
|
||||
return 0;
|
||||
|
||||
for (; missing-- > 0;) {
|
||||
ret = cndm_prepare_rx_desc(priv, priv->rxq_prod & priv->rxq_mask);
|
||||
if (ret)
|
||||
break;
|
||||
priv->rxq_prod++;
|
||||
}
|
||||
|
||||
dma_wmb();
|
||||
iowrite32(priv->rxq_prod & 0xffff, priv->hw_addr + priv->rxq_db_offs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cndm_process_rx_cq(struct net_device *ndev, int napi_budget)
|
||||
{
|
||||
struct cndm_priv *priv = netdev_priv(ndev);
|
||||
struct cndm_cpl *cpl;
|
||||
struct cndm_rx_info *rx_info;
|
||||
struct sk_buff *skb;
|
||||
struct page *page;
|
||||
int done = 0;
|
||||
u32 len;
|
||||
|
||||
u32 cq_cons_ptr;
|
||||
u32 cq_index;
|
||||
u32 cons_ptr;
|
||||
u32 index;
|
||||
|
||||
cq_cons_ptr = priv->rxcq_cons;
|
||||
cons_ptr = priv->rxq_cons;
|
||||
|
||||
while (done < napi_budget) {
|
||||
cq_index = cq_cons_ptr & priv->rxcq_mask;
|
||||
cpl = (struct cndm_cpl *)(priv->rxcq_region + cq_index * 16);
|
||||
|
||||
if (!!(cpl->phase & 0x80) == !!(cq_cons_ptr & priv->rxcq_size))
|
||||
break;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
index = cons_ptr & priv->rxq_mask;
|
||||
|
||||
rx_info = &priv->rx_info[index];
|
||||
page = rx_info->page;
|
||||
len = min_t(u32, le16_to_cpu(cpl->len), rx_info->len);
|
||||
|
||||
netdev_dbg(priv->ndev, "Process RX cpl index %d", index);
|
||||
|
||||
if (!page) {
|
||||
netdev_err(priv->ndev, "Null page at index %d", index);
|
||||
break;
|
||||
}
|
||||
|
||||
dma_unmap_page(priv->dev, rx_info->dma_addr, rx_info->len, DMA_FROM_DEVICE);
|
||||
rx_info->dma_addr = 0;
|
||||
rx_info->page = NULL;
|
||||
|
||||
if (len < ETH_HLEN) {
|
||||
netdev_warn(priv->ndev, "Dropping short frame (len %d)", len);
|
||||
__free_pages(page, 0);
|
||||
goto rx_drop;
|
||||
}
|
||||
|
||||
skb = napi_get_frags(&priv->rx_napi);
|
||||
if (!skb) {
|
||||
netdev_err(priv->ndev, "Failed to allocate skb %d", index);
|
||||
__free_pages(page, 0);
|
||||
goto rx_drop;
|
||||
}
|
||||
|
||||
// RX hardware timestamp
|
||||
skb_hwtstamps(skb)->hwtstamp = cndm_read_cpl_ts(priv, cpl);
|
||||
|
||||
__skb_fill_page_desc(skb, 0, page, 0, len);
|
||||
|
||||
skb_shinfo(skb)->nr_frags = 1;
|
||||
skb->len = len;
|
||||
skb->data_len = len;
|
||||
skb->truesize = rx_info->len;
|
||||
|
||||
napi_gro_frags(&priv->rx_napi);
|
||||
|
||||
rx_drop:
|
||||
done++;
|
||||
cq_cons_ptr++;
|
||||
cons_ptr++;
|
||||
}
|
||||
|
||||
priv->rxcq_cons = cq_cons_ptr;
|
||||
priv->rxq_cons = cons_ptr;
|
||||
|
||||
cndm_refill_rx_buffers(priv);
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
int cndm_poll_rx_cq(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct cndm_priv *priv = container_of(napi, struct cndm_priv, rx_napi);
|
||||
int done;
|
||||
|
||||
done = cndm_process_rx_cq(priv->ndev, budget);
|
||||
|
||||
if (done == budget)
|
||||
return done;
|
||||
|
||||
napi_complete(napi);
|
||||
|
||||
// TODO re-enable interrupts
|
||||
|
||||
return done;
|
||||
}
|
||||
315
src/cndm/modules/cndm/cndm_sq.c
Normal file
315
src/cndm/modules/cndm/cndm_sq.c
Normal file
@@ -0,0 +1,315 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2025-2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#include "cndm.h"
|
||||
|
||||
struct cndm_ring *cndm_create_sq(struct cndm_priv *priv)
|
||||
{
|
||||
struct cndm_ring *sq;
|
||||
|
||||
sq = kzalloc(sizeof(*sq), GFP_KERNEL);
|
||||
if (!sq)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
sq->cdev = priv->cdev;
|
||||
sq->dev = priv->dev;
|
||||
sq->priv = priv;
|
||||
|
||||
sq->index = -1;
|
||||
sq->enabled = 0;
|
||||
|
||||
sq->prod_ptr = 0;
|
||||
sq->cons_ptr = 0;
|
||||
|
||||
sq->db_offset = 0;
|
||||
sq->db_addr = NULL;
|
||||
|
||||
return sq;
|
||||
}
|
||||
|
||||
void cndm_destroy_sq(struct cndm_ring *sq)
|
||||
{
|
||||
cndm_close_sq(sq);
|
||||
|
||||
kfree(sq);
|
||||
}
|
||||
|
||||
int cndm_open_sq(struct cndm_ring *sq, struct cndm_priv *priv, struct cndm_cq *cq, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct cndm_cmd_queue cmd;
|
||||
struct cndm_cmd_queue rsp;
|
||||
|
||||
if (sq->enabled || sq->buf || !priv || !cq)
|
||||
return -EINVAL;
|
||||
|
||||
sq->size = roundup_pow_of_two(size);
|
||||
sq->size_mask = sq->size - 1;
|
||||
sq->stride = 16;
|
||||
|
||||
sq->tx_info = kvzalloc(sizeof(*sq->tx_info) * sq->size, GFP_KERNEL);
|
||||
if (!sq->tx_info)
|
||||
ret = -ENOMEM;
|
||||
|
||||
sq->buf_size = sq->size * sq->stride;
|
||||
sq->buf = dma_alloc_coherent(sq->dev, sq->buf_size, &sq->buf_dma_addr, GFP_KERNEL);
|
||||
if (!sq->buf) {
|
||||
return -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sq->priv = priv;
|
||||
sq->cq = cq;
|
||||
cq->src_ring = sq;
|
||||
// cq->handler = cndm_tx_irq;
|
||||
|
||||
sq->prod_ptr = 0;
|
||||
sq->cons_ptr = 0;
|
||||
|
||||
cmd.opcode = CNDM_CMD_OP_CREATE_SQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = sq->priv->ndev->dev_port;
|
||||
cmd.qn = 0;
|
||||
cmd.qn2 = cq->cqn;
|
||||
cmd.pd = 0;
|
||||
cmd.size = ilog2(sq->size);
|
||||
cmd.dboffs = 0;
|
||||
cmd.ptr1 = sq->buf_dma_addr;
|
||||
cmd.ptr2 = 0;
|
||||
|
||||
cndm_exec_cmd(sq->cdev, &cmd, &rsp);
|
||||
|
||||
sq->index = rsp.qn;
|
||||
sq->db_offset = rsp.dboffs;
|
||||
sq->db_addr = priv->cdev->hw_addr + rsp.dboffs;
|
||||
|
||||
sq->enabled = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
cndm_close_sq(sq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cndm_close_sq(struct cndm_ring *sq)
|
||||
{
|
||||
struct cndm_dev *cdev = sq->cdev;
|
||||
struct cndm_cmd_queue cmd;
|
||||
struct cndm_cmd_queue rsp;
|
||||
|
||||
sq->enabled = 0;
|
||||
|
||||
if (sq->cq) {
|
||||
sq->cq->src_ring = NULL;
|
||||
sq->cq->handler = NULL;
|
||||
}
|
||||
|
||||
sq->cq = NULL;
|
||||
|
||||
if (sq->index != -1) {
|
||||
cmd.opcode = CNDM_CMD_OP_DESTROY_SQ;
|
||||
cmd.flags = 0x00000000;
|
||||
cmd.port = sq->priv->ndev->dev_port;
|
||||
cmd.qn = sq->index;
|
||||
|
||||
cndm_exec_cmd(cdev, &cmd, &rsp);
|
||||
|
||||
sq->index = -1;
|
||||
}
|
||||
|
||||
if (sq->buf) {
|
||||
cndm_free_tx_buf(sq);
|
||||
|
||||
dma_free_coherent(sq->dev, sq->buf_size, sq->buf, sq->buf_dma_addr);
|
||||
sq->buf = NULL;
|
||||
sq->buf_dma_addr = 0;
|
||||
}
|
||||
|
||||
if (sq->tx_info) {
|
||||
kvfree(sq->tx_info);
|
||||
sq->tx_info = NULL;
|
||||
}
|
||||
|
||||
sq->priv = NULL;
|
||||
}
|
||||
|
||||
static void cndm_free_tx_desc(struct cndm_ring *sq, int index, int napi_budget)
|
||||
{
|
||||
struct cndm_priv *priv = sq->priv;
|
||||
struct device *dev = priv->dev;
|
||||
struct cndm_tx_info *tx_info = &sq->tx_info[index];
|
||||
struct sk_buff *skb = tx_info->skb;
|
||||
|
||||
netdev_dbg(priv->ndev, "Free TX desc index %d", index);
|
||||
|
||||
dma_unmap_single(dev, tx_info->dma_addr, tx_info->len, DMA_TO_DEVICE);
|
||||
tx_info->dma_addr = 0;
|
||||
|
||||
napi_consume_skb(skb, napi_budget);
|
||||
tx_info->skb = NULL;
|
||||
}
|
||||
|
||||
int cndm_free_tx_buf(struct cndm_ring *sq)
|
||||
{
|
||||
u32 index;
|
||||
int cnt = 0;
|
||||
|
||||
while (sq->prod_ptr != sq->cons_ptr) {
|
||||
index = sq->cons_ptr & sq->size_mask;
|
||||
cndm_free_tx_desc(sq, index, 0);
|
||||
sq->cons_ptr++;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int cndm_process_tx_cq(struct cndm_cq *cq, int napi_budget)
|
||||
{
|
||||
struct cndm_priv *priv = cq->priv;
|
||||
struct cndm_ring *sq = cq->src_ring;
|
||||
struct cndm_tx_info *tx_info;
|
||||
struct cndm_cpl *cpl;
|
||||
struct skb_shared_hwtstamps hwts;
|
||||
int done = 0;
|
||||
|
||||
u32 cq_cons_ptr;
|
||||
u32 cq_index;
|
||||
u32 cons_ptr;
|
||||
u32 index;
|
||||
|
||||
cq_cons_ptr = cq->cons_ptr;
|
||||
cons_ptr = sq->cons_ptr;
|
||||
|
||||
while (done < napi_budget) {
|
||||
cq_index = cq_cons_ptr & cq->size_mask;
|
||||
cpl = (struct cndm_cpl *)(cq->buf + cq_index * 16);
|
||||
|
||||
if (!!(cpl->phase & 0x80) == !!(cq_cons_ptr & cq->size))
|
||||
break;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
index = cons_ptr & sq->size_mask;
|
||||
tx_info = &sq->tx_info[index];
|
||||
|
||||
// TX hardware timestamp
|
||||
if (unlikely(tx_info->ts_requested)) {
|
||||
netdev_dbg(priv->ndev, "%s: TX TS requested", __func__);
|
||||
hwts.hwtstamp = cndm_read_cpl_ts(sq, cpl);
|
||||
skb_tstamp_tx(tx_info->skb, &hwts);
|
||||
}
|
||||
|
||||
cndm_free_tx_desc(sq, index, napi_budget);
|
||||
|
||||
done++;
|
||||
cq_cons_ptr++;
|
||||
cons_ptr++;
|
||||
}
|
||||
|
||||
cq->cons_ptr = cq_cons_ptr;
|
||||
sq->cons_ptr = cons_ptr;
|
||||
|
||||
if (netif_tx_queue_stopped(sq->tx_queue) && (done != 0 || sq->prod_ptr == sq->cons_ptr))
|
||||
netif_tx_wake_queue(sq->tx_queue);
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
int cndm_poll_tx_cq(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct cndm_cq *cq = container_of(napi, struct cndm_cq, napi);
|
||||
int done;
|
||||
|
||||
done = cndm_process_tx_cq(cq, budget);
|
||||
|
||||
if (done == budget)
|
||||
return done;
|
||||
|
||||
napi_complete(napi);
|
||||
|
||||
// TODO re-enable interrupts
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
int cndm_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
struct skb_shared_info *shinfo = skb_shinfo(skb);
|
||||
struct cndm_priv *priv = netdev_priv(ndev);
|
||||
struct cndm_ring *sq = priv->txq;
|
||||
struct device *dev = priv->dev;
|
||||
u32 index;
|
||||
u32 cons_ptr;
|
||||
u32 len;
|
||||
dma_addr_t dma_addr;
|
||||
struct cndm_desc *tx_desc;
|
||||
struct cndm_tx_info *tx_info;
|
||||
|
||||
netdev_dbg(ndev, "Got packet for TX");
|
||||
|
||||
if (skb->len < ETH_HLEN) {
|
||||
netdev_warn(ndev, "Dropping short frame");
|
||||
goto tx_drop;
|
||||
}
|
||||
|
||||
cons_ptr = READ_ONCE(sq->cons_ptr);
|
||||
|
||||
index = sq->prod_ptr & sq->size_mask;
|
||||
|
||||
tx_desc = (struct cndm_desc *)(sq->buf + index*16);
|
||||
tx_info = &sq->tx_info[index];
|
||||
|
||||
// TX hardware timestamp
|
||||
tx_info->ts_requested = 0;
|
||||
if (unlikely(shinfo->tx_flags & SKBTX_HW_TSTAMP)) {
|
||||
netdev_dbg(ndev, "%s: TX TS requested", __func__);
|
||||
shinfo->tx_flags |= SKBTX_IN_PROGRESS;
|
||||
tx_info->ts_requested = 1;
|
||||
}
|
||||
|
||||
len = skb_headlen(skb);
|
||||
|
||||
dma_addr = dma_map_single(dev, skb->data, len, DMA_TO_DEVICE);
|
||||
|
||||
if (unlikely(dma_mapping_error(dev, dma_addr))) {
|
||||
netdev_err(ndev, "Mapping failed");
|
||||
goto tx_drop;
|
||||
}
|
||||
|
||||
tx_desc->len = cpu_to_le32(len);
|
||||
tx_desc->addr = cpu_to_le64(dma_addr);
|
||||
|
||||
tx_info->skb = skb;
|
||||
tx_info->len = len;
|
||||
tx_info->dma_addr = dma_addr;
|
||||
|
||||
netdev_dbg(ndev, "Write desc index %d len %d", index, len);
|
||||
|
||||
sq->prod_ptr++;
|
||||
|
||||
skb_tx_timestamp(skb);
|
||||
|
||||
if (sq->prod_ptr - sq->cons_ptr >= 128) {
|
||||
netdev_dbg(ndev, "TX ring full");
|
||||
netif_tx_stop_queue(sq->tx_queue);
|
||||
}
|
||||
|
||||
dma_wmb();
|
||||
iowrite32(sq->prod_ptr & 0xffff, sq->db_addr);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
tx_drop:
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL
|
||||
/*
|
||||
|
||||
Copyright (c) 2025 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#include "cndm.h"
|
||||
|
||||
static void cndm_free_tx_desc(struct cndm_priv *priv, int index, int napi_budget)
|
||||
{
|
||||
struct device *dev = priv->dev;
|
||||
struct cndm_tx_info *tx_info = &priv->tx_info[index];
|
||||
struct sk_buff *skb = tx_info->skb;
|
||||
|
||||
netdev_dbg(priv->ndev, "Free TX desc index %d", index);
|
||||
|
||||
dma_unmap_single(dev, tx_info->dma_addr, tx_info->len, DMA_TO_DEVICE);
|
||||
tx_info->dma_addr = 0;
|
||||
|
||||
napi_consume_skb(skb, napi_budget);
|
||||
tx_info->skb = NULL;
|
||||
}
|
||||
|
||||
int cndm_free_tx_buf(struct cndm_priv *priv)
|
||||
{
|
||||
u32 index;
|
||||
int cnt = 0;
|
||||
|
||||
while (priv->txq_prod != priv->txq_cons) {
|
||||
index = priv->txq_cons & priv->txq_mask;
|
||||
cndm_free_tx_desc(priv, index, 0);
|
||||
priv->txq_cons++;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int cndm_process_tx_cq(struct net_device *ndev, int napi_budget)
|
||||
{
|
||||
struct cndm_priv *priv = netdev_priv(ndev);
|
||||
struct cndm_tx_info *tx_info;
|
||||
struct cndm_cpl *cpl;
|
||||
struct skb_shared_hwtstamps hwts;
|
||||
int done = 0;
|
||||
|
||||
u32 cq_cons_ptr;
|
||||
u32 cq_index;
|
||||
u32 cons_ptr;
|
||||
u32 index;
|
||||
|
||||
cq_cons_ptr = priv->txcq_cons;
|
||||
cons_ptr = priv->txq_cons;
|
||||
|
||||
while (done < napi_budget) {
|
||||
cq_index = cq_cons_ptr & priv->txcq_mask;
|
||||
cpl = (struct cndm_cpl *)(priv->txcq_region + cq_index * 16);
|
||||
|
||||
if (!!(cpl->phase & 0x80) == !!(cq_cons_ptr & priv->txcq_size))
|
||||
break;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
index = cons_ptr & priv->txq_mask;
|
||||
tx_info = &priv->tx_info[index];
|
||||
|
||||
// TX hardware timestamp
|
||||
if (unlikely(tx_info->ts_requested)) {
|
||||
netdev_dbg(priv->ndev, "%s: TX TS requested", __func__);
|
||||
hwts.hwtstamp = cndm_read_cpl_ts(priv, cpl);
|
||||
skb_tstamp_tx(tx_info->skb, &hwts);
|
||||
}
|
||||
|
||||
cndm_free_tx_desc(priv, index, napi_budget);
|
||||
|
||||
done++;
|
||||
cq_cons_ptr++;
|
||||
cons_ptr++;
|
||||
}
|
||||
|
||||
priv->txcq_cons = cq_cons_ptr;
|
||||
priv->txq_cons = cons_ptr;
|
||||
|
||||
if (netif_tx_queue_stopped(priv->tx_queue) && (done != 0 || priv->txq_prod == priv->txq_cons))
|
||||
netif_tx_wake_queue(priv->tx_queue);
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
int cndm_poll_tx_cq(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct cndm_priv *priv = container_of(napi, struct cndm_priv, tx_napi);
|
||||
int done;
|
||||
|
||||
done = cndm_process_tx_cq(priv->ndev, budget);
|
||||
|
||||
if (done == budget)
|
||||
return done;
|
||||
|
||||
napi_complete(napi);
|
||||
|
||||
// TODO re-enable interrupts
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
int cndm_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
struct skb_shared_info *shinfo = skb_shinfo(skb);
|
||||
struct cndm_priv *priv = netdev_priv(ndev);
|
||||
struct device *dev = priv->dev;
|
||||
u32 index;
|
||||
u32 cons_ptr;
|
||||
u32 len;
|
||||
dma_addr_t dma_addr;
|
||||
struct cndm_desc *tx_desc;
|
||||
struct cndm_tx_info *tx_info;
|
||||
|
||||
netdev_dbg(ndev, "Got packet for TX");
|
||||
|
||||
if (skb->len < ETH_HLEN) {
|
||||
netdev_warn(ndev, "Dropping short frame");
|
||||
goto tx_drop;
|
||||
}
|
||||
|
||||
cons_ptr = READ_ONCE(priv->txq_cons);
|
||||
|
||||
index = priv->txq_prod & priv->txq_mask;
|
||||
|
||||
tx_desc = (struct cndm_desc *)(priv->txq_region + index*16);
|
||||
tx_info = &priv->tx_info[index];
|
||||
|
||||
// TX hardware timestamp
|
||||
tx_info->ts_requested = 0;
|
||||
if (unlikely(shinfo->tx_flags & SKBTX_HW_TSTAMP)) {
|
||||
netdev_dbg(ndev, "%s: TX TS requested", __func__);
|
||||
shinfo->tx_flags |= SKBTX_IN_PROGRESS;
|
||||
tx_info->ts_requested = 1;
|
||||
}
|
||||
|
||||
len = skb_headlen(skb);
|
||||
|
||||
dma_addr = dma_map_single(dev, skb->data, len, DMA_TO_DEVICE);
|
||||
|
||||
if (unlikely(dma_mapping_error(dev, dma_addr))) {
|
||||
netdev_err(ndev, "Mapping failed");
|
||||
goto tx_drop;
|
||||
}
|
||||
|
||||
tx_desc->len = cpu_to_le32(len);
|
||||
tx_desc->addr = cpu_to_le64(dma_addr);
|
||||
|
||||
tx_info->skb = skb;
|
||||
tx_info->len = len;
|
||||
tx_info->dma_addr = dma_addr;
|
||||
|
||||
netdev_dbg(ndev, "Write desc index %d len %d", index, len);
|
||||
|
||||
priv->txq_prod++;
|
||||
|
||||
skb_tx_timestamp(skb);
|
||||
|
||||
if (priv->txq_prod - priv->txq_cons >= 128) {
|
||||
netdev_dbg(ndev, "TX ring full");
|
||||
netif_tx_stop_queue(priv->tx_queue);
|
||||
}
|
||||
|
||||
dma_wmb();
|
||||
iowrite32(priv->txq_prod & 0xffff, priv->hw_addr + priv->txq_db_offs);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
tx_drop:
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
@@ -20,6 +20,17 @@ module cndm_micro_cpl_wr
|
||||
input wire logic clk,
|
||||
input wire logic rst,
|
||||
|
||||
/*
|
||||
* Control register interface
|
||||
*/
|
||||
taxi_axil_if.wr_slv s_axil_ctrl_wr,
|
||||
taxi_axil_if.rd_slv s_axil_ctrl_rd,
|
||||
|
||||
/*
|
||||
* Datapath control register interface
|
||||
*/
|
||||
taxi_apb_if.slv s_apb_dp_ctrl,
|
||||
|
||||
/*
|
||||
* DMA
|
||||
*/
|
||||
@@ -27,54 +38,185 @@ module cndm_micro_cpl_wr
|
||||
taxi_dma_desc_if.sts_snk dma_wr_desc_sts,
|
||||
taxi_dma_ram_if.rd_slv dma_ram_rd,
|
||||
|
||||
input wire logic txcq_en,
|
||||
input wire logic [3:0] txcq_size,
|
||||
input wire logic [63:0] txcq_base_addr,
|
||||
output wire logic [15:0] txcq_prod,
|
||||
input wire logic rxcq_en,
|
||||
input wire logic [3:0] rxcq_size,
|
||||
input wire logic [63:0] rxcq_base_addr,
|
||||
output wire logic [15:0] rxcq_prod,
|
||||
|
||||
taxi_axis_if.snk axis_cpl[2],
|
||||
taxi_axis_if.snk s_axis_cpl,
|
||||
output wire logic irq
|
||||
);
|
||||
|
||||
taxi_axis_if #(
|
||||
.DATA_W(axis_cpl[0].DATA_W),
|
||||
.KEEP_EN(axis_cpl[0].KEEP_EN),
|
||||
.KEEP_W(axis_cpl[0].KEEP_W),
|
||||
.STRB_EN(axis_cpl[0].STRB_EN),
|
||||
.LAST_EN(axis_cpl[0].LAST_EN),
|
||||
.ID_EN(1),
|
||||
.ID_W(1),
|
||||
.DEST_EN(axis_cpl[0].DEST_EN),
|
||||
.DEST_W(axis_cpl[0].DEST_W),
|
||||
.USER_EN(axis_cpl[0].USER_EN),
|
||||
.USER_W(axis_cpl[0].USER_W)
|
||||
) cpl_comb();
|
||||
localparam AXIL_ADDR_W = s_axil_ctrl_wr.ADDR_W;
|
||||
localparam AXIL_DATA_W = s_axil_ctrl_wr.DATA_W;
|
||||
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 0,
|
||||
STATE_RX_CPL = 1,
|
||||
STATE_WRITE_DATA = 2;
|
||||
localparam APB_ADDR_W = s_apb_dp_ctrl.ADDR_W;
|
||||
localparam APB_DATA_W = s_apb_dp_ctrl.DATA_W;
|
||||
|
||||
logic [2:0] state_reg = STATE_IDLE;
|
||||
logic txcq_en_reg = '0;
|
||||
logic [3:0] txcq_size_reg = '0;
|
||||
logic [63:0] txcq_base_addr_reg = '0;
|
||||
logic rxcq_en_reg = '0;
|
||||
logic [3:0] rxcq_size_reg = '0;
|
||||
logic [63:0] rxcq_base_addr_reg = '0;
|
||||
|
||||
logic [15:0] txcq_prod_ptr_reg = '0;
|
||||
logic [15:0] rxcq_prod_ptr_reg = '0;
|
||||
|
||||
logic s_axil_ctrl_awready_reg = 1'b0;
|
||||
logic s_axil_ctrl_wready_reg = 1'b0;
|
||||
logic s_axil_ctrl_bvalid_reg = 1'b0;
|
||||
|
||||
logic s_axil_ctrl_arready_reg = 1'b0;
|
||||
logic [AXIL_DATA_W-1:0] s_axil_ctrl_rdata_reg = '0;
|
||||
logic s_axil_ctrl_rvalid_reg = 1'b0;
|
||||
|
||||
assign s_axil_ctrl_wr.awready = s_axil_ctrl_awready_reg;
|
||||
assign s_axil_ctrl_wr.wready = s_axil_ctrl_wready_reg;
|
||||
assign s_axil_ctrl_wr.bresp = '0;
|
||||
assign s_axil_ctrl_wr.buser = '0;
|
||||
assign s_axil_ctrl_wr.bvalid = s_axil_ctrl_bvalid_reg;
|
||||
|
||||
assign s_axil_ctrl_rd.arready = s_axil_ctrl_arready_reg;
|
||||
assign s_axil_ctrl_rd.rdata = s_axil_ctrl_rdata_reg;
|
||||
assign s_axil_ctrl_rd.rresp = '0;
|
||||
assign s_axil_ctrl_rd.ruser = '0;
|
||||
assign s_axil_ctrl_rd.rvalid = s_axil_ctrl_rvalid_reg;
|
||||
|
||||
logic s_apb_dp_ctrl_pready_reg = 1'b0;
|
||||
logic [AXIL_DATA_W-1:0] s_apb_dp_ctrl_prdata_reg = '0;
|
||||
|
||||
assign s_apb_dp_ctrl.pready = s_apb_dp_ctrl_pready_reg;
|
||||
assign s_apb_dp_ctrl.prdata = s_apb_dp_ctrl_prdata_reg;
|
||||
assign s_apb_dp_ctrl.pslverr = 1'b0;
|
||||
assign s_apb_dp_ctrl.pruser = '0;
|
||||
assign s_apb_dp_ctrl.pbuser = '0;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
s_axil_ctrl_awready_reg <= 1'b0;
|
||||
s_axil_ctrl_wready_reg <= 1'b0;
|
||||
s_axil_ctrl_bvalid_reg <= s_axil_ctrl_bvalid_reg && !s_axil_ctrl_wr.bready;
|
||||
|
||||
s_axil_ctrl_arready_reg <= 1'b0;
|
||||
s_axil_ctrl_rvalid_reg <= s_axil_ctrl_rvalid_reg && !s_axil_ctrl_rd.rready;
|
||||
|
||||
s_apb_dp_ctrl_pready_reg <= 1'b0;
|
||||
|
||||
if (s_axil_ctrl_wr.awvalid && s_axil_ctrl_wr.wvalid && !s_axil_ctrl_bvalid_reg) begin
|
||||
s_axil_ctrl_awready_reg <= 1'b1;
|
||||
s_axil_ctrl_wready_reg <= 1'b1;
|
||||
s_axil_ctrl_bvalid_reg <= 1'b1;
|
||||
|
||||
// case ({s_axil_ctrl_wr.awaddr[9:2], 2'b00})
|
||||
// 10'h000: begin
|
||||
// txcq_en_reg <= s_axil_ctrl_wr.wdata[0];
|
||||
// txcq_size_reg <= s_axil_ctrl_wr.wdata[19:16];
|
||||
// end
|
||||
// 10'h008: txcq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata;
|
||||
// 10'h00c: txcq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata;
|
||||
|
||||
// 10'h100: begin
|
||||
// rxcq_en_reg <= s_axil_ctrl_wr.wdata[0];
|
||||
// rxcq_size_reg <= s_axil_ctrl_wr.wdata[19:16];
|
||||
// end
|
||||
// 10'h108: rxcq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata;
|
||||
// 10'h10c: rxcq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata;
|
||||
// default: begin end
|
||||
// endcase
|
||||
end
|
||||
|
||||
if (s_axil_ctrl_rd.arvalid && !s_axil_ctrl_rvalid_reg) begin
|
||||
s_axil_ctrl_rdata_reg <= '0;
|
||||
|
||||
s_axil_ctrl_arready_reg <= 1'b1;
|
||||
s_axil_ctrl_rvalid_reg <= 1'b1;
|
||||
|
||||
// case ({s_axil_ctrl_rd.araddr[9:2], 2'b00})
|
||||
// 10'h000: begin
|
||||
// s_axil_ctrl_rdata_reg[0] <= txcq_en_reg;
|
||||
// s_axil_ctrl_rdata_reg[19:16] <= txcq_size_reg;
|
||||
// end
|
||||
// 10'h004: s_axil_ctrl_rdata_reg[15:0] <= txcq_prod_ptr_reg;
|
||||
// 10'h008: s_axil_ctrl_rdata_reg <= txcq_base_addr_reg[31:0];
|
||||
// 10'h00c: s_axil_ctrl_rdata_reg <= txcq_base_addr_reg[63:32];
|
||||
|
||||
// 10'h100: begin
|
||||
// s_axil_ctrl_rdata_reg[0] <= rxcq_en_reg;
|
||||
// s_axil_ctrl_rdata_reg[19:16] <= rxcq_size_reg;
|
||||
// end
|
||||
// 10'h104: s_axil_ctrl_rdata_reg[15:0] <= rxcq_prod_ptr_reg;
|
||||
// 10'h108: s_axil_ctrl_rdata_reg <= rxcq_base_addr_reg[31:0];
|
||||
// 10'h10c: s_axil_ctrl_rdata_reg <= rxcq_base_addr_reg[63:32];
|
||||
// default: begin end
|
||||
// endcase
|
||||
end
|
||||
|
||||
if (s_apb_dp_ctrl.penable && s_apb_dp_ctrl.psel && !s_apb_dp_ctrl_pready_reg) begin
|
||||
s_apb_dp_ctrl_pready_reg <= 1'b1;
|
||||
s_apb_dp_ctrl_prdata_reg <= '0;
|
||||
|
||||
if (s_apb_dp_ctrl.pwrite) begin
|
||||
case ({s_apb_dp_ctrl.paddr[9:2], 2'b00})
|
||||
10'h000: begin
|
||||
txcq_en_reg <= s_apb_dp_ctrl.pwdata[0];
|
||||
txcq_size_reg <= s_apb_dp_ctrl.pwdata[19:16];
|
||||
end
|
||||
10'h008: txcq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata;
|
||||
10'h00c: txcq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata;
|
||||
|
||||
10'h100: begin
|
||||
rxcq_en_reg <= s_apb_dp_ctrl.pwdata[0];
|
||||
rxcq_size_reg <= s_apb_dp_ctrl.pwdata[19:16];
|
||||
end
|
||||
10'h108: rxcq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata;
|
||||
10'h10c: rxcq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata;
|
||||
default: begin end
|
||||
endcase
|
||||
end
|
||||
|
||||
case ({s_apb_dp_ctrl.paddr[9:2], 2'b00})
|
||||
10'h000: begin
|
||||
s_apb_dp_ctrl_prdata_reg[0] <= txcq_en_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[19:16] <= txcq_size_reg;
|
||||
end
|
||||
10'h004: s_apb_dp_ctrl_prdata_reg[15:0] <= txcq_prod_ptr_reg;
|
||||
10'h008: s_apb_dp_ctrl_prdata_reg <= txcq_base_addr_reg[31:0];
|
||||
10'h00c: s_apb_dp_ctrl_prdata_reg <= txcq_base_addr_reg[63:32];
|
||||
|
||||
10'h100: begin
|
||||
s_apb_dp_ctrl_prdata_reg[0] <= rxcq_en_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[19:16] <= rxcq_size_reg;
|
||||
end
|
||||
10'h104: s_apb_dp_ctrl_prdata_reg[15:0] <= rxcq_prod_ptr_reg;
|
||||
10'h108: s_apb_dp_ctrl_prdata_reg <= rxcq_base_addr_reg[31:0];
|
||||
10'h10c: s_apb_dp_ctrl_prdata_reg <= rxcq_base_addr_reg[63:32];
|
||||
default: begin end
|
||||
endcase
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
s_axil_ctrl_awready_reg <= 1'b0;
|
||||
s_axil_ctrl_wready_reg <= 1'b0;
|
||||
s_axil_ctrl_bvalid_reg <= 1'b0;
|
||||
|
||||
s_axil_ctrl_arready_reg <= 1'b0;
|
||||
s_axil_ctrl_rvalid_reg <= 1'b0;
|
||||
|
||||
s_apb_dp_ctrl_pready_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
STATE_IDLE,
|
||||
STATE_RX_CPL,
|
||||
STATE_WRITE_DATA
|
||||
} state_t;
|
||||
|
||||
state_t state_reg = STATE_IDLE;
|
||||
|
||||
logic phase_tag_reg = 1'b0;
|
||||
|
||||
logic irq_reg = 1'b0;
|
||||
|
||||
assign txcq_prod = txcq_prod_ptr_reg;
|
||||
assign rxcq_prod = rxcq_prod_ptr_reg;
|
||||
|
||||
assign irq = irq_reg;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
cpl_comb.tready <= 1'b0;
|
||||
s_axis_cpl.tready <= 1'b0;
|
||||
|
||||
dma_wr_desc_req.req_src_sel <= '0;
|
||||
dma_wr_desc_req.req_src_asid <= '0;
|
||||
@@ -89,11 +231,11 @@ always_ff @(posedge clk) begin
|
||||
dma_wr_desc_req.req_user <= '0;
|
||||
dma_wr_desc_req.req_valid <= dma_wr_desc_req.req_valid && !dma_wr_desc_req.req_ready;
|
||||
|
||||
if (!txcq_en) begin
|
||||
if (!txcq_en_reg) begin
|
||||
txcq_prod_ptr_reg <= '0;
|
||||
end
|
||||
|
||||
if (!rxcq_en) begin
|
||||
if (!rxcq_en_reg) begin
|
||||
rxcq_prod_ptr_reg <= '0;
|
||||
end
|
||||
|
||||
@@ -103,12 +245,12 @@ always_ff @(posedge clk) begin
|
||||
STATE_IDLE: begin
|
||||
dma_wr_desc_req.req_src_addr <= '0;
|
||||
|
||||
if (cpl_comb.tid == 0) begin
|
||||
dma_wr_desc_req.req_dst_addr <= txcq_base_addr + 64'(16'(txcq_prod_ptr_reg & ({16{1'b1}} >> (16 - txcq_size))) * 16);
|
||||
phase_tag_reg <= !txcq_prod_ptr_reg[txcq_size];
|
||||
if (cpl_comb.tvalid && !cpl_comb.tready) begin
|
||||
if (s_axis_cpl.tdest == 0) begin
|
||||
dma_wr_desc_req.req_dst_addr <= txcq_base_addr_reg + 64'(16'(txcq_prod_ptr_reg & ({16{1'b1}} >> (16 - txcq_size_reg))) * 16);
|
||||
phase_tag_reg <= !txcq_prod_ptr_reg[txcq_size_reg];
|
||||
if (s_axis_cpl.tvalid && !s_axis_cpl.tready) begin
|
||||
txcq_prod_ptr_reg <= txcq_prod_ptr_reg + 1;
|
||||
if (txcq_en) begin
|
||||
if (txcq_en_reg) begin
|
||||
dma_wr_desc_req.req_valid <= 1'b1;
|
||||
state_reg <= STATE_WRITE_DATA;
|
||||
end else begin
|
||||
@@ -116,11 +258,11 @@ always_ff @(posedge clk) begin
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
dma_wr_desc_req.req_dst_addr <= rxcq_base_addr + 64'(16'(rxcq_prod_ptr_reg & ({16{1'b1}} >> (16 - rxcq_size))) * 16);
|
||||
phase_tag_reg <= !rxcq_prod_ptr_reg[rxcq_size];
|
||||
if (cpl_comb.tvalid && !cpl_comb.tready) begin
|
||||
dma_wr_desc_req.req_dst_addr <= rxcq_base_addr_reg + 64'(16'(rxcq_prod_ptr_reg & ({16{1'b1}} >> (16 - rxcq_size_reg))) * 16);
|
||||
phase_tag_reg <= !rxcq_prod_ptr_reg[rxcq_size_reg];
|
||||
if (s_axis_cpl.tvalid && !s_axis_cpl.tready) begin
|
||||
rxcq_prod_ptr_reg <= rxcq_prod_ptr_reg + 1;
|
||||
if (rxcq_en) begin
|
||||
if (rxcq_en_reg) begin
|
||||
dma_wr_desc_req.req_valid <= 1'b1;
|
||||
state_reg <= STATE_WRITE_DATA;
|
||||
end else begin
|
||||
@@ -131,7 +273,7 @@ always_ff @(posedge clk) begin
|
||||
end
|
||||
STATE_WRITE_DATA: begin
|
||||
if (dma_wr_desc_sts.sts_valid) begin
|
||||
cpl_comb.tready <= 1'b1;
|
||||
s_axis_cpl.tready <= 1'b1;
|
||||
irq_reg <= 1'b1;
|
||||
state_reg <= STATE_IDLE;
|
||||
end
|
||||
@@ -149,27 +291,6 @@ always_ff @(posedge clk) begin
|
||||
end
|
||||
end
|
||||
|
||||
taxi_axis_arb_mux #(
|
||||
.S_COUNT(2),
|
||||
.UPDATE_TID(1),
|
||||
.ARB_ROUND_ROBIN(1),
|
||||
.ARB_LSB_HIGH_PRIO(1)
|
||||
)
|
||||
mux_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
|
||||
/*
|
||||
* AXI4-Stream input (sink)
|
||||
*/
|
||||
.s_axis(axis_cpl),
|
||||
|
||||
/*
|
||||
* AXI4-Stream output (source)
|
||||
*/
|
||||
.m_axis(cpl_comb)
|
||||
);
|
||||
|
||||
// extract parameters
|
||||
localparam SEGS = dma_ram_rd.SEGS;
|
||||
localparam SEG_ADDR_W = dma_ram_rd.SEG_ADDR_W;
|
||||
@@ -179,7 +300,7 @@ localparam SEG_BE_W = dma_ram_rd.SEG_BE_W;
|
||||
if (SEGS*SEG_DATA_W < 128)
|
||||
$fatal(0, "Total segmented interface width must be at least 128 (instance %m)");
|
||||
|
||||
wire [SEGS-1:0][SEG_DATA_W-1:0] ram_data = (SEG_DATA_W*SEGS)'({phase_tag_reg, cpl_comb.tdata[126:0]});
|
||||
wire [SEGS-1:0][SEG_DATA_W-1:0] ram_data = (SEG_DATA_W*SEGS)'({phase_tag_reg, s_axis_cpl.tdata[126:0]});
|
||||
|
||||
for (genvar n = 0; n < SEGS; n = n + 1) begin
|
||||
|
||||
|
||||
@@ -20,6 +20,17 @@ module cndm_micro_desc_rd
|
||||
input wire logic clk,
|
||||
input wire logic rst,
|
||||
|
||||
/*
|
||||
* Control register interface
|
||||
*/
|
||||
taxi_axil_if.wr_slv s_axil_ctrl_wr,
|
||||
taxi_axil_if.rd_slv s_axil_ctrl_rd,
|
||||
|
||||
/*
|
||||
* Datapath control register interface
|
||||
*/
|
||||
taxi_apb_if.slv s_apb_dp_ctrl,
|
||||
|
||||
/*
|
||||
* DMA
|
||||
*/
|
||||
@@ -27,23 +38,195 @@ module cndm_micro_desc_rd
|
||||
taxi_dma_desc_if.sts_snk dma_rd_desc_sts,
|
||||
taxi_dma_ram_if.wr_slv dma_ram_wr,
|
||||
|
||||
input wire logic txq_en,
|
||||
input wire logic [3:0] txq_size,
|
||||
input wire logic [63:0] txq_base_addr,
|
||||
input wire logic [15:0] txq_prod,
|
||||
output wire logic [15:0] txq_cons,
|
||||
input wire logic rxq_en,
|
||||
input wire logic [3:0] rxq_size,
|
||||
input wire logic [63:0] rxq_base_addr,
|
||||
input wire logic [15:0] rxq_prod,
|
||||
output wire logic [15:0] rxq_cons,
|
||||
|
||||
input wire logic [1:0] desc_req,
|
||||
taxi_axis_if.src axis_desc[2]
|
||||
taxi_axis_if.src m_axis_desc
|
||||
);
|
||||
|
||||
localparam AXIL_ADDR_W = s_axil_ctrl_wr.ADDR_W;
|
||||
localparam AXIL_DATA_W = s_axil_ctrl_wr.DATA_W;
|
||||
|
||||
localparam APB_ADDR_W = s_apb_dp_ctrl.ADDR_W;
|
||||
localparam APB_DATA_W = s_apb_dp_ctrl.DATA_W;
|
||||
|
||||
localparam RAM_ADDR_W = 16;
|
||||
|
||||
logic txq_en_reg = '0;
|
||||
logic [3:0] txq_size_reg = '0;
|
||||
logic [7:0] txq_cqn_reg = '0;
|
||||
logic [63:0] txq_base_addr_reg = '0;
|
||||
logic [15:0] txq_prod_reg = '0;
|
||||
logic rxq_en_reg = '0;
|
||||
logic [3:0] rxq_size_reg = '0;
|
||||
logic [7:0] rxq_cqn_reg = '0;
|
||||
logic [63:0] rxq_base_addr_reg = '0;
|
||||
logic [15:0] rxq_prod_reg = '0;
|
||||
|
||||
logic [15:0] txq_cons_ptr_reg = '0;
|
||||
logic [15:0] rxq_cons_ptr_reg = '0;
|
||||
|
||||
logic s_axil_ctrl_awready_reg = 1'b0;
|
||||
logic s_axil_ctrl_wready_reg = 1'b0;
|
||||
logic s_axil_ctrl_bvalid_reg = 1'b0;
|
||||
|
||||
logic s_axil_ctrl_arready_reg = 1'b0;
|
||||
logic [AXIL_DATA_W-1:0] s_axil_ctrl_rdata_reg = '0;
|
||||
logic s_axil_ctrl_rvalid_reg = 1'b0;
|
||||
|
||||
assign s_axil_ctrl_wr.awready = s_axil_ctrl_awready_reg;
|
||||
assign s_axil_ctrl_wr.wready = s_axil_ctrl_wready_reg;
|
||||
assign s_axil_ctrl_wr.bresp = '0;
|
||||
assign s_axil_ctrl_wr.buser = '0;
|
||||
assign s_axil_ctrl_wr.bvalid = s_axil_ctrl_bvalid_reg;
|
||||
|
||||
assign s_axil_ctrl_rd.arready = s_axil_ctrl_arready_reg;
|
||||
assign s_axil_ctrl_rd.rdata = s_axil_ctrl_rdata_reg;
|
||||
assign s_axil_ctrl_rd.rresp = '0;
|
||||
assign s_axil_ctrl_rd.ruser = '0;
|
||||
assign s_axil_ctrl_rd.rvalid = s_axil_ctrl_rvalid_reg;
|
||||
|
||||
logic s_apb_dp_ctrl_pready_reg = 1'b0;
|
||||
logic [AXIL_DATA_W-1:0] s_apb_dp_ctrl_prdata_reg = '0;
|
||||
|
||||
assign s_apb_dp_ctrl.pready = s_apb_dp_ctrl_pready_reg;
|
||||
assign s_apb_dp_ctrl.prdata = s_apb_dp_ctrl_prdata_reg;
|
||||
assign s_apb_dp_ctrl.pslverr = 1'b0;
|
||||
assign s_apb_dp_ctrl.pruser = '0;
|
||||
assign s_apb_dp_ctrl.pbuser = '0;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
s_axil_ctrl_awready_reg <= 1'b0;
|
||||
s_axil_ctrl_wready_reg <= 1'b0;
|
||||
s_axil_ctrl_bvalid_reg <= s_axil_ctrl_bvalid_reg && !s_axil_ctrl_wr.bready;
|
||||
|
||||
s_axil_ctrl_arready_reg <= 1'b0;
|
||||
s_axil_ctrl_rvalid_reg <= s_axil_ctrl_rvalid_reg && !s_axil_ctrl_rd.rready;
|
||||
|
||||
s_apb_dp_ctrl_pready_reg <= 1'b0;
|
||||
|
||||
if (s_axil_ctrl_wr.awvalid && s_axil_ctrl_wr.wvalid && !s_axil_ctrl_bvalid_reg) begin
|
||||
s_axil_ctrl_awready_reg <= 1'b1;
|
||||
s_axil_ctrl_wready_reg <= 1'b1;
|
||||
s_axil_ctrl_bvalid_reg <= 1'b1;
|
||||
|
||||
case ({s_axil_ctrl_wr.awaddr[9:2], 2'b00})
|
||||
// 10'h000: begin
|
||||
// txq_en_reg <= s_axil_ctrl_wr.wdata[0];
|
||||
// txq_size_reg <= s_axil_ctrl_wr.wdata[19:16];
|
||||
// end
|
||||
10'h004: txq_prod_reg <= s_axil_ctrl_wr.wdata[15:0];
|
||||
// 10'h008: txq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata;
|
||||
// 10'h00c: txq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata;
|
||||
|
||||
// 10'h100: begin
|
||||
// rxq_en_reg <= s_axil_ctrl_wr.wdata[0];
|
||||
// rxq_size_reg <= s_axil_ctrl_wr.wdata[19:16];
|
||||
// end
|
||||
10'h104: rxq_prod_reg <= s_axil_ctrl_wr.wdata[15:0];
|
||||
// 10'h108: rxq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata;
|
||||
// 10'h10c: rxq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata;
|
||||
default: begin end
|
||||
endcase
|
||||
end
|
||||
|
||||
if (s_axil_ctrl_rd.arvalid && !s_axil_ctrl_rvalid_reg) begin
|
||||
s_axil_ctrl_rdata_reg <= '0;
|
||||
|
||||
s_axil_ctrl_arready_reg <= 1'b1;
|
||||
s_axil_ctrl_rvalid_reg <= 1'b1;
|
||||
|
||||
// case ({s_axil_ctrl_rd.araddr[9:2], 2'b00})
|
||||
// 10'h000: begin
|
||||
// s_axil_ctrl_rdata_reg[0] <= txq_en_reg;
|
||||
// s_axil_ctrl_rdata_reg[19:16] <= txq_size_reg;
|
||||
// end
|
||||
// 10'h004: begin
|
||||
// s_axil_ctrl_rdata_reg[15:0] <= txq_prod_reg;
|
||||
// s_axil_ctrl_rdata_reg[31:16] <= txq_cons_ptr_reg;
|
||||
// end
|
||||
// 10'h008: s_axil_ctrl_rdata_reg <= txq_base_addr_reg[31:0];
|
||||
// 10'h00c: s_axil_ctrl_rdata_reg <= txq_base_addr_reg[63:32];
|
||||
|
||||
// 10'h100: begin
|
||||
// s_axil_ctrl_rdata_reg[0] <= rxq_en_reg;
|
||||
// s_axil_ctrl_rdata_reg[19:16] <= rxq_size_reg;
|
||||
// end
|
||||
// 10'h104: begin
|
||||
// s_axil_ctrl_rdata_reg[15:0] <= rxq_prod_reg;
|
||||
// s_axil_ctrl_rdata_reg[31:16] <= rxq_cons_ptr_reg;
|
||||
// end
|
||||
// 10'h108: s_axil_ctrl_rdata_reg <= rxq_base_addr_reg[31:0];
|
||||
// 10'h10c: s_axil_ctrl_rdata_reg <= rxq_base_addr_reg[63:32];
|
||||
// default: begin end
|
||||
// endcase
|
||||
end
|
||||
|
||||
if (s_apb_dp_ctrl.penable && s_apb_dp_ctrl.psel && !s_apb_dp_ctrl_pready_reg) begin
|
||||
s_apb_dp_ctrl_pready_reg <= 1'b1;
|
||||
s_apb_dp_ctrl_prdata_reg <= '0;
|
||||
|
||||
if (s_apb_dp_ctrl.pwrite) begin
|
||||
case ({s_apb_dp_ctrl.paddr[9:2], 2'b00})
|
||||
10'h000: begin
|
||||
txq_en_reg <= s_apb_dp_ctrl.pwdata[0];
|
||||
txq_size_reg <= s_apb_dp_ctrl.pwdata[19:16];
|
||||
txq_cqn_reg <= s_apb_dp_ctrl.pwdata[31:24];
|
||||
end
|
||||
10'h004: txq_prod_reg <= s_apb_dp_ctrl.pwdata[15:0];
|
||||
10'h008: txq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata;
|
||||
10'h00c: txq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata;
|
||||
|
||||
10'h100: begin
|
||||
rxq_en_reg <= s_apb_dp_ctrl.pwdata[0];
|
||||
rxq_size_reg <= s_apb_dp_ctrl.pwdata[19:16];
|
||||
rxq_cqn_reg <= s_apb_dp_ctrl.pwdata[31:24];
|
||||
end
|
||||
10'h104: rxq_prod_reg <= s_apb_dp_ctrl.pwdata[15:0];
|
||||
10'h108: rxq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata;
|
||||
10'h10c: rxq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata;
|
||||
default: begin end
|
||||
endcase
|
||||
end
|
||||
|
||||
case ({s_apb_dp_ctrl.paddr[9:2], 2'b00})
|
||||
10'h000: begin
|
||||
s_apb_dp_ctrl_prdata_reg[0] <= txq_en_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[19:16] <= txq_size_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[31:24] <= txq_cqn_reg;
|
||||
end
|
||||
10'h004: begin
|
||||
s_apb_dp_ctrl_prdata_reg[15:0] <= txq_prod_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[31:16] <= txq_cons_ptr_reg;
|
||||
end
|
||||
10'h008: s_apb_dp_ctrl_prdata_reg <= txq_base_addr_reg[31:0];
|
||||
10'h00c: s_apb_dp_ctrl_prdata_reg <= txq_base_addr_reg[63:32];
|
||||
|
||||
10'h100: begin
|
||||
s_apb_dp_ctrl_prdata_reg[0] <= rxq_en_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[19:16] <= rxq_size_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[31:24] <= rxq_cqn_reg;
|
||||
end
|
||||
10'h104: begin
|
||||
s_apb_dp_ctrl_prdata_reg[15:0] <= rxq_prod_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[31:16] <= rxq_cons_ptr_reg;
|
||||
end
|
||||
10'h108: s_apb_dp_ctrl_prdata_reg <= rxq_base_addr_reg[31:0];
|
||||
10'h10c: s_apb_dp_ctrl_prdata_reg <= rxq_base_addr_reg[63:32];
|
||||
default: begin end
|
||||
endcase
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
s_axil_ctrl_awready_reg <= 1'b0;
|
||||
s_axil_ctrl_wready_reg <= 1'b0;
|
||||
s_axil_ctrl_bvalid_reg <= 1'b0;
|
||||
|
||||
s_axil_ctrl_arready_reg <= 1'b0;
|
||||
s_axil_ctrl_rvalid_reg <= 1'b0;
|
||||
|
||||
s_apb_dp_ctrl_pready_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
taxi_dma_desc_if #(
|
||||
.SRC_ADDR_W(RAM_ADDR_W),
|
||||
.SRC_SEL_EN(1'b0),
|
||||
@@ -54,29 +237,25 @@ taxi_dma_desc_if #(
|
||||
.IMM_EN(1'b0),
|
||||
.LEN_W(5),
|
||||
.TAG_W(1),
|
||||
.ID_EN(0),
|
||||
.DEST_EN(1),
|
||||
.DEST_W(1),
|
||||
.USER_EN(1),
|
||||
.USER_W(1)
|
||||
.ID_EN(m_axis_desc.ID_EN),
|
||||
.ID_W(m_axis_desc.ID_W),
|
||||
.DEST_EN(m_axis_desc.DEST_EN),
|
||||
.DEST_W(m_axis_desc.DEST_W),
|
||||
.USER_EN(m_axis_desc.USER_EN),
|
||||
.USER_W(m_axis_desc.USER_W)
|
||||
) dma_desc();
|
||||
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 0,
|
||||
STATE_READ_DESC = 1,
|
||||
STATE_READ_DATA = 2,
|
||||
STATE_TX_DESC = 3;
|
||||
typedef enum logic [1:0] {
|
||||
STATE_IDLE,
|
||||
STATE_READ_DESC,
|
||||
STATE_READ_DATA,
|
||||
STATE_TX_DESC
|
||||
} state_t;
|
||||
|
||||
logic [2:0] state_reg = STATE_IDLE;
|
||||
state_t state_reg = STATE_IDLE;
|
||||
|
||||
logic [1:0] desc_req_reg = '0;
|
||||
|
||||
logic [15:0] txq_cons_ptr_reg = '0;
|
||||
logic [15:0] rxq_cons_ptr_reg = '0;
|
||||
|
||||
assign txq_cons = txq_cons_ptr_reg;
|
||||
assign rxq_cons = rxq_cons_ptr_reg;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
// axis_desc.tready <= 1'b0;
|
||||
|
||||
@@ -102,27 +281,27 @@ always_ff @(posedge clk) begin
|
||||
dma_desc.req_imm_en <= '0;
|
||||
dma_desc.req_len <= 16;
|
||||
dma_desc.req_tag <= '0;
|
||||
dma_desc.req_id <= '0;
|
||||
dma_desc.req_user <= '0;
|
||||
dma_desc.req_valid <= dma_desc.req_valid && !dma_desc.req_ready;
|
||||
|
||||
desc_req_reg <= desc_req_reg | desc_req;
|
||||
|
||||
if (!txq_en) begin
|
||||
if (!txq_en_reg) begin
|
||||
txq_cons_ptr_reg <= '0;
|
||||
end
|
||||
|
||||
if (!rxq_en) begin
|
||||
if (!rxq_en_reg) begin
|
||||
rxq_cons_ptr_reg <= '0;
|
||||
end
|
||||
|
||||
case (state_reg)
|
||||
STATE_IDLE: begin
|
||||
if (desc_req_reg[1]) begin
|
||||
dma_rd_desc_req.req_src_addr <= rxq_base_addr + 64'(16'(rxq_cons_ptr_reg & ({16{1'b1}} >> (16 - rxq_size))) * 16);
|
||||
dma_desc.req_dest <= 1'b1;
|
||||
dma_rd_desc_req.req_src_addr <= rxq_base_addr_reg + 64'(16'(rxq_cons_ptr_reg & ({16{1'b1}} >> (16 - rxq_size_reg))) * 16);
|
||||
dma_desc.req_id <= 1'b1;
|
||||
dma_desc.req_dest <= rxq_cqn_reg;
|
||||
desc_req_reg[1] <= 1'b0;
|
||||
if (rxq_cons_ptr_reg == rxq_prod || !rxq_en) begin
|
||||
if (rxq_cons_ptr_reg == rxq_prod_reg || !rxq_en_reg) begin
|
||||
dma_desc.req_user <= 1'b1;
|
||||
dma_desc.req_valid <= 1'b1;
|
||||
state_reg <= STATE_TX_DESC;
|
||||
@@ -133,10 +312,11 @@ always_ff @(posedge clk) begin
|
||||
state_reg <= STATE_READ_DESC;
|
||||
end
|
||||
end else if (desc_req_reg[0]) begin
|
||||
dma_rd_desc_req.req_src_addr <= txq_base_addr + 64'(16'(txq_cons_ptr_reg & ({16{1'b1}} >> (16 - txq_size))) * 16);
|
||||
dma_desc.req_dest <= 1'b0;
|
||||
dma_rd_desc_req.req_src_addr <= txq_base_addr_reg + 64'(16'(txq_cons_ptr_reg & ({16{1'b1}} >> (16 - txq_size_reg))) * 16);
|
||||
dma_desc.req_id <= 1'b0;
|
||||
dma_desc.req_dest <= txq_cqn_reg;
|
||||
desc_req_reg[0] <= 1'b0;
|
||||
if (txq_cons_ptr_reg == txq_prod || !txq_en) begin
|
||||
if (txq_cons_ptr_reg == txq_prod_reg || !txq_en_reg) begin
|
||||
dma_desc.req_user <= 1'b1;
|
||||
dma_desc.req_valid <= 1'b1;
|
||||
state_reg <= STATE_TX_DESC;
|
||||
@@ -195,19 +375,6 @@ ram_inst (
|
||||
.dma_ram_rd(dma_ram_rd)
|
||||
);
|
||||
|
||||
taxi_axis_if #(
|
||||
.DATA_W(axis_desc[0].DATA_W),
|
||||
.KEEP_EN(axis_desc[0].KEEP_EN),
|
||||
.KEEP_W(axis_desc[0].KEEP_W),
|
||||
.LAST_EN(axis_desc[0].LAST_EN),
|
||||
.ID_EN(axis_desc[0].ID_EN),
|
||||
.ID_W(axis_desc[0].ID_W),
|
||||
.DEST_EN(1),
|
||||
.DEST_W(1),
|
||||
.USER_EN(axis_desc[0].USER_EN),
|
||||
.USER_W(axis_desc[0].USER_W)
|
||||
) m_axis_rd_data();
|
||||
|
||||
taxi_dma_client_axis_source
|
||||
dma_inst (
|
||||
.clk(clk),
|
||||
@@ -222,7 +389,7 @@ dma_inst (
|
||||
/*
|
||||
* AXI stream read data output
|
||||
*/
|
||||
.m_axis_rd_data(m_axis_rd_data),
|
||||
.m_axis_rd_data(m_axis_desc),
|
||||
|
||||
/*
|
||||
* RAM interface
|
||||
@@ -235,32 +402,6 @@ dma_inst (
|
||||
.enable(1'b1)
|
||||
);
|
||||
|
||||
taxi_axis_demux #(
|
||||
.M_COUNT(2),
|
||||
.TDEST_ROUTE(1)
|
||||
)
|
||||
demux_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
|
||||
/*
|
||||
* AXI4-Stream input (sink)
|
||||
*/
|
||||
.s_axis(m_axis_rd_data),
|
||||
|
||||
/*
|
||||
* AXI4-Stream output (source)
|
||||
*/
|
||||
.m_axis(axis_desc),
|
||||
|
||||
/*
|
||||
* Control
|
||||
*/
|
||||
.enable(1'b1),
|
||||
.drop(1'b0),
|
||||
.select('0)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
||||
|
||||
@@ -82,12 +82,14 @@ typedef enum logic [4:0] {
|
||||
STATE_REG_1,
|
||||
STATE_REG_2,
|
||||
STATE_REG_3,
|
||||
STATE_Q_RESET_1,
|
||||
STATE_Q_RESET_2,
|
||||
STATE_Q_SET_BASE_L,
|
||||
STATE_Q_SET_BASE_H,
|
||||
STATE_Q_ENABLE,
|
||||
STATE_Q_DISABLE,
|
||||
STATE_CREATE_Q_FIND_1,
|
||||
STATE_CREATE_Q_FIND_2,
|
||||
STATE_CREATE_Q_RESET_1,
|
||||
STATE_CREATE_Q_RESET_2,
|
||||
STATE_CREATE_Q_SET_BASE_L,
|
||||
STATE_CREATE_Q_SET_BASE_H,
|
||||
STATE_CREATE_Q_ENABLE,
|
||||
STATE_DESTROY_Q_DISABLE,
|
||||
STATE_PTP_READ_1,
|
||||
STATE_PTP_READ_2,
|
||||
STATE_PTP_SET,
|
||||
@@ -152,6 +154,7 @@ logic [15:0] opcode_reg = '0, opcode_next;
|
||||
logic [31:0] flags_reg = '0, flags_next;
|
||||
logic [15:0] port_reg = '0, port_next;
|
||||
logic [23:0] qn_reg = '0, qn_next;
|
||||
logic [23:0] qn2_reg = '0, qn2_next;
|
||||
|
||||
logic [3:0] cmd_ptr_reg = '0, cmd_ptr_next;
|
||||
logic [DP_APB_ADDR_W-1:0] dp_ptr_reg = '0, dp_ptr_next;
|
||||
@@ -190,6 +193,7 @@ always_comb begin
|
||||
flags_next = flags_reg;
|
||||
port_next = port_reg;
|
||||
qn_next = qn_reg;
|
||||
qn2_next = qn2_reg;
|
||||
|
||||
cmd_ptr_next = cmd_ptr_reg;
|
||||
dp_ptr_next = dp_ptr_reg;
|
||||
@@ -220,6 +224,7 @@ always_comb begin
|
||||
4'd1: flags_next = s_axis_cmd.tdata;
|
||||
4'd2: port_next = s_axis_cmd.tdata[15:0];
|
||||
4'd3: qn_next = s_axis_cmd.tdata[23:0];
|
||||
4'd4: qn2_next = s_axis_cmd.tdata[23:0];
|
||||
default: begin end
|
||||
endcase
|
||||
|
||||
@@ -242,46 +247,65 @@ always_comb begin
|
||||
|
||||
// determine block base address
|
||||
case (opcode_reg)
|
||||
CMD_OP_CREATE_EQ,
|
||||
CMD_OP_MODIFY_EQ,
|
||||
CMD_OP_QUERY_EQ,
|
||||
CMD_OP_DESTROY_EQ:
|
||||
// CMD_OP_CREATE_EQ:
|
||||
// begin
|
||||
// // EQ
|
||||
// qn_next = 0;
|
||||
// dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h8000) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
||||
// host_ptr_next = 32'({port_reg, 16'd0} | 'h8000) + PORT_BASE_ADDR_HOST;
|
||||
// end
|
||||
// CMD_OP_MODIFY_EQ,
|
||||
// CMD_OP_QUERY_EQ,
|
||||
// CMD_OP_DESTROY_EQ:
|
||||
// begin
|
||||
// // EQ
|
||||
// dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h8000) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
||||
// host_ptr_next = 32'({port_reg, 16'd0} | 'h8000) + PORT_BASE_ADDR_HOST;
|
||||
// end
|
||||
CMD_OP_CREATE_CQ:
|
||||
begin
|
||||
// EQ
|
||||
dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0000) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
||||
host_ptr_next = 32'({port_reg, 16'd0} | 'h0000) + PORT_BASE_ADDR_HOST;
|
||||
// CQ
|
||||
cnt_next = 1;
|
||||
dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h8000) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
||||
host_ptr_next = 32'({port_reg, 16'd0} | 'h8000) + PORT_BASE_ADDR_HOST;
|
||||
end
|
||||
CMD_OP_CREATE_CQ,
|
||||
CMD_OP_MODIFY_CQ,
|
||||
CMD_OP_QUERY_CQ,
|
||||
CMD_OP_DESTROY_CQ:
|
||||
begin
|
||||
// CQ
|
||||
if (qn_reg[0]) begin
|
||||
dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0300) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
||||
host_ptr_next = 32'({port_reg, 16'd0} | 'h0300) + PORT_BASE_ADDR_HOST;
|
||||
end else begin
|
||||
dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0400) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
||||
host_ptr_next = 32'({port_reg, 16'd0} | 'h0400) + PORT_BASE_ADDR_HOST;
|
||||
end
|
||||
dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h8000 | {qn_reg, 8'd00}) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
||||
host_ptr_next = 32'({port_reg, 16'd0} | 'h8000 | {qn_reg, 8'd00}) + PORT_BASE_ADDR_HOST;
|
||||
end
|
||||
CMD_OP_CREATE_SQ:
|
||||
begin
|
||||
// SQ
|
||||
cnt_next = 0;
|
||||
dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0000) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
||||
host_ptr_next = 32'({port_reg, 16'd0} | 'h0000) + PORT_BASE_ADDR_HOST;
|
||||
end
|
||||
CMD_OP_CREATE_SQ,
|
||||
CMD_OP_MODIFY_SQ,
|
||||
CMD_OP_QUERY_SQ,
|
||||
CMD_OP_DESTROY_SQ:
|
||||
begin
|
||||
// SQ
|
||||
dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0000) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
||||
host_ptr_next = 32'({port_reg, 16'd0} | 'h0000) + PORT_BASE_ADDR_HOST;
|
||||
end
|
||||
CMD_OP_CREATE_RQ:
|
||||
begin
|
||||
// RQ
|
||||
cnt_next = 0;
|
||||
dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0100) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
||||
host_ptr_next = 32'({port_reg, 16'd0} | 'h0100) + PORT_BASE_ADDR_HOST;
|
||||
end
|
||||
CMD_OP_CREATE_RQ,
|
||||
CMD_OP_MODIFY_RQ,
|
||||
CMD_OP_QUERY_RQ,
|
||||
CMD_OP_DESTROY_RQ:
|
||||
begin
|
||||
// RQ
|
||||
dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0200) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
||||
host_ptr_next = 32'({port_reg, 16'd0} | 'h0200) + PORT_BASE_ADDR_HOST;
|
||||
dp_ptr_next = DP_APB_ADDR_W'({port_reg, 16'd0} | 'h0100) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
||||
host_ptr_next = 32'({port_reg, 16'd0} | 'h0100) + PORT_BASE_ADDR_HOST;
|
||||
end
|
||||
default: begin end
|
||||
endcase
|
||||
@@ -330,7 +354,8 @@ always_comb begin
|
||||
CMD_OP_CREATE_RQ:
|
||||
begin
|
||||
// create queue operation
|
||||
state_next = STATE_Q_RESET_1;
|
||||
qn_next = '0;
|
||||
state_next = STATE_CREATE_Q_FIND_1;
|
||||
end
|
||||
CMD_OP_MODIFY_EQ,
|
||||
CMD_OP_MODIFY_CQ,
|
||||
@@ -366,7 +391,7 @@ always_comb begin
|
||||
CMD_OP_DESTROY_RQ:
|
||||
begin
|
||||
// destroy queue operation
|
||||
state_next = STATE_Q_DISABLE;
|
||||
state_next = STATE_DESTROY_Q_DISABLE;
|
||||
end
|
||||
default: begin
|
||||
// unknown opcode
|
||||
@@ -420,8 +445,56 @@ always_comb begin
|
||||
state_next = STATE_REG_3;
|
||||
end
|
||||
end
|
||||
STATE_Q_RESET_1: begin
|
||||
STATE_CREATE_Q_FIND_1: begin
|
||||
// read queue enable bit
|
||||
if (!m_apb_dp_ctrl_psel_reg) begin
|
||||
m_apb_dp_ctrl_paddr_next = dp_ptr_reg + 'h0000;
|
||||
m_apb_dp_ctrl_psel_next = 1'b1;
|
||||
m_apb_dp_ctrl_pwrite_next = 1'b0;
|
||||
m_apb_dp_ctrl_pwdata_next = 32'h00000000;
|
||||
m_apb_dp_ctrl_pstrb_next = '1;
|
||||
|
||||
state_next = STATE_CREATE_Q_FIND_2;
|
||||
end else begin
|
||||
state_next = STATE_CREATE_Q_FIND_1;
|
||||
end
|
||||
end
|
||||
STATE_CREATE_Q_FIND_2: begin
|
||||
// check queue enable bit
|
||||
if (m_apb_dp_ctrl.pready) begin
|
||||
cnt_next = cnt_reg - 1;
|
||||
|
||||
if (m_apb_dp_ctrl.prdata[0] == 0) begin
|
||||
// queue is inactive
|
||||
state_next = STATE_CREATE_Q_RESET_1;
|
||||
end else begin
|
||||
// queue is active
|
||||
qn_next = qn_reg + 1;
|
||||
dp_ptr_next = dp_ptr_reg + 'h100;
|
||||
if (cnt_reg == 0) begin
|
||||
// no more queues
|
||||
m_axis_rsp_tdata_next = '0; // TODO
|
||||
m_axis_rsp_tvalid_next = 1'b1;
|
||||
m_axis_rsp_tlast_next = 1'b0;
|
||||
|
||||
state_next = STATE_PAD_RSP;
|
||||
end else begin
|
||||
// try next queue
|
||||
state_next = STATE_CREATE_Q_FIND_1;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_CREATE_Q_FIND_2;
|
||||
end
|
||||
end
|
||||
STATE_CREATE_Q_RESET_1: begin
|
||||
// reset queue 1
|
||||
|
||||
// store queue number
|
||||
cmd_ram_wr_data = 32'(qn_reg);
|
||||
cmd_ram_wr_addr = 3;
|
||||
cmd_ram_wr_en = 1'b1;
|
||||
|
||||
if (!m_apb_dp_ctrl_psel_reg) begin
|
||||
m_apb_dp_ctrl_paddr_next = dp_ptr_reg + 'h0000;
|
||||
m_apb_dp_ctrl_psel_next = 1'b1;
|
||||
@@ -429,14 +502,15 @@ always_comb begin
|
||||
m_apb_dp_ctrl_pwdata_next = 32'h00000000;
|
||||
m_apb_dp_ctrl_pstrb_next = '1;
|
||||
|
||||
state_next = STATE_Q_RESET_2;
|
||||
state_next = STATE_CREATE_Q_RESET_2;
|
||||
end else begin
|
||||
state_next = STATE_Q_RESET_1;
|
||||
state_next = STATE_CREATE_Q_RESET_1;
|
||||
end
|
||||
end
|
||||
STATE_Q_RESET_2: begin
|
||||
STATE_CREATE_Q_RESET_2: begin
|
||||
// reset queue 2
|
||||
|
||||
// store doorbell offset
|
||||
cmd_ram_wr_data = host_ptr_reg + 'h0004;
|
||||
cmd_ram_wr_addr = 7;
|
||||
cmd_ram_wr_en = 1'b1;
|
||||
@@ -448,12 +522,12 @@ always_comb begin
|
||||
m_apb_dp_ctrl_pwdata_next = 32'h00000000;
|
||||
m_apb_dp_ctrl_pstrb_next = '1;
|
||||
|
||||
state_next = STATE_Q_SET_BASE_L;
|
||||
state_next = STATE_CREATE_Q_SET_BASE_L;
|
||||
end else begin
|
||||
state_next = STATE_Q_RESET_2;
|
||||
state_next = STATE_CREATE_Q_RESET_2;
|
||||
end
|
||||
end
|
||||
STATE_Q_SET_BASE_L: begin
|
||||
STATE_CREATE_Q_SET_BASE_L: begin
|
||||
// set queue base addr (LSB)
|
||||
cmd_ram_rd_addr = 8;
|
||||
if (!m_apb_dp_ctrl_psel_reg) begin
|
||||
@@ -463,12 +537,12 @@ always_comb begin
|
||||
m_apb_dp_ctrl_pwdata_next = cmd_ram_rd_data;
|
||||
m_apb_dp_ctrl_pstrb_next = '1;
|
||||
|
||||
state_next = STATE_Q_SET_BASE_H;
|
||||
state_next = STATE_CREATE_Q_SET_BASE_H;
|
||||
end else begin
|
||||
state_next = STATE_Q_SET_BASE_L;
|
||||
state_next = STATE_CREATE_Q_SET_BASE_L;
|
||||
end
|
||||
end
|
||||
STATE_Q_SET_BASE_H: begin
|
||||
STATE_CREATE_Q_SET_BASE_H: begin
|
||||
// set queue base addr (MSB)
|
||||
cmd_ram_rd_addr = 9;
|
||||
if (!m_apb_dp_ctrl_psel_reg) begin
|
||||
@@ -478,12 +552,12 @@ always_comb begin
|
||||
m_apb_dp_ctrl_pwdata_next = cmd_ram_rd_data;
|
||||
m_apb_dp_ctrl_pstrb_next = '1;
|
||||
|
||||
state_next = STATE_Q_ENABLE;
|
||||
state_next = STATE_CREATE_Q_ENABLE;
|
||||
end else begin
|
||||
state_next = STATE_Q_SET_BASE_H;
|
||||
state_next = STATE_CREATE_Q_SET_BASE_H;
|
||||
end
|
||||
end
|
||||
STATE_Q_ENABLE: begin
|
||||
STATE_CREATE_Q_ENABLE: begin
|
||||
// enable queue
|
||||
cmd_ram_rd_addr = 6;
|
||||
if (!m_apb_dp_ctrl_psel_reg) begin
|
||||
@@ -491,6 +565,7 @@ always_comb begin
|
||||
m_apb_dp_ctrl_psel_next = 1'b1;
|
||||
m_apb_dp_ctrl_pwrite_next = 1'b1;
|
||||
m_apb_dp_ctrl_pwdata_next = '0;
|
||||
m_apb_dp_ctrl_pwdata_next[31:24] = qn2_reg[7:0];
|
||||
m_apb_dp_ctrl_pwdata_next[19:16] = cmd_ram_rd_data[3:0];
|
||||
m_apb_dp_ctrl_pwdata_next[0] = 1'b1;
|
||||
m_apb_dp_ctrl_pstrb_next = '1;
|
||||
@@ -501,10 +576,10 @@ always_comb begin
|
||||
|
||||
state_next = STATE_SEND_RSP;
|
||||
end else begin
|
||||
state_next = STATE_Q_ENABLE;
|
||||
state_next = STATE_CREATE_Q_ENABLE;
|
||||
end
|
||||
end
|
||||
STATE_Q_DISABLE: begin
|
||||
STATE_DESTROY_Q_DISABLE: begin
|
||||
// disable queue
|
||||
if (!m_apb_dp_ctrl_psel_reg) begin
|
||||
m_apb_dp_ctrl_paddr_next = dp_ptr_reg + 'h0000;
|
||||
@@ -519,7 +594,7 @@ always_comb begin
|
||||
|
||||
state_next = STATE_SEND_RSP;
|
||||
end else begin
|
||||
state_next = STATE_Q_DISABLE;
|
||||
state_next = STATE_DESTROY_Q_DISABLE;
|
||||
end
|
||||
end
|
||||
STATE_PTP_READ_1: begin
|
||||
@@ -746,6 +821,7 @@ always_ff @(posedge clk) begin
|
||||
flags_reg <= flags_next;
|
||||
port_reg <= port_next;
|
||||
qn_reg <= qn_next;
|
||||
qn2_reg <= qn2_next;
|
||||
|
||||
cmd_ptr_reg <= cmd_ptr_next;
|
||||
dp_ptr_reg <= dp_ptr_next;
|
||||
|
||||
@@ -75,244 +75,76 @@ localparam RAM_SEG_DATA_W = dma_ram_wr.SEG_DATA_W;
|
||||
localparam RAM_SEG_BE_W = dma_ram_wr.SEG_BE_W;
|
||||
localparam RAM_SEL_W = dma_ram_wr.SEL_W;
|
||||
|
||||
logic txq_en_reg = '0;
|
||||
logic [3:0] txq_size_reg = '0;
|
||||
logic [63:0] txq_base_addr_reg = '0;
|
||||
logic [15:0] txq_prod_reg = '0;
|
||||
wire [15:0] txq_cons;
|
||||
logic rxq_en_reg = '0;
|
||||
logic [3:0] rxq_size_reg = '0;
|
||||
logic [63:0] rxq_base_addr_reg = '0;
|
||||
logic [15:0] rxq_prod_reg = '0;
|
||||
wire [15:0] rxq_cons;
|
||||
taxi_axil_if #(
|
||||
.DATA_W(s_axil_ctrl_wr.DATA_W),
|
||||
.ADDR_W(15),
|
||||
.STRB_W(s_axil_ctrl_wr.STRB_W),
|
||||
.AWUSER_EN(s_axil_ctrl_wr.AWUSER_EN),
|
||||
.AWUSER_W(s_axil_ctrl_wr.AWUSER_W),
|
||||
.WUSER_EN(s_axil_ctrl_wr.WUSER_EN),
|
||||
.WUSER_W(s_axil_ctrl_wr.WUSER_W),
|
||||
.BUSER_EN(s_axil_ctrl_wr.BUSER_EN),
|
||||
.BUSER_W(s_axil_ctrl_wr.BUSER_W),
|
||||
.ARUSER_EN(s_axil_ctrl_wr.ARUSER_EN),
|
||||
.ARUSER_W(s_axil_ctrl_wr.ARUSER_W),
|
||||
.RUSER_EN(s_axil_ctrl_wr.RUSER_EN),
|
||||
.RUSER_W(s_axil_ctrl_wr.RUSER_W)
|
||||
)
|
||||
axil_ctrl[2]();
|
||||
|
||||
logic txcq_en_reg = '0;
|
||||
logic [3:0] txcq_size_reg = '0;
|
||||
logic [63:0] txcq_base_addr_reg = '0;
|
||||
wire [15:0] txcq_prod;
|
||||
logic rxcq_en_reg = '0;
|
||||
logic [3:0] rxcq_size_reg = '0;
|
||||
logic [63:0] rxcq_base_addr_reg = '0;
|
||||
wire [15:0] rxcq_prod;
|
||||
taxi_axil_interconnect_1s #(
|
||||
.M_COUNT($size(axil_ctrl)),
|
||||
.ADDR_W(s_axil_ctrl_wr.ADDR_W),
|
||||
.M_REGIONS(1),
|
||||
.M_BASE_ADDR('0),
|
||||
.M_ADDR_W({$size(axil_ctrl){{1{32'd15}}}}),
|
||||
.M_SECURE({$size(axil_ctrl){1'b0}})
|
||||
)
|
||||
port_intercon_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
|
||||
logic s_axil_ctrl_awready_reg = 1'b0;
|
||||
logic s_axil_ctrl_wready_reg = 1'b0;
|
||||
logic s_axil_ctrl_bvalid_reg = 1'b0;
|
||||
/*
|
||||
* AXI4-lite slave interface
|
||||
*/
|
||||
.s_axil_wr(s_axil_ctrl_wr),
|
||||
.s_axil_rd(s_axil_ctrl_rd),
|
||||
|
||||
logic s_axil_ctrl_arready_reg = 1'b0;
|
||||
logic [AXIL_DATA_W-1:0] s_axil_ctrl_rdata_reg = '0;
|
||||
logic s_axil_ctrl_rvalid_reg = 1'b0;
|
||||
/*
|
||||
* AXI4-lite master interfaces
|
||||
*/
|
||||
.m_axil_wr(axil_ctrl),
|
||||
.m_axil_rd(axil_ctrl)
|
||||
);
|
||||
|
||||
assign s_axil_ctrl_wr.awready = s_axil_ctrl_awready_reg;
|
||||
assign s_axil_ctrl_wr.wready = s_axil_ctrl_wready_reg;
|
||||
assign s_axil_ctrl_wr.bresp = '0;
|
||||
assign s_axil_ctrl_wr.buser = '0;
|
||||
assign s_axil_ctrl_wr.bvalid = s_axil_ctrl_bvalid_reg;
|
||||
taxi_apb_if #(
|
||||
.DATA_W(32),
|
||||
.ADDR_W(15)
|
||||
)
|
||||
apb_dp_ctrl[2]();
|
||||
|
||||
assign s_axil_ctrl_rd.arready = s_axil_ctrl_arready_reg;
|
||||
assign s_axil_ctrl_rd.rdata = s_axil_ctrl_rdata_reg;
|
||||
assign s_axil_ctrl_rd.rresp = '0;
|
||||
assign s_axil_ctrl_rd.ruser = '0;
|
||||
assign s_axil_ctrl_rd.rvalid = s_axil_ctrl_rvalid_reg;
|
||||
taxi_apb_interconnect #(
|
||||
.M_CNT($size(apb_dp_ctrl)),
|
||||
.ADDR_W(s_apb_dp_ctrl.ADDR_W),
|
||||
.M_REGIONS(1),
|
||||
.M_BASE_ADDR('0),
|
||||
.M_ADDR_W({$size(apb_dp_ctrl){{1{32'd15}}}}),
|
||||
.M_SECURE({$size(apb_dp_ctrl){1'b0}})
|
||||
)
|
||||
port_dp_intercon_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
|
||||
logic s_apb_dp_ctrl_pready_reg = 1'b0;
|
||||
logic [AXIL_DATA_W-1:0] s_apb_dp_ctrl_prdata_reg = '0;
|
||||
/*
|
||||
* APB slave interface
|
||||
*/
|
||||
.s_apb(s_apb_dp_ctrl),
|
||||
|
||||
assign s_apb_dp_ctrl.pready = s_apb_dp_ctrl_pready_reg;
|
||||
assign s_apb_dp_ctrl.prdata = s_apb_dp_ctrl_prdata_reg;
|
||||
assign s_apb_dp_ctrl.pslverr = 1'b0;
|
||||
assign s_apb_dp_ctrl.pruser = '0;
|
||||
assign s_apb_dp_ctrl.pbuser = '0;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
s_axil_ctrl_awready_reg <= 1'b0;
|
||||
s_axil_ctrl_wready_reg <= 1'b0;
|
||||
s_axil_ctrl_bvalid_reg <= s_axil_ctrl_bvalid_reg && !s_axil_ctrl_wr.bready;
|
||||
|
||||
s_axil_ctrl_arready_reg <= 1'b0;
|
||||
s_axil_ctrl_rvalid_reg <= s_axil_ctrl_rvalid_reg && !s_axil_ctrl_rd.rready;
|
||||
|
||||
s_apb_dp_ctrl_pready_reg <= 1'b0;
|
||||
|
||||
if (s_axil_ctrl_wr.awvalid && s_axil_ctrl_wr.wvalid && !s_axil_ctrl_bvalid_reg) begin
|
||||
s_axil_ctrl_awready_reg <= 1'b1;
|
||||
s_axil_ctrl_wready_reg <= 1'b1;
|
||||
s_axil_ctrl_bvalid_reg <= 1'b1;
|
||||
|
||||
case ({s_axil_ctrl_wr.awaddr[15:2], 2'b00})
|
||||
16'h0100: begin
|
||||
txq_en_reg <= s_axil_ctrl_wr.wdata[0];
|
||||
txq_size_reg <= s_axil_ctrl_wr.wdata[19:16];
|
||||
end
|
||||
16'h0104: txq_prod_reg <= s_axil_ctrl_wr.wdata[15:0];
|
||||
16'h0108: txq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata;
|
||||
16'h010c: txq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata;
|
||||
|
||||
16'h0200: begin
|
||||
rxq_en_reg <= s_axil_ctrl_wr.wdata[0];
|
||||
rxq_size_reg <= s_axil_ctrl_wr.wdata[19:16];
|
||||
end
|
||||
16'h0204: rxq_prod_reg <= s_axil_ctrl_wr.wdata[15:0];
|
||||
16'h0208: rxq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata;
|
||||
16'h020c: rxq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata;
|
||||
|
||||
16'h0300: begin
|
||||
txcq_en_reg <= s_axil_ctrl_wr.wdata[0];
|
||||
txcq_size_reg <= s_axil_ctrl_wr.wdata[19:16];
|
||||
end
|
||||
16'h0308: txcq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata;
|
||||
16'h030c: txcq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata;
|
||||
|
||||
16'h0400: begin
|
||||
rxcq_en_reg <= s_axil_ctrl_wr.wdata[0];
|
||||
rxcq_size_reg <= s_axil_ctrl_wr.wdata[19:16];
|
||||
end
|
||||
16'h0408: rxcq_base_addr_reg[31:0] <= s_axil_ctrl_wr.wdata;
|
||||
16'h040c: rxcq_base_addr_reg[63:32] <= s_axil_ctrl_wr.wdata;
|
||||
default: begin end
|
||||
endcase
|
||||
end
|
||||
|
||||
if (s_axil_ctrl_rd.arvalid && !s_axil_ctrl_rvalid_reg) begin
|
||||
s_axil_ctrl_rdata_reg <= '0;
|
||||
|
||||
s_axil_ctrl_arready_reg <= 1'b1;
|
||||
s_axil_ctrl_rvalid_reg <= 1'b1;
|
||||
|
||||
case ({s_axil_ctrl_rd.araddr[15:2], 2'b00})
|
||||
16'h0100: begin
|
||||
s_axil_ctrl_rdata_reg[0] <= txq_en_reg;
|
||||
s_axil_ctrl_rdata_reg[19:16] <= txq_size_reg;
|
||||
end
|
||||
16'h0104: begin
|
||||
s_axil_ctrl_rdata_reg[15:0] <= txq_prod_reg;
|
||||
s_axil_ctrl_rdata_reg[31:16] <= txq_cons;
|
||||
end
|
||||
16'h0108: s_axil_ctrl_rdata_reg <= txq_base_addr_reg[31:0];
|
||||
16'h010c: s_axil_ctrl_rdata_reg <= txq_base_addr_reg[63:32];
|
||||
|
||||
16'h0200: begin
|
||||
s_axil_ctrl_rdata_reg[0] <= rxq_en_reg;
|
||||
s_axil_ctrl_rdata_reg[19:16] <= rxq_size_reg;
|
||||
end
|
||||
16'h0204: begin
|
||||
s_axil_ctrl_rdata_reg[15:0] <= rxq_prod_reg;
|
||||
s_axil_ctrl_rdata_reg[31:16] <= rxq_cons;
|
||||
end
|
||||
16'h0208: s_axil_ctrl_rdata_reg <= rxq_base_addr_reg[31:0];
|
||||
16'h020c: s_axil_ctrl_rdata_reg <= rxq_base_addr_reg[63:32];
|
||||
|
||||
16'h0300: begin
|
||||
s_axil_ctrl_rdata_reg[0] <= txcq_en_reg;
|
||||
s_axil_ctrl_rdata_reg[19:16] <= txcq_size_reg;
|
||||
end
|
||||
16'h0304: s_axil_ctrl_rdata_reg[15:0] <= txcq_prod;
|
||||
16'h0308: s_axil_ctrl_rdata_reg <= txcq_base_addr_reg[31:0];
|
||||
16'h030c: s_axil_ctrl_rdata_reg <= txcq_base_addr_reg[63:32];
|
||||
|
||||
16'h0400: begin
|
||||
s_axil_ctrl_rdata_reg[0] <= rxcq_en_reg;
|
||||
s_axil_ctrl_rdata_reg[19:16] <= rxcq_size_reg;
|
||||
end
|
||||
16'h0404: s_axil_ctrl_rdata_reg[15:0] <= rxcq_prod;
|
||||
16'h0408: s_axil_ctrl_rdata_reg <= rxcq_base_addr_reg[31:0];
|
||||
16'h040c: s_axil_ctrl_rdata_reg <= rxcq_base_addr_reg[63:32];
|
||||
default: begin end
|
||||
endcase
|
||||
end
|
||||
|
||||
if (s_apb_dp_ctrl.penable && s_apb_dp_ctrl.psel && !s_apb_dp_ctrl_pready_reg) begin
|
||||
s_apb_dp_ctrl_pready_reg <= 1'b1;
|
||||
s_apb_dp_ctrl_prdata_reg <= '0;
|
||||
|
||||
if (s_apb_dp_ctrl.pwrite) begin
|
||||
case ({s_apb_dp_ctrl.paddr[15:2], 2'b00})
|
||||
16'h0100: begin
|
||||
txq_en_reg <= s_apb_dp_ctrl.pwdata[0];
|
||||
txq_size_reg <= s_apb_dp_ctrl.pwdata[19:16];
|
||||
end
|
||||
16'h0104: txq_prod_reg <= s_apb_dp_ctrl.pwdata[15:0];
|
||||
16'h0108: txq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata;
|
||||
16'h010c: txq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata;
|
||||
|
||||
16'h0200: begin
|
||||
rxq_en_reg <= s_apb_dp_ctrl.pwdata[0];
|
||||
rxq_size_reg <= s_apb_dp_ctrl.pwdata[19:16];
|
||||
end
|
||||
16'h0204: rxq_prod_reg <= s_apb_dp_ctrl.pwdata[15:0];
|
||||
16'h0208: rxq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata;
|
||||
16'h020c: rxq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata;
|
||||
|
||||
16'h0300: begin
|
||||
txcq_en_reg <= s_apb_dp_ctrl.pwdata[0];
|
||||
txcq_size_reg <= s_apb_dp_ctrl.pwdata[19:16];
|
||||
end
|
||||
16'h0308: txcq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata;
|
||||
16'h030c: txcq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata;
|
||||
|
||||
16'h0400: begin
|
||||
rxcq_en_reg <= s_apb_dp_ctrl.pwdata[0];
|
||||
rxcq_size_reg <= s_apb_dp_ctrl.pwdata[19:16];
|
||||
end
|
||||
16'h0408: rxcq_base_addr_reg[31:0] <= s_apb_dp_ctrl.pwdata;
|
||||
16'h040c: rxcq_base_addr_reg[63:32] <= s_apb_dp_ctrl.pwdata;
|
||||
default: begin end
|
||||
endcase
|
||||
end
|
||||
|
||||
case ({s_apb_dp_ctrl.paddr[15:2], 2'b00})
|
||||
16'h0100: begin
|
||||
s_apb_dp_ctrl_prdata_reg[0] <= txq_en_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[19:16] <= txq_size_reg;
|
||||
end
|
||||
16'h0104: begin
|
||||
s_apb_dp_ctrl_prdata_reg[15:0] <= txq_prod_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[31:16] <= txq_cons;
|
||||
end
|
||||
16'h0108: s_apb_dp_ctrl_prdata_reg <= txq_base_addr_reg[31:0];
|
||||
16'h010c: s_apb_dp_ctrl_prdata_reg <= txq_base_addr_reg[63:32];
|
||||
|
||||
16'h0200: begin
|
||||
s_apb_dp_ctrl_prdata_reg[0] <= rxq_en_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[19:16] <= rxq_size_reg;
|
||||
end
|
||||
16'h0204: begin
|
||||
s_apb_dp_ctrl_prdata_reg[15:0] <= rxq_prod_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[31:16] <= rxq_cons;
|
||||
end
|
||||
16'h0208: s_apb_dp_ctrl_prdata_reg <= rxq_base_addr_reg[31:0];
|
||||
16'h020c: s_apb_dp_ctrl_prdata_reg <= rxq_base_addr_reg[63:32];
|
||||
|
||||
16'h0300: begin
|
||||
s_apb_dp_ctrl_prdata_reg[0] <= txcq_en_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[19:16] <= txcq_size_reg;
|
||||
end
|
||||
16'h0304: s_apb_dp_ctrl_prdata_reg[15:0] <= txcq_prod;
|
||||
16'h0308: s_apb_dp_ctrl_prdata_reg <= txcq_base_addr_reg[31:0];
|
||||
16'h030c: s_apb_dp_ctrl_prdata_reg <= txcq_base_addr_reg[63:32];
|
||||
|
||||
16'h0400: begin
|
||||
s_apb_dp_ctrl_prdata_reg[0] <= rxcq_en_reg;
|
||||
s_apb_dp_ctrl_prdata_reg[19:16] <= rxcq_size_reg;
|
||||
end
|
||||
16'h0404: s_apb_dp_ctrl_prdata_reg[15:0] <= rxcq_prod;
|
||||
16'h0408: s_apb_dp_ctrl_prdata_reg <= rxcq_base_addr_reg[31:0];
|
||||
16'h040c: s_apb_dp_ctrl_prdata_reg <= rxcq_base_addr_reg[63:32];
|
||||
default: begin end
|
||||
endcase
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
s_axil_ctrl_awready_reg <= 1'b0;
|
||||
s_axil_ctrl_wready_reg <= 1'b0;
|
||||
s_axil_ctrl_bvalid_reg <= 1'b0;
|
||||
|
||||
s_axil_ctrl_arready_reg <= 1'b0;
|
||||
s_axil_ctrl_rvalid_reg <= 1'b0;
|
||||
|
||||
s_apb_dp_ctrl_pready_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
/*
|
||||
* APB master interfaces
|
||||
*/
|
||||
.m_apb(apb_dp_ctrl)
|
||||
);
|
||||
|
||||
taxi_dma_desc_if #(
|
||||
.SRC_ADDR_W(dma_rd_desc_req.SRC_ADDR_W),
|
||||
@@ -429,32 +261,37 @@ wr_dma_mux_inst (
|
||||
.client_ram_rd(dma_ram_rd_int)
|
||||
);
|
||||
|
||||
// descriptor fetch
|
||||
wire [1:0] desc_req;
|
||||
|
||||
taxi_axis_if #(
|
||||
.DATA_W(16*8),
|
||||
.KEEP_EN(1),
|
||||
.LAST_EN(1),
|
||||
.ID_EN(0),
|
||||
.DEST_EN(1), // TODO
|
||||
.ID_EN(1),
|
||||
.ID_W(1),
|
||||
.DEST_EN(1),
|
||||
.DEST_W(8),
|
||||
.USER_EN(1),
|
||||
.USER_W(1)
|
||||
) axis_desc[2]();
|
||||
|
||||
taxi_axis_if #(
|
||||
.DATA_W(16*8),
|
||||
.KEEP_EN(1),
|
||||
.LAST_EN(1),
|
||||
.ID_EN(1), // TODO
|
||||
.DEST_EN(0),
|
||||
.USER_EN(0)
|
||||
) axis_cpl[2]();
|
||||
) axis_desc();
|
||||
|
||||
cndm_micro_desc_rd
|
||||
desc_rd_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
|
||||
/*
|
||||
* Control register interface
|
||||
*/
|
||||
.s_axil_ctrl_wr(axil_ctrl[0]),
|
||||
.s_axil_ctrl_rd(axil_ctrl[0]),
|
||||
|
||||
/*
|
||||
* Datapath control register interface
|
||||
*/
|
||||
.s_apb_dp_ctrl(apb_dp_ctrl[0]),
|
||||
|
||||
/*
|
||||
* DMA
|
||||
*/
|
||||
@@ -462,19 +299,92 @@ desc_rd_inst (
|
||||
.dma_rd_desc_sts(dma_rd_desc_int[0]),
|
||||
.dma_ram_wr(dma_ram_wr_int[0]),
|
||||
|
||||
.txq_en(txq_en_reg),
|
||||
.txq_size(txq_size_reg),
|
||||
.txq_base_addr(txq_base_addr_reg),
|
||||
.txq_prod(txq_prod_reg),
|
||||
.txq_cons(txq_cons),
|
||||
.rxq_en(rxq_en_reg),
|
||||
.rxq_size(rxq_size_reg),
|
||||
.rxq_base_addr(rxq_base_addr_reg),
|
||||
.rxq_prod(rxq_prod_reg),
|
||||
.rxq_cons(rxq_cons),
|
||||
|
||||
.desc_req(desc_req),
|
||||
.axis_desc(axis_desc)
|
||||
.m_axis_desc(axis_desc)
|
||||
);
|
||||
|
||||
// desc demux
|
||||
taxi_axis_if #(
|
||||
.DATA_W(axis_desc.DATA_W),
|
||||
.KEEP_EN(axis_desc.KEEP_EN),
|
||||
.KEEP_W(axis_desc.KEEP_W),
|
||||
.LAST_EN(axis_desc.LAST_EN),
|
||||
.ID_EN(axis_desc.ID_EN),
|
||||
.ID_W(axis_desc.ID_W),
|
||||
.DEST_EN(axis_desc.DEST_EN),
|
||||
.DEST_W(axis_desc.DEST_W),
|
||||
.USER_EN(axis_desc.USER_EN),
|
||||
.USER_W(axis_desc.USER_W)
|
||||
) axis_desc_txrx[2]();
|
||||
|
||||
taxi_axis_demux #(
|
||||
.M_COUNT(2),
|
||||
.TID_ROUTE(1)
|
||||
)
|
||||
desc_demux_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
|
||||
/*
|
||||
* AXI4-Stream input (sink)
|
||||
*/
|
||||
.s_axis(axis_desc),
|
||||
|
||||
/*
|
||||
* AXI4-Stream output (source)
|
||||
*/
|
||||
.m_axis(axis_desc_txrx),
|
||||
|
||||
/*
|
||||
* Control
|
||||
*/
|
||||
.enable(1'b1),
|
||||
.drop(1'b0),
|
||||
.select('0)
|
||||
);
|
||||
|
||||
// completion write
|
||||
taxi_axis_if #(
|
||||
.DATA_W(16*8),
|
||||
.KEEP_EN(1),
|
||||
.LAST_EN(1),
|
||||
.ID_EN(0),
|
||||
.DEST_EN(1),
|
||||
.DEST_W(8),
|
||||
.USER_EN(0)
|
||||
) axis_cpl();
|
||||
|
||||
taxi_axis_if #(
|
||||
.DATA_W(axis_cpl.DATA_W),
|
||||
.KEEP_EN(axis_cpl.KEEP_EN),
|
||||
.KEEP_W(axis_cpl.KEEP_W),
|
||||
.LAST_EN(axis_cpl.LAST_EN),
|
||||
.ID_EN(axis_cpl.ID_EN),
|
||||
.ID_W(axis_cpl.ID_W),
|
||||
.DEST_EN(axis_cpl.DEST_EN),
|
||||
.DEST_W(axis_cpl.DEST_W),
|
||||
.USER_EN(axis_cpl.USER_EN),
|
||||
.USER_W(axis_cpl.USER_W)
|
||||
) axis_cpl_txrx[2]();
|
||||
|
||||
taxi_axis_arb_mux #(
|
||||
.S_COUNT(2),
|
||||
.ARB_ROUND_ROBIN(1),
|
||||
.ARB_LSB_HIGH_PRIO(1)
|
||||
)
|
||||
cpl_mux_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
|
||||
/*
|
||||
* AXI4-Stream input (sink)
|
||||
*/
|
||||
.s_axis(axis_cpl_txrx),
|
||||
|
||||
/*
|
||||
* AXI4-Stream output (source)
|
||||
*/
|
||||
.m_axis(axis_cpl)
|
||||
);
|
||||
|
||||
cndm_micro_cpl_wr
|
||||
@@ -482,6 +392,17 @@ cpl_wr_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
|
||||
/*
|
||||
* Control register interface
|
||||
*/
|
||||
.s_axil_ctrl_wr(axil_ctrl[1]),
|
||||
.s_axil_ctrl_rd(axil_ctrl[1]),
|
||||
|
||||
/*
|
||||
* Datapath control register interface
|
||||
*/
|
||||
.s_apb_dp_ctrl(apb_dp_ctrl[1]),
|
||||
|
||||
/*
|
||||
* DMA
|
||||
*/
|
||||
@@ -489,19 +410,11 @@ cpl_wr_inst (
|
||||
.dma_wr_desc_sts(dma_wr_desc_int[0]),
|
||||
.dma_ram_rd(dma_ram_rd_int[0]),
|
||||
|
||||
.txcq_en(txcq_en_reg),
|
||||
.txcq_size(txcq_size_reg),
|
||||
.txcq_base_addr(txcq_base_addr_reg),
|
||||
.txcq_prod(txcq_prod),
|
||||
.rxcq_en(rxcq_en_reg),
|
||||
.rxcq_size(rxcq_size_reg),
|
||||
.rxcq_base_addr(rxcq_base_addr_reg),
|
||||
.rxcq_prod(rxcq_prod),
|
||||
|
||||
.axis_cpl(axis_cpl),
|
||||
.s_axis_cpl(axis_cpl),
|
||||
.irq(irq)
|
||||
);
|
||||
|
||||
// TX path
|
||||
taxi_axis_if #(
|
||||
.DATA_W(mac_axis_tx.DATA_W),
|
||||
.USER_EN(1),
|
||||
@@ -636,12 +549,13 @@ tx_inst (
|
||||
.dma_ram_wr(dma_ram_wr_int[1]),
|
||||
|
||||
.desc_req(desc_req[0]),
|
||||
.axis_desc(axis_desc[0]),
|
||||
.s_axis_desc(axis_desc_txrx[0]),
|
||||
.tx_data(mac_tx_int),
|
||||
.tx_cpl(mac_tx_cpl_int),
|
||||
.axis_cpl(axis_cpl[0])
|
||||
.m_axis_cpl(axis_cpl_txrx[0])
|
||||
);
|
||||
|
||||
// RX path
|
||||
taxi_axis_if #(
|
||||
.DATA_W(mac_axis_rx.DATA_W),
|
||||
.USER_EN(1),
|
||||
@@ -720,8 +634,8 @@ rx_inst (
|
||||
|
||||
.rx_data(mac_rx_int),
|
||||
.desc_req(desc_req[1]),
|
||||
.axis_desc(axis_desc[1]),
|
||||
.axis_cpl(axis_cpl[1])
|
||||
.s_axis_desc(axis_desc_txrx[1]),
|
||||
.m_axis_cpl(axis_cpl_txrx[1])
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -39,8 +39,8 @@ module cndm_micro_rx #(
|
||||
|
||||
taxi_axis_if.snk rx_data,
|
||||
output wire logic desc_req,
|
||||
taxi_axis_if.snk axis_desc,
|
||||
taxi_axis_if.src axis_cpl
|
||||
taxi_axis_if.snk s_axis_desc,
|
||||
taxi_axis_if.src m_axis_cpl
|
||||
);
|
||||
|
||||
localparam RAM_ADDR_W = 16;
|
||||
@@ -61,13 +61,14 @@ taxi_dma_desc_if #(
|
||||
.USER_W(rx_data.USER_W)
|
||||
) dma_desc();
|
||||
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 0,
|
||||
STATE_RX_DATA = 1,
|
||||
STATE_READ_DESC = 2,
|
||||
STATE_WRITE_DATA = 3;
|
||||
typedef enum logic [1:0] {
|
||||
STATE_IDLE,
|
||||
STATE_RX_DATA,
|
||||
STATE_READ_DESC,
|
||||
STATE_WRITE_DATA
|
||||
} state_t;
|
||||
|
||||
logic [2:0] state_reg = STATE_IDLE;
|
||||
state_t state_reg = STATE_IDLE;
|
||||
|
||||
logic desc_req_reg = 1'b0;
|
||||
|
||||
@@ -154,7 +155,7 @@ end
|
||||
always_ff @(posedge clk) begin
|
||||
desc_req_reg <= 1'b0;
|
||||
|
||||
axis_desc.tready <= 1'b0;
|
||||
s_axis_desc.tready <= 1'b0;
|
||||
|
||||
dma_wr_desc_req.req_src_sel <= '0;
|
||||
dma_wr_desc_req.req_src_asid <= '0;
|
||||
@@ -183,17 +184,16 @@ always_ff @(posedge clk) begin
|
||||
dma_desc.req_user <= '0;
|
||||
dma_desc.req_valid <= dma_desc.req_valid && !dma_desc.req_ready;
|
||||
|
||||
axis_cpl.tkeep <= '0;
|
||||
axis_cpl.tid <= '0;
|
||||
axis_cpl.tdest <= '0;
|
||||
axis_cpl.tuser <= '0;
|
||||
axis_cpl.tlast <= 1'b1;
|
||||
axis_cpl.tvalid <= axis_cpl.tvalid && !axis_cpl.tready;
|
||||
m_axis_cpl.tkeep <= '0;
|
||||
m_axis_cpl.tid <= '0;
|
||||
m_axis_cpl.tuser <= '0;
|
||||
m_axis_cpl.tlast <= 1'b1;
|
||||
m_axis_cpl.tvalid <= m_axis_cpl.tvalid && !m_axis_cpl.tready;
|
||||
|
||||
if (rx_ptp_ts_valid) begin
|
||||
axis_cpl.tdata[127:112] <= rx_ptp_ts[63:48]; // sec
|
||||
axis_cpl.tdata[95:64] <= rx_ptp_ts[47:16]; // ns
|
||||
axis_cpl.tdata[111:96] <= rx_ptp_ts[15:0]; // fns
|
||||
m_axis_cpl.tdata[127:112] <= rx_ptp_ts[63:48]; // sec
|
||||
m_axis_cpl.tdata[95:64] <= rx_ptp_ts[47:16]; // ns
|
||||
m_axis_cpl.tdata[111:96] <= rx_ptp_ts[15:0]; // fns
|
||||
end
|
||||
|
||||
case (state_reg)
|
||||
@@ -203,24 +203,26 @@ always_ff @(posedge clk) begin
|
||||
end
|
||||
STATE_RX_DATA: begin
|
||||
dma_wr_desc_req.req_len <= 20'(dma_desc.sts_len);
|
||||
axis_cpl.tdata[47:32] <= 16'(dma_desc.sts_len);
|
||||
m_axis_cpl.tdata[47:32] <= 16'(dma_desc.sts_len);
|
||||
if (dma_desc.sts_valid) begin
|
||||
desc_req_reg <= 1'b1;
|
||||
state_reg <= STATE_READ_DESC;
|
||||
end
|
||||
end
|
||||
STATE_READ_DESC: begin
|
||||
axis_desc.tready <= 1'b1;
|
||||
s_axis_desc.tready <= 1'b1;
|
||||
|
||||
dma_wr_desc_req.req_src_addr <= '0;
|
||||
dma_wr_desc_req.req_dst_addr <= axis_desc.tdata[127:64];
|
||||
dma_wr_desc_req.req_dst_addr <= s_axis_desc.tdata[127:64];
|
||||
|
||||
if (axis_desc.tvalid && axis_desc.tready) begin
|
||||
if (dma_wr_desc_req.req_len > 20'(axis_desc.tdata[47:32])) begin
|
||||
dma_wr_desc_req.req_len <= 20'(axis_desc.tdata[47:32]);
|
||||
m_axis_cpl.tdest <= s_axis_desc.tdest; // CQN
|
||||
|
||||
if (s_axis_desc.tvalid && s_axis_desc.tready) begin
|
||||
if (dma_wr_desc_req.req_len > 20'(s_axis_desc.tdata[47:32])) begin
|
||||
dma_wr_desc_req.req_len <= 20'(s_axis_desc.tdata[47:32]);
|
||||
end
|
||||
|
||||
if (axis_desc.tuser) begin
|
||||
if (s_axis_desc.tuser) begin
|
||||
// failed to read desc
|
||||
state_reg <= STATE_IDLE;
|
||||
end else begin
|
||||
@@ -231,7 +233,7 @@ always_ff @(posedge clk) begin
|
||||
end
|
||||
STATE_WRITE_DATA: begin
|
||||
if (dma_wr_desc_sts.sts_valid) begin
|
||||
axis_cpl.tvalid <= 1'b1;
|
||||
m_axis_cpl.tvalid <= 1'b1;
|
||||
state_reg <= STATE_IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
@@ -38,10 +38,10 @@ module cndm_micro_tx #(
|
||||
taxi_dma_ram_if.wr_slv dma_ram_wr,
|
||||
|
||||
output wire logic desc_req,
|
||||
taxi_axis_if.snk axis_desc,
|
||||
taxi_axis_if.snk s_axis_desc,
|
||||
taxi_axis_if.src tx_data,
|
||||
taxi_axis_if.snk tx_cpl,
|
||||
taxi_axis_if.src axis_cpl
|
||||
taxi_axis_if.src m_axis_cpl
|
||||
);
|
||||
|
||||
localparam RAM_ADDR_W = 16;
|
||||
@@ -62,13 +62,14 @@ taxi_dma_desc_if #(
|
||||
.USER_W(1)
|
||||
) dma_desc();
|
||||
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 0,
|
||||
STATE_READ_DESC = 1,
|
||||
STATE_READ_DATA = 2,
|
||||
STATE_TX_DATA = 3;
|
||||
typedef enum logic [1:0] {
|
||||
STATE_IDLE,
|
||||
STATE_READ_DESC,
|
||||
STATE_READ_DATA,
|
||||
STATE_TX_DATA
|
||||
} state_t;
|
||||
|
||||
logic [2:0] state_reg = STATE_IDLE;
|
||||
state_t state_reg = STATE_IDLE;
|
||||
|
||||
logic desc_req_reg = 1'b0;
|
||||
|
||||
@@ -139,7 +140,7 @@ end
|
||||
always_ff @(posedge clk) begin
|
||||
desc_req_reg <= 1'b0;
|
||||
|
||||
axis_desc.tready <= 1'b0;
|
||||
s_axis_desc.tready <= 1'b0;
|
||||
|
||||
dma_rd_desc_req.req_src_sel <= '0;
|
||||
dma_rd_desc_req.req_src_asid <= '0;
|
||||
@@ -166,12 +167,11 @@ always_ff @(posedge clk) begin
|
||||
dma_desc.req_user <= '0;
|
||||
dma_desc.req_valid <= dma_desc.req_valid && !dma_desc.req_ready;
|
||||
|
||||
axis_cpl.tkeep <= '0;
|
||||
axis_cpl.tid <= '0;
|
||||
axis_cpl.tdest <= '0;
|
||||
axis_cpl.tuser <= '0;
|
||||
axis_cpl.tlast <= 1'b1;
|
||||
axis_cpl.tvalid <= axis_cpl.tvalid && !axis_cpl.tready;
|
||||
m_axis_cpl.tkeep <= '0;
|
||||
m_axis_cpl.tid <= '0;
|
||||
m_axis_cpl.tuser <= '0;
|
||||
m_axis_cpl.tlast <= 1'b1;
|
||||
m_axis_cpl.tvalid <= m_axis_cpl.tvalid && !m_axis_cpl.tready;
|
||||
|
||||
case (state_reg)
|
||||
STATE_IDLE: begin
|
||||
@@ -179,19 +179,21 @@ always_ff @(posedge clk) begin
|
||||
state_reg <= STATE_READ_DESC;
|
||||
end
|
||||
STATE_READ_DESC: begin
|
||||
axis_desc.tready <= 1'b1;
|
||||
s_axis_desc.tready <= 1'b1;
|
||||
|
||||
dma_rd_desc_req.req_src_addr <= axis_desc.tdata[127:64];
|
||||
dma_rd_desc_req.req_src_addr <= s_axis_desc.tdata[127:64];
|
||||
dma_rd_desc_req.req_dst_addr <= '0;
|
||||
dma_rd_desc_req.req_len <= 20'(axis_desc.tdata[47:32]);
|
||||
dma_rd_desc_req.req_len <= 20'(s_axis_desc.tdata[47:32]);
|
||||
|
||||
dma_desc.req_src_addr <= '0;
|
||||
dma_desc.req_len <= axis_desc.tdata[47:32];
|
||||
dma_desc.req_len <= s_axis_desc.tdata[47:32];
|
||||
|
||||
axis_cpl.tdata[47:32] <= axis_desc.tdata[47:32];
|
||||
m_axis_cpl.tdata[47:32] <= s_axis_desc.tdata[47:32];
|
||||
|
||||
if (axis_desc.tvalid && axis_desc.tready) begin
|
||||
if (axis_desc.tuser) begin
|
||||
m_axis_cpl.tdest <= s_axis_desc.tdest; // CQN
|
||||
|
||||
if (s_axis_desc.tvalid && s_axis_desc.tready) begin
|
||||
if (s_axis_desc.tuser) begin
|
||||
// failed to read desc
|
||||
state_reg <= STATE_IDLE;
|
||||
end else begin
|
||||
@@ -207,11 +209,11 @@ always_ff @(posedge clk) begin
|
||||
end
|
||||
end
|
||||
STATE_TX_DATA: begin
|
||||
axis_cpl.tdata[127:112] <= tx_cpl_ptp_ts[63:48]; // sec
|
||||
axis_cpl.tdata[95:64] <= tx_cpl_ptp_ts[47:16]; // ns
|
||||
axis_cpl.tdata[111:96] <= tx_cpl_ptp_ts[15:0]; // fns
|
||||
m_axis_cpl.tdata[127:112] <= tx_cpl_ptp_ts[63:48]; // sec
|
||||
m_axis_cpl.tdata[95:64] <= tx_cpl_ptp_ts[47:16]; // ns
|
||||
m_axis_cpl.tdata[111:96] <= tx_cpl_ptp_ts[15:0]; // fns
|
||||
if (tx_cpl_valid) begin
|
||||
axis_cpl.tvalid <= 1'b1;
|
||||
m_axis_cpl.tvalid <= 1'b1;
|
||||
state_reg <= STATE_IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
@@ -57,165 +57,233 @@ CNDM_CMD_PTP_FLG_OFFSET_REL = 0x00000008
|
||||
CNDM_CMD_PTP_FLG_OFFSET_FNS = 0x00000010
|
||||
CNDM_CMD_PTP_FLG_SET_PERIOD = 0x00000080
|
||||
|
||||
class Port:
|
||||
def __init__(self, driver, index):
|
||||
|
||||
class Cq:
|
||||
def __init__(self, driver, port):
|
||||
self.driver = driver
|
||||
self.log = driver.log
|
||||
self.index = index
|
||||
self.hw_regs = driver.hw_regs
|
||||
|
||||
self.rxq_log_size = (256).bit_length()-1
|
||||
self.rxq_size = 2**self.rxq_log_size
|
||||
self.rxq_mask = self.rxq_size-1
|
||||
self.rxq = None
|
||||
self.rxq_prod = 0
|
||||
self.rxq_cons = 0
|
||||
self.rx_rqn = 0
|
||||
self.rxq_db_offs = 0
|
||||
self.port = port
|
||||
self.irqn = None
|
||||
|
||||
self.rx_info = [None] * self.rxq_size
|
||||
self.log_size = 0
|
||||
self.size = 0
|
||||
self.size_mask = 0
|
||||
self.stride = 0
|
||||
self.cqn = None
|
||||
self.enabled = False
|
||||
|
||||
self.rxcq_log_size = (256).bit_length()-1
|
||||
self.rxcq_size = 2**self.rxcq_log_size
|
||||
self.rxcq_mask = self.rxcq_size-1
|
||||
self.rxcq = None
|
||||
self.rxcq_prod = 0
|
||||
self.rxcq_cons = 0
|
||||
self.rx_cqn = 0
|
||||
self.buf_size = 0
|
||||
self.buf_region = None
|
||||
self.buf_dma = 0
|
||||
self.buf = None
|
||||
|
||||
self.txq_log_size = (256).bit_length()-1
|
||||
self.txq_size = 2**self.txq_log_size
|
||||
self.txq_mask = self.txq_size-1
|
||||
self.txq = None
|
||||
self.txq_prod = 0
|
||||
self.txq_cons = 0
|
||||
self.tx_sqn = 0
|
||||
self.txq_db_offs = 0
|
||||
self.eq = None
|
||||
|
||||
self.tx_info = [None] * self.txq_size
|
||||
self.src_ring = None
|
||||
self.handler = None
|
||||
|
||||
self.txcq_log_size = (256).bit_length()-1
|
||||
self.txcq_size = 2**self.txcq_log_size
|
||||
self.txcq_mask = self.txcq_size-1
|
||||
self.txcq = None
|
||||
self.txcq_prod = 0
|
||||
self.txcq_cons = 0
|
||||
self.tx_cqn = 0
|
||||
self.cons_ptr = None
|
||||
|
||||
self.rx_queue = Queue()
|
||||
self.hw_regs = self.driver.hw_regs
|
||||
|
||||
async def init(self):
|
||||
async def open(self, irqn, size):
|
||||
if self.cqn is not None:
|
||||
raise Exception("Already open")
|
||||
|
||||
self.rxcq = self.driver.pool.alloc_region(self.rxcq_size*16)
|
||||
addr = self.rxcq.get_absolute_address(0)
|
||||
self.irqn = irqn
|
||||
|
||||
self.log_size = size.bit_length() - 1
|
||||
self.size = 2**self.log_size
|
||||
self.size_mask = self.size-1
|
||||
self.stride = 16
|
||||
|
||||
self.buf_size = self.size*self.stride
|
||||
self.buf_region = self.driver.pool.alloc_region(self.buf_size)
|
||||
self.buf_dma = self.buf_region.get_absolute_address(0)
|
||||
self.buf = self.buf_region.mem
|
||||
|
||||
self.buf[0:self.buf_size] = b'\x00'*self.buf_size
|
||||
|
||||
self.cons_ptr = 0
|
||||
|
||||
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLQQLLLL",
|
||||
0, # rsvd
|
||||
CNDM_CMD_OP_CREATE_CQ, # opcode
|
||||
0x00000000, # flags
|
||||
self.index, # port
|
||||
self.port.index, # port
|
||||
0, # cqn
|
||||
0, # eqn
|
||||
self.irqn, # eqn
|
||||
0, # pd
|
||||
self.rxcq_log_size, # size
|
||||
self.log_size, # size
|
||||
0, # dboffs
|
||||
addr, # base addr
|
||||
self.buf_dma, # base addr
|
||||
0, # ptr2
|
||||
0, # prod_ptr
|
||||
0, # cons_ptr
|
||||
0, # rsvd
|
||||
0, # rsvd
|
||||
))
|
||||
print(rsp)
|
||||
|
||||
self.rxq = self.driver.pool.alloc_region(self.rxq_size*16)
|
||||
addr = self.rxq.get_absolute_address(0)
|
||||
rsp_unpacked = struct.unpack("<HHLLLLLLLQQLLLL", rsp)
|
||||
print(rsp_unpacked)
|
||||
self.cqn = rsp_unpacked[4]
|
||||
|
||||
self.log.info("Opened CQ %d", self.cqn)
|
||||
|
||||
self.enabled = True
|
||||
|
||||
async def close(self):
|
||||
if self.cqn is None:
|
||||
return
|
||||
|
||||
self.enabled = False
|
||||
|
||||
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLQQLLLL",
|
||||
0, # rsvd
|
||||
CNDM_CMD_OP_CREATE_RQ, # opcode
|
||||
CNDM_CMD_OP_DESTROY_CQ, # opcode
|
||||
0x00000000, # flags
|
||||
self.index, # port
|
||||
0, # rqn
|
||||
0, # cqn
|
||||
0, # pd
|
||||
self.rxq_log_size, # size
|
||||
0, # dboffs
|
||||
addr, # base addr
|
||||
0, # ptr2
|
||||
0, # prod_ptr
|
||||
0, # cons_ptr
|
||||
0, # rsvd
|
||||
0, # rsvd
|
||||
))
|
||||
print(rsp)
|
||||
|
||||
self.rxq_db_offs = struct.unpack_from("<L", rsp, 7*4)[0]
|
||||
|
||||
self.txcq = self.driver.pool.alloc_region(self.txcq_size*16)
|
||||
addr = self.txcq.get_absolute_address(0)
|
||||
|
||||
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLQQLLLL",
|
||||
0, # rsvd
|
||||
CNDM_CMD_OP_CREATE_CQ, # opcode
|
||||
0x00000000, # flags
|
||||
self.index, # port
|
||||
1, # cqn
|
||||
self.port.index, # port
|
||||
self.cqn, # cqn
|
||||
0, # eqn
|
||||
0, # pd
|
||||
self.txcq_log_size, # size
|
||||
0, # size
|
||||
0, # dboffs
|
||||
addr, # base addr
|
||||
0, # base addr
|
||||
0, # ptr2
|
||||
0, # prod_ptr
|
||||
0, # cons_ptr
|
||||
0, # rsvd
|
||||
0, # rsvd
|
||||
))
|
||||
print(rsp)
|
||||
|
||||
self.txq = self.driver.pool.alloc_region(self.txq_size*16)
|
||||
addr = self.txq.get_absolute_address(0)
|
||||
self.cqn = None
|
||||
|
||||
# TODO free buffer
|
||||
|
||||
|
||||
class Sq:
|
||||
def __init__(self, driver, port):
|
||||
self.driver = driver
|
||||
self.log = driver.log
|
||||
|
||||
self.port = port
|
||||
|
||||
self.log_size = 0
|
||||
self.size = 0
|
||||
self.size_mask = 0
|
||||
self.full_size = 0
|
||||
self.stride = 0
|
||||
self.sqn = None
|
||||
self.enabled = False
|
||||
|
||||
self.buf_size = 0
|
||||
self.buf_region = None
|
||||
self.buf_dma = 0
|
||||
self.buf = None
|
||||
|
||||
self.cq = None
|
||||
|
||||
self.prod_ptr = None
|
||||
self.cons_ptr = None
|
||||
|
||||
self.packets = 0
|
||||
self.bytes = 0
|
||||
|
||||
self.db_offset = None
|
||||
|
||||
self.hw_regs = self.driver.hw_regs
|
||||
|
||||
async def open(self, cq, size):
|
||||
if self.sqn is not None:
|
||||
raise Exception("Already open")
|
||||
|
||||
self.log_size = size.bit_length() - 1
|
||||
self.size = 2**self.log_size
|
||||
self.size_mask = self.size-1
|
||||
self.stride = 16
|
||||
|
||||
self.tx_info = [None]*self.size
|
||||
|
||||
self.buf_size = self.size*self.stride
|
||||
self.buf_region = self.driver.pool.alloc_region(self.buf_size)
|
||||
self.buf_dma = self.buf_region.get_absolute_address(0)
|
||||
self.buf = self.buf_region.mem
|
||||
|
||||
self.buf[0:self.buf_size] = b'\x00'*self.buf_size
|
||||
|
||||
self.prod_ptr = 0
|
||||
self.cons_ptr = 0
|
||||
|
||||
self.cq = cq
|
||||
self.cq.src_ring = self
|
||||
self.cq.handler = Sq.process_tx_cq
|
||||
|
||||
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLQQLLLL",
|
||||
0, # rsvd
|
||||
CNDM_CMD_OP_CREATE_SQ, # opcode
|
||||
0x00000000, # flags
|
||||
self.index, # port
|
||||
self.port.index, # port
|
||||
0, # sqn
|
||||
1, # cqn
|
||||
self.cq.cqn, # cqn
|
||||
0, # pd
|
||||
self.txq_log_size, # size
|
||||
self.log_size, # size
|
||||
0, # dboffs
|
||||
addr, # base addr
|
||||
self.buf_dma, # base addr
|
||||
0, # ptr2
|
||||
0, # prod_ptr
|
||||
0, # cons_ptr
|
||||
0, # rsvd
|
||||
0, # rsvd
|
||||
))
|
||||
print(rsp)
|
||||
|
||||
self.txq_db_offs = struct.unpack_from("<L", rsp, 7*4)[0]
|
||||
rsp_unpacked = struct.unpack("<HHLLLLLLLQQLLLL", rsp)
|
||||
print(rsp_unpacked)
|
||||
self.sqn = rsp_unpacked[4]
|
||||
self.db_offset = rsp_unpacked[8]
|
||||
|
||||
await self.refill_rx_buffers()
|
||||
self.log.info("Opened SQ %d", self.sqn)
|
||||
|
||||
self.enabled = True
|
||||
|
||||
async def close(self):
|
||||
if self.sqn is None:
|
||||
return
|
||||
|
||||
self.enabled = False
|
||||
|
||||
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLQQLLLL",
|
||||
0, # rsvd
|
||||
CNDM_CMD_OP_DESTROY_SQ, # opcode
|
||||
0x00000000, # flags
|
||||
self.port.index, # port
|
||||
self.sqn, # sqn
|
||||
0, # eqn
|
||||
0, # pd
|
||||
0, # size
|
||||
0, # dboffs
|
||||
0, # base addr
|
||||
0, # ptr2
|
||||
0, # prod_ptr
|
||||
0, # cons_ptr
|
||||
0, # rsvd
|
||||
0, # rsvd
|
||||
))
|
||||
|
||||
self.sqn = None
|
||||
|
||||
# TODO free buffer
|
||||
|
||||
async def start_xmit(self, data):
|
||||
headroom = 10
|
||||
tx_buf = self.driver.alloc_pkt()
|
||||
await tx_buf.write(headroom, data)
|
||||
index = self.txq_prod & self.txq_mask
|
||||
index = self.prod_ptr & self.size_mask
|
||||
ptr = tx_buf.get_absolute_address(0)
|
||||
struct.pack_into('<xxxxLQ', self.txq.mem, 16*index, len(data), ptr+headroom)
|
||||
struct.pack_into('<xxxxLQ', self.buf, 16*index, len(data), ptr+headroom)
|
||||
self.tx_info[index] = tx_buf
|
||||
self.txq_prod += 1
|
||||
await self.hw_regs.write_dword(self.txq_db_offs, self.txq_prod & 0xffff)
|
||||
|
||||
async def recv(self):
|
||||
return await self.rx_queue.get()
|
||||
|
||||
async def recv_nowait(self):
|
||||
return self.rx_queue.get_nowait()
|
||||
self.prod_ptr += 1
|
||||
await self.hw_regs.write_dword(self.db_offset, self.prod_ptr & 0xffff)
|
||||
|
||||
def free_tx_desc(self, index):
|
||||
pkt = self.tx_info[index]
|
||||
@@ -223,37 +291,156 @@ class Port:
|
||||
self.tx_info[index] = None
|
||||
|
||||
def free_tx_buf(self):
|
||||
while self.txq_cons != self.txq_prod:
|
||||
index = self.txq_cons & self.txq_mask
|
||||
while self.cons_ptr != self.txq_prod:
|
||||
index = self.cons_ptr & self.size_mask
|
||||
self.free_tx_desc(index)
|
||||
self.txq_cons += 1
|
||||
self.cons_ptr += 1
|
||||
|
||||
async def process_tx_cq(self):
|
||||
@staticmethod
|
||||
async def process_tx_cq(cq):
|
||||
sq = cq.src_ring
|
||||
|
||||
cq_cons_ptr = self.txcq_cons
|
||||
cons_ptr = self.txq_cons
|
||||
cq.log.info("Process CQ %d for SQ %d", cq.cqn, sq.sqn)
|
||||
|
||||
cq_cons_ptr = cq.cons_ptr
|
||||
cons_ptr = sq.cons_ptr
|
||||
|
||||
while True:
|
||||
cq_index = cq_cons_ptr & self.txcq_mask
|
||||
index = cons_ptr & self.txq_mask
|
||||
cq_index = cq_cons_ptr & cq.size_mask
|
||||
index = cons_ptr & sq.size_mask
|
||||
|
||||
cpl_data = struct.unpack_from("<LLLL", self.txcq.mem, cq_index*16)
|
||||
cpl_data = struct.unpack_from("<LLLL", cq.buf, cq_index*16)
|
||||
|
||||
self.log.info("TX CQ index %d data %s", cq_index, cpl_data)
|
||||
cq.log.info("TX CQ index %d data %s", cq_index, cpl_data)
|
||||
|
||||
if bool(cpl_data[-1] & 0x80000000) == bool(cq_cons_ptr & self.txcq_size):
|
||||
self.log.info("CQ empty")
|
||||
if bool(cpl_data[-1] & 0x80000000) == bool(cq_cons_ptr & cq.size):
|
||||
cq.log.info("CQ empty")
|
||||
break
|
||||
|
||||
pkt = self.tx_info[index]
|
||||
pkt = sq.tx_info[index]
|
||||
|
||||
self.free_tx_desc(index)
|
||||
sq.free_tx_desc(index)
|
||||
|
||||
cq_cons_ptr += 1
|
||||
cons_ptr += 1
|
||||
|
||||
self.txcq_cons = cq_cons_ptr
|
||||
self.txq_cons = cons_ptr
|
||||
cq.cons_ptr = cq_cons_ptr
|
||||
sq.cons_ptr = cons_ptr
|
||||
|
||||
|
||||
class Rq:
|
||||
def __init__(self, driver, port):
|
||||
self.driver = driver
|
||||
self.log = driver.log
|
||||
|
||||
self.port = port
|
||||
|
||||
self.log_size = 0
|
||||
self.size = 0
|
||||
self.size_mask = 0
|
||||
self.full_size = 0
|
||||
self.stride = 0
|
||||
self.rqn = None
|
||||
self.enabled = False
|
||||
|
||||
self.buf_size = 0
|
||||
self.buf_region = None
|
||||
self.buf_dma = 0
|
||||
self.buf = None
|
||||
|
||||
self.cq = None
|
||||
|
||||
self.prod_ptr = None
|
||||
self.cons_ptr = None
|
||||
|
||||
self.packets = 0
|
||||
self.bytes = 0
|
||||
|
||||
self.db_offset = None
|
||||
|
||||
self.hw_regs = self.driver.hw_regs
|
||||
|
||||
async def open(self, cq, size):
|
||||
if self.rqn is not None:
|
||||
raise Exception("Already open")
|
||||
|
||||
self.log_size = size.bit_length() - 1
|
||||
self.size = 2**self.log_size
|
||||
self.size_mask = self.size-1
|
||||
self.stride = 16
|
||||
|
||||
self.rx_info = [None]*self.size
|
||||
|
||||
self.buf_size = self.size*self.stride
|
||||
self.buf_region = self.driver.pool.alloc_region(self.buf_size)
|
||||
self.buf_dma = self.buf_region.get_absolute_address(0)
|
||||
self.buf = self.buf_region.mem
|
||||
|
||||
self.buf[0:self.buf_size] = b'\x00'*self.buf_size
|
||||
|
||||
self.prod_ptr = 0
|
||||
self.cons_ptr = 0
|
||||
|
||||
self.cq = cq
|
||||
self.cq.src_ring = self
|
||||
self.cq.handler = Rq.process_rx_cq
|
||||
|
||||
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLQQLLLL",
|
||||
0, # rsvd
|
||||
CNDM_CMD_OP_CREATE_RQ, # opcode
|
||||
0x00000000, # flags
|
||||
self.port.index, # port
|
||||
0, # rqn
|
||||
self.cq.cqn, # cqn
|
||||
0, # pd
|
||||
self.log_size, # size
|
||||
0, # dboffs
|
||||
self.buf_dma, # base addr
|
||||
0, # ptr2
|
||||
0, # prod_ptr
|
||||
0, # cons_ptr
|
||||
0, # rsvd
|
||||
0, # rsvd
|
||||
))
|
||||
|
||||
rsp_unpacked = struct.unpack("<HHLLLLLLLQQLLLL", rsp)
|
||||
print(rsp_unpacked)
|
||||
self.rqn = rsp_unpacked[4]
|
||||
self.db_offset = rsp_unpacked[8]
|
||||
|
||||
self.log.info("Opened RQ %d", self.rqn)
|
||||
|
||||
self.enabled = True
|
||||
|
||||
await self.refill_rx_buffers()
|
||||
|
||||
async def close(self):
|
||||
if self.rqn is None:
|
||||
return
|
||||
|
||||
self.enabled = False
|
||||
|
||||
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLQQLLLL",
|
||||
0, # rsvd
|
||||
CNDM_CMD_OP_DESTROY_RQ, # opcode
|
||||
0x00000000, # flags
|
||||
self.port.index, # port
|
||||
self.rqn, # rqn
|
||||
0, # eqn
|
||||
0, # pd
|
||||
0, # size
|
||||
0, # dboffs
|
||||
0, # base addr
|
||||
0, # ptr2
|
||||
0, # prod_ptr
|
||||
0, # cons_ptr
|
||||
0, # rsvd
|
||||
0, # rsvd
|
||||
))
|
||||
|
||||
self.rqn = None
|
||||
|
||||
# TODO free buffer
|
||||
|
||||
def free_rx_desc(self, index):
|
||||
pkt = self.rx_info[index]
|
||||
@@ -261,10 +448,10 @@ class Port:
|
||||
self.rx_info[index] = None
|
||||
|
||||
def free_rx_buf(self):
|
||||
while self.rxq_cons != self.rxq_prod:
|
||||
index = self.rxq_cons & self.rxq_mask
|
||||
while self.cons_ptr != self.prod_ptr:
|
||||
index = self.cons_ptr & self.size_mask
|
||||
self.free_rx_desc(index)
|
||||
self.rxq_cons += 1
|
||||
self.cons_ptr += 1
|
||||
|
||||
def prepare_rx_desc(self, index):
|
||||
pkt = self.driver.alloc_pkt()
|
||||
@@ -273,60 +460,103 @@ class Port:
|
||||
length = pkt.size
|
||||
ptr = pkt.get_absolute_address(0)
|
||||
|
||||
struct.pack_into('<xxxxLQ', self.rxq.mem, 16*index, length, ptr)
|
||||
struct.pack_into('<xxxxLQ', self.buf, 16*index, length, ptr)
|
||||
|
||||
async def refill_rx_buffers(self):
|
||||
missing = self.rxq_size - (self.rxq_prod - self.rxq_cons)
|
||||
missing = self.size - (self.prod_ptr - self.cons_ptr)
|
||||
|
||||
if missing < 8:
|
||||
return
|
||||
|
||||
for k in range(missing):
|
||||
self.prepare_rx_desc(self.rxq_prod & self.rxq_mask)
|
||||
self.rxq_prod += 1
|
||||
self.prepare_rx_desc(self.prod_ptr & self.size_mask)
|
||||
self.prod_ptr += 1
|
||||
|
||||
await self.hw_regs.write_dword(self.rxq_db_offs, self.rxq_prod & 0xffff)
|
||||
await self.hw_regs.write_dword(self.db_offset, self.prod_ptr & 0xffff)
|
||||
|
||||
async def process_rx_cq(self):
|
||||
@staticmethod
|
||||
async def process_rx_cq(cq):
|
||||
rq = cq.src_ring
|
||||
|
||||
cq_cons_ptr = self.rxcq_cons
|
||||
cons_ptr = self.rxq_cons
|
||||
cq.log.info("Process CQ %d for RQ %d", cq.cqn, rq.rqn)
|
||||
|
||||
cq_cons_ptr = cq.cons_ptr
|
||||
cons_ptr = rq.cons_ptr
|
||||
|
||||
while True:
|
||||
cq_index = cq_cons_ptr & self.rxcq_mask
|
||||
index = cons_ptr & self.rxq_mask
|
||||
cq_index = cq_cons_ptr & cq.size_mask
|
||||
index = cons_ptr & rq.size_mask
|
||||
|
||||
cpl_data = struct.unpack_from("<LLLL", self.rxcq.mem, cq_index*16)
|
||||
cpl_data = struct.unpack_from("<LLLL", cq.buf, cq_index*16)
|
||||
|
||||
self.log.info("RX CQ index %d data %s", cq_index, cpl_data)
|
||||
rq.log.info("RX CQ index %d data %s", cq_index, cpl_data)
|
||||
|
||||
if bool(cpl_data[-1] & 0x80000000) == bool(cq_cons_ptr & self.rxcq_size):
|
||||
self.log.info("CQ empty")
|
||||
if bool(cpl_data[-1] & 0x80000000) == bool(cq_cons_ptr & cq.size):
|
||||
rq.log.info("CQ empty")
|
||||
break
|
||||
|
||||
pkt = self.rx_info[index]
|
||||
pkt = rq.rx_info[index]
|
||||
length = cpl_data[1]
|
||||
|
||||
data = pkt[:length]
|
||||
|
||||
self.log.info("Packet: %s", data)
|
||||
rq.log.info("Packet: %s", data)
|
||||
|
||||
self.rx_queue.put_nowait(data)
|
||||
rq.port.rx_queue.put_nowait(data)
|
||||
|
||||
self.free_rx_desc(index)
|
||||
rq.free_rx_desc(index)
|
||||
|
||||
cq_cons_ptr += 1
|
||||
cons_ptr += 1
|
||||
|
||||
self.rxcq_cons = cq_cons_ptr
|
||||
self.rxq_cons = cons_ptr
|
||||
cq.cons_ptr = cq_cons_ptr
|
||||
rq.cons_ptr = cons_ptr
|
||||
|
||||
await self.refill_rx_buffers()
|
||||
await rq.refill_rx_buffers()
|
||||
|
||||
|
||||
class Port:
|
||||
def __init__(self, driver, index):
|
||||
self.driver = driver
|
||||
self.log = driver.log
|
||||
self.index = index
|
||||
self.hw_regs = driver.hw_regs
|
||||
|
||||
self.rxq = None
|
||||
self.rxcq = None
|
||||
|
||||
self.txq = None
|
||||
self.txcq = None
|
||||
|
||||
self.rx_queue = Queue()
|
||||
|
||||
async def init(self):
|
||||
|
||||
self.rxcq = Cq(self.driver, self)
|
||||
await self.rxcq.open(self.index, 256)
|
||||
|
||||
self.rxq = Rq(self.driver, self)
|
||||
await self.rxq.open(self.rxcq, 256)
|
||||
|
||||
self.txcq = Cq(self.driver, self)
|
||||
await self.txcq.open(self.index, 256)
|
||||
|
||||
self.txq = Sq(self.driver, self)
|
||||
await self.txq.open(self.txcq, 256)
|
||||
|
||||
async def start_xmit(self, data):
|
||||
await self.txq.start_xmit(data)
|
||||
|
||||
async def recv(self):
|
||||
return await self.rx_queue.get()
|
||||
|
||||
async def recv_nowait(self):
|
||||
return self.rx_queue.get_nowait()
|
||||
|
||||
async def interrupt_handler(self):
|
||||
self.log.info("Interrupt")
|
||||
await self.process_rx_cq()
|
||||
await self.process_tx_cq()
|
||||
await self.rxcq.handler(self.rxcq)
|
||||
await self.txcq.handler(self.txcq)
|
||||
|
||||
|
||||
class Driver:
|
||||
|
||||
@@ -66,12 +66,13 @@ taxi_axis_if #(
|
||||
) cpl_comb();
|
||||
|
||||
// Completion write control state machine
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 0,
|
||||
STATE_RX_CPL = 1,
|
||||
STATE_WRITE_DATA = 2;
|
||||
typedef enum logic [1:0] {
|
||||
STATE_IDLE,
|
||||
STATE_RX_CPL,
|
||||
STATE_WRITE_DATA
|
||||
} state_t;
|
||||
|
||||
logic [2:0] state_reg = STATE_IDLE;
|
||||
state_t state_reg = STATE_IDLE;
|
||||
|
||||
logic [15:0] txcq_prod_ptr_reg = '0;
|
||||
logic [15:0] rxcq_prod_ptr_reg = '0;
|
||||
|
||||
@@ -69,13 +69,14 @@ taxi_dma_desc_if #(
|
||||
) dma_desc();
|
||||
|
||||
// Descriptor read control state machine
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 0,
|
||||
STATE_READ_DESC = 1,
|
||||
STATE_READ_DATA = 2,
|
||||
STATE_TX_DESC = 3;
|
||||
typedef enum logic [1:0] {
|
||||
STATE_IDLE,
|
||||
STATE_READ_DESC,
|
||||
STATE_READ_DATA,
|
||||
STATE_TX_DESC
|
||||
} state_t;
|
||||
|
||||
logic [2:0] state_reg = STATE_IDLE;
|
||||
state_t state_reg = STATE_IDLE;
|
||||
|
||||
logic [1:0] desc_req_reg = '0;
|
||||
|
||||
|
||||
@@ -64,13 +64,14 @@ taxi_dma_desc_if #(
|
||||
) dma_desc();
|
||||
|
||||
// Receive datapath control state machine
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 0,
|
||||
STATE_RX_DATA = 1,
|
||||
STATE_READ_DESC = 2,
|
||||
STATE_WRITE_DATA = 3;
|
||||
typedef enum logic [1:0] {
|
||||
STATE_IDLE,
|
||||
STATE_RX_DATA,
|
||||
STATE_READ_DESC,
|
||||
STATE_WRITE_DATA
|
||||
} state_t;
|
||||
|
||||
logic [2:0] state_reg = STATE_IDLE;
|
||||
state_t state_reg = STATE_IDLE;
|
||||
|
||||
logic desc_req_reg = 1'b0;
|
||||
|
||||
|
||||
@@ -64,13 +64,14 @@ taxi_dma_desc_if #(
|
||||
) dma_desc();
|
||||
|
||||
// Transmit datapath control state machine
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 0,
|
||||
STATE_READ_DESC = 1,
|
||||
STATE_READ_DATA = 2,
|
||||
STATE_TX_DATA = 3;
|
||||
typedef enum logic [1:0] {
|
||||
STATE_IDLE,
|
||||
STATE_READ_DESC,
|
||||
STATE_READ_DATA,
|
||||
STATE_TX_DATA
|
||||
} state_t;
|
||||
|
||||
logic [2:0] state_reg = STATE_IDLE;
|
||||
state_t state_reg = STATE_IDLE;
|
||||
|
||||
logic desc_req_reg = 1'b0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user