mirror of
https://github.com/fpganinja/taxi.git
synced 2026-04-09 05:18:44 -07:00
Compare commits
7 Commits
50ba1d4c89
...
962950a1e3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
962950a1e3 | ||
|
|
d7eb1b21a2 | ||
|
|
c7279a1ea2 | ||
|
|
ed61857bc3 | ||
|
|
2ea3c204de | ||
|
|
c37d967de9 | ||
|
|
e514869d70 |
@@ -12,6 +12,7 @@ cndm-y += cndm_dev.o
|
|||||||
cndm-y += cndm_netdev.o
|
cndm-y += cndm_netdev.o
|
||||||
cndm-y += cndm_ethtool.o
|
cndm-y += cndm_ethtool.o
|
||||||
cndm-y += cndm_ptp.o
|
cndm-y += cndm_ptp.o
|
||||||
|
cndm-y += cndm_eq.o
|
||||||
cndm-y += cndm_cq.o
|
cndm-y += cndm_cq.o
|
||||||
cndm-y += cndm_sq.o
|
cndm-y += cndm_sq.o
|
||||||
cndm-y += cndm_rq.o
|
cndm-y += cndm_rq.o
|
||||||
|
|||||||
@@ -173,6 +173,9 @@ struct cndm_cq {
|
|||||||
int enabled;
|
int enabled;
|
||||||
|
|
||||||
struct cndm_ring *src_ring;
|
struct cndm_ring *src_ring;
|
||||||
|
struct cndm_eq *eq;
|
||||||
|
struct cndm_irq *irq;
|
||||||
|
struct notifier_block irq_nb;
|
||||||
|
|
||||||
void (*handler)(struct cndm_cq *cq);
|
void (*handler)(struct cndm_cq *cq);
|
||||||
|
|
||||||
@@ -180,6 +183,35 @@ struct cndm_cq {
|
|||||||
u8 __iomem *db_addr;
|
u8 __iomem *db_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cndm_eq {
|
||||||
|
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;
|
||||||
|
int eqn;
|
||||||
|
int enabled;
|
||||||
|
|
||||||
|
struct cndm_irq *irq;
|
||||||
|
struct notifier_block irq_nb;
|
||||||
|
|
||||||
|
void (*handler)(struct cndm_eq *eq);
|
||||||
|
|
||||||
|
spinlock_t table_lock;
|
||||||
|
struct radix_tree_root cq_table;
|
||||||
|
|
||||||
|
u32 db_offset;
|
||||||
|
u8 __iomem *db_addr;
|
||||||
|
};
|
||||||
|
|
||||||
struct cndm_priv {
|
struct cndm_priv {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct net_device *ndev;
|
struct net_device *ndev;
|
||||||
@@ -190,14 +222,13 @@ struct cndm_priv {
|
|||||||
|
|
||||||
void __iomem *hw_addr;
|
void __iomem *hw_addr;
|
||||||
|
|
||||||
struct cndm_irq *irq;
|
|
||||||
struct notifier_block irq_nb;
|
|
||||||
|
|
||||||
struct hwtstamp_config hwts_config;
|
struct hwtstamp_config hwts_config;
|
||||||
|
|
||||||
int rxq_count;
|
int rxq_count;
|
||||||
int txq_count;
|
int txq_count;
|
||||||
|
|
||||||
|
struct cndm_eq *eq;
|
||||||
|
|
||||||
struct cndm_ring *txq;
|
struct cndm_ring *txq;
|
||||||
struct cndm_ring *rxq;
|
struct cndm_ring *rxq;
|
||||||
};
|
};
|
||||||
@@ -230,17 +261,32 @@ 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_register_phc(struct cndm_dev *cdev);
|
||||||
void cndm_unregister_phc(struct cndm_dev *cdev);
|
void cndm_unregister_phc(struct cndm_dev *cdev);
|
||||||
|
|
||||||
|
// cndm_eq.c
|
||||||
|
struct cndm_eq *cndm_create_eq(struct cndm_priv *priv);
|
||||||
|
void cndm_destroy_eq(struct cndm_eq *eq);
|
||||||
|
int cndm_open_eq(struct cndm_eq *eq, struct cndm_irq *irq, int size);
|
||||||
|
void cndm_close_eq(struct cndm_eq *eq);
|
||||||
|
int cndm_eq_attach_cq(struct cndm_eq *eq, struct cndm_cq *cq);
|
||||||
|
void cndm_eq_detach_cq(struct cndm_eq *eq, struct cndm_cq *cq);
|
||||||
|
void cndm_eq_write_cons_ptr(const struct cndm_eq *eq);
|
||||||
|
void cndm_eq_write_cons_ptr_arm(const struct cndm_eq *eq);
|
||||||
|
|
||||||
// cndm_cq.c
|
// cndm_cq.c
|
||||||
struct cndm_cq *cndm_create_cq(struct cndm_priv *priv);
|
struct cndm_cq *cndm_create_cq(struct cndm_priv *priv);
|
||||||
void cndm_destroy_cq(struct cndm_cq *cq);
|
void cndm_destroy_cq(struct cndm_cq *cq);
|
||||||
int cndm_open_cq(struct cndm_cq *cq, int irqn, int size);
|
int cndm_open_cq(struct cndm_cq *cq, struct cndm_eq *eq, struct cndm_irq *irq, int size);
|
||||||
void cndm_close_cq(struct cndm_cq *cq);
|
void cndm_close_cq(struct cndm_cq *cq);
|
||||||
|
void cndm_cq_write_cons_ptr(const struct cndm_cq *cq);
|
||||||
|
void cndm_cq_write_cons_ptr_arm(const struct cndm_cq *cq);
|
||||||
|
|
||||||
// cndm_sq.c
|
// cndm_sq.c
|
||||||
struct cndm_ring *cndm_create_sq(struct cndm_priv *priv);
|
struct cndm_ring *cndm_create_sq(struct cndm_priv *priv);
|
||||||
void cndm_destroy_sq(struct cndm_ring *sq);
|
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);
|
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);
|
void cndm_close_sq(struct cndm_ring *sq);
|
||||||
|
bool cndm_is_sq_ring_empty(const struct cndm_ring *sq);
|
||||||
|
bool cndm_is_sq_ring_full(const struct cndm_ring *sq);
|
||||||
|
void cndm_sq_write_prod_ptr(const struct cndm_ring *sq);
|
||||||
int cndm_free_tx_buf(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_poll_tx_cq(struct napi_struct *napi, int budget);
|
||||||
int cndm_start_xmit(struct sk_buff *skb, struct net_device *ndev);
|
int cndm_start_xmit(struct sk_buff *skb, struct net_device *ndev);
|
||||||
@@ -250,6 +296,9 @@ struct cndm_ring *cndm_create_rq(struct cndm_priv *priv);
|
|||||||
void cndm_destroy_rq(struct cndm_ring *rq);
|
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);
|
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);
|
void cndm_close_rq(struct cndm_ring *rq);
|
||||||
|
bool cndm_is_rq_ring_empty(const struct cndm_ring *rq);
|
||||||
|
bool cndm_is_rq_ring_full(const struct cndm_ring *rq);
|
||||||
|
void cndm_rq_write_prod_ptr(const struct cndm_ring *rq);
|
||||||
int cndm_free_rx_buf(struct cndm_ring *rq);
|
int cndm_free_rx_buf(struct cndm_ring *rq);
|
||||||
int cndm_refill_rx_buffers(struct cndm_ring *rq);
|
int cndm_refill_rx_buffers(struct cndm_ring *rq);
|
||||||
int cndm_poll_rx_cq(struct napi_struct *napi, int budget);
|
int cndm_poll_rx_cq(struct napi_struct *napi, int budget);
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ Authors:
|
|||||||
|
|
||||||
#include "cndm.h"
|
#include "cndm.h"
|
||||||
|
|
||||||
|
static int cndm_cq_int(struct notifier_block *nb, unsigned long action, void *data);
|
||||||
|
|
||||||
struct cndm_cq *cndm_create_cq(struct cndm_priv *priv)
|
struct cndm_cq *cndm_create_cq(struct cndm_priv *priv)
|
||||||
{
|
{
|
||||||
struct cndm_cq *cq;
|
struct cndm_cq *cq;
|
||||||
@@ -25,6 +27,8 @@ struct cndm_cq *cndm_create_cq(struct cndm_priv *priv)
|
|||||||
cq->cqn = -1;
|
cq->cqn = -1;
|
||||||
cq->enabled = 0;
|
cq->enabled = 0;
|
||||||
|
|
||||||
|
cq->irq_nb.notifier_call = cndm_cq_int;
|
||||||
|
|
||||||
cq->cons_ptr = 0;
|
cq->cons_ptr = 0;
|
||||||
|
|
||||||
cq->db_offset = 0;
|
cq->db_offset = 0;
|
||||||
@@ -40,14 +44,15 @@ void cndm_destroy_cq(struct cndm_cq *cq)
|
|||||||
kfree(cq);
|
kfree(cq);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cndm_open_cq(struct cndm_cq *cq, int irqn, int size)
|
int cndm_open_cq(struct cndm_cq *cq, struct cndm_eq *eq, struct cndm_irq *irq, int size)
|
||||||
{
|
{
|
||||||
|
u32 dqn;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
struct cndm_cmd_queue cmd;
|
struct cndm_cmd_queue cmd;
|
||||||
struct cndm_cmd_queue rsp;
|
struct cndm_cmd_queue rsp;
|
||||||
|
|
||||||
if (cq->enabled || cq->buf)
|
if (cq->enabled || cq->buf || (!irq && !eq))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
cq->size = roundup_pow_of_two(size);
|
cq->size = roundup_pow_of_two(size);
|
||||||
@@ -59,6 +64,19 @@ int cndm_open_cq(struct cndm_cq *cq, int irqn, int size)
|
|||||||
if (!cq->buf)
|
if (!cq->buf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
// can use either EQ or IRQ, but prefer EQ if both are specified
|
||||||
|
if (eq) {
|
||||||
|
cq->eq = eq;
|
||||||
|
dqn = eq->eqn;
|
||||||
|
} else if (irq) {
|
||||||
|
ret = atomic_notifier_chain_register(&irq->nh, &cq->irq_nb);
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
cq->irq = irq;
|
||||||
|
dqn = irq->index | 0x80000000;
|
||||||
|
}
|
||||||
|
|
||||||
cq->cons_ptr = 0;
|
cq->cons_ptr = 0;
|
||||||
|
|
||||||
// clear all phase tag bits
|
// clear all phase tag bits
|
||||||
@@ -68,7 +86,7 @@ int cndm_open_cq(struct cndm_cq *cq, int irqn, int size)
|
|||||||
cmd.flags = 0x00000000;
|
cmd.flags = 0x00000000;
|
||||||
cmd.port = cq->priv->ndev->dev_port;
|
cmd.port = cq->priv->ndev->dev_port;
|
||||||
cmd.qn = 0;
|
cmd.qn = 0;
|
||||||
cmd.qn2 = irqn; // TODO
|
cmd.qn2 = dqn;
|
||||||
cmd.pd = 0;
|
cmd.pd = 0;
|
||||||
cmd.size = ilog2(cq->size);
|
cmd.size = ilog2(cq->size);
|
||||||
cmd.dboffs = 0;
|
cmd.dboffs = 0;
|
||||||
@@ -87,8 +105,14 @@ int cndm_open_cq(struct cndm_cq *cq, int irqn, int size)
|
|||||||
cq->db_offset = rsp.dboffs;
|
cq->db_offset = rsp.dboffs;
|
||||||
cq->db_addr = cq->cdev->hw_addr + rsp.dboffs;
|
cq->db_addr = cq->cdev->hw_addr + rsp.dboffs;
|
||||||
|
|
||||||
|
if (eq) {
|
||||||
|
cndm_eq_attach_cq(eq, cq);
|
||||||
|
}
|
||||||
|
|
||||||
cq->enabled = 1;
|
cq->enabled = 1;
|
||||||
|
|
||||||
|
cndm_cq_write_cons_ptr_arm(cq);
|
||||||
|
|
||||||
netdev_dbg(cq->priv->ndev, "Opened CQ %d", cq->cqn);
|
netdev_dbg(cq->priv->ndev, "Opened CQ %d", cq->cqn);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -119,9 +143,39 @@ void cndm_close_cq(struct cndm_cq *cq)
|
|||||||
cq->db_addr = NULL;
|
cq->db_addr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cq->eq) {
|
||||||
|
cndm_eq_detach_cq(cq->eq, cq);
|
||||||
|
cq->eq = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cq->irq) {
|
||||||
|
atomic_notifier_chain_unregister(&cq->irq->nh, &cq->irq_nb);
|
||||||
|
cq->irq = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (cq->buf) {
|
if (cq->buf) {
|
||||||
dma_free_coherent(cq->dev, cq->buf_size, cq->buf, cq->buf_dma_addr);
|
dma_free_coherent(cq->dev, cq->buf_size, cq->buf, cq->buf_dma_addr);
|
||||||
cq->buf = NULL;
|
cq->buf = NULL;
|
||||||
cq->buf_dma_addr = 0;
|
cq->buf_dma_addr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cndm_cq_write_cons_ptr(const struct cndm_cq *cq)
|
||||||
|
{
|
||||||
|
iowrite32(cq->cons_ptr & 0xffff, cq->db_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cndm_cq_write_cons_ptr_arm(const struct cndm_cq *cq)
|
||||||
|
{
|
||||||
|
iowrite32((cq->cons_ptr & 0xffff) | 0x80000000, cq->db_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cndm_cq_int(struct notifier_block *nb, unsigned long action, void *data)
|
||||||
|
{
|
||||||
|
struct cndm_cq *cq = container_of(nb, struct cndm_cq, irq_nb);
|
||||||
|
|
||||||
|
if (likely(cq->handler))
|
||||||
|
cq->handler(cq);
|
||||||
|
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|||||||
@@ -202,14 +202,10 @@ struct cndm_cpl {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct cndm_event {
|
struct cndm_event {
|
||||||
|
__le16 rsvd0;
|
||||||
__le16 type;
|
__le16 type;
|
||||||
__le16 source;
|
__le32 source;
|
||||||
__le32 rsvd0;
|
|
||||||
__le32 rsvd1;
|
__le32 rsvd1;
|
||||||
__le32 rsvd2;
|
|
||||||
__le32 rsvd3;
|
|
||||||
__le32 rsvd4;
|
|
||||||
__le32 rsvd5;
|
|
||||||
__le32 phase;
|
__le32 phase;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ static int cndm_open(struct net_device *ndev)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = cndm_open_cq(cq, 0, 256);
|
ret = cndm_open_cq(cq, priv->eq, &priv->cdev->irq[0], 256);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
cndm_destroy_cq(cq);
|
cndm_destroy_cq(cq);
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -75,7 +75,7 @@ static int cndm_open(struct net_device *ndev)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = cndm_open_cq(cq, 0, 256);
|
ret = cndm_open_cq(cq, priv->eq, &priv->cdev->irq[0], 256);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
cndm_destroy_cq(cq);
|
cndm_destroy_cq(cq);
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -278,20 +278,6 @@ static const struct net_device_ops cndm_netdev_ops = {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static int cndm_netdev_irq(struct notifier_block *nb, unsigned long action, void *data)
|
|
||||||
{
|
|
||||||
struct cndm_priv *priv = container_of(nb, struct cndm_priv, irq_nb);
|
|
||||||
|
|
||||||
netdev_dbg(priv->ndev, "Interrupt");
|
|
||||||
|
|
||||||
if (priv->port_up) {
|
|
||||||
napi_schedule_irqoff(&priv->txq->cq->napi);
|
|
||||||
napi_schedule_irqoff(&priv->rxq->cq->napi);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NOTIFY_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port)
|
struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port)
|
||||||
{
|
{
|
||||||
struct device *dev = cdev->dev;
|
struct device *dev = cdev->dev;
|
||||||
@@ -340,6 +326,19 @@ struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port)
|
|||||||
ndev->min_mtu = ETH_MIN_MTU;
|
ndev->min_mtu = ETH_MIN_MTU;
|
||||||
ndev->max_mtu = 1500;
|
ndev->max_mtu = 1500;
|
||||||
|
|
||||||
|
priv->eq = cndm_create_eq(priv);
|
||||||
|
if (IS_ERR_OR_NULL(priv->eq)) {
|
||||||
|
ret = PTR_ERR(priv->eq);
|
||||||
|
priv->eq = NULL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cndm_open_eq(priv->eq, &priv->cdev->irq[0], 256);
|
||||||
|
if (ret) {
|
||||||
|
cndm_destroy_eq(priv->eq);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
netif_carrier_off(ndev);
|
netif_carrier_off(ndev);
|
||||||
|
|
||||||
ret = register_netdev(ndev);
|
ret = register_netdev(ndev);
|
||||||
@@ -350,14 +349,6 @@ struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port)
|
|||||||
|
|
||||||
priv->registered = 1;
|
priv->registered = 1;
|
||||||
|
|
||||||
priv->irq_nb.notifier_call = cndm_netdev_irq;
|
|
||||||
priv->irq = &cdev->irq[port % cdev->irq_count];
|
|
||||||
ret = atomic_notifier_chain_register(&priv->irq->nh, &priv->irq_nb);
|
|
||||||
if (ret) {
|
|
||||||
priv->irq = NULL;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ndev;
|
return ndev;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@@ -372,10 +363,8 @@ void cndm_destroy_netdev(struct net_device *ndev)
|
|||||||
if (priv->registered)
|
if (priv->registered)
|
||||||
unregister_netdev(ndev);
|
unregister_netdev(ndev);
|
||||||
|
|
||||||
if (priv->irq)
|
if (priv->eq)
|
||||||
atomic_notifier_chain_unregister(&priv->irq->nh, &priv->irq_nb);
|
cndm_destroy_eq(priv->eq);
|
||||||
|
|
||||||
priv->irq = NULL;
|
|
||||||
|
|
||||||
free_netdev(ndev);
|
free_netdev(ndev);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ Authors:
|
|||||||
|
|
||||||
#include "cndm.h"
|
#include "cndm.h"
|
||||||
|
|
||||||
|
static void cndm_rq_cq_handler(struct cndm_cq *cq);
|
||||||
|
|
||||||
struct cndm_ring *cndm_create_rq(struct cndm_priv *priv)
|
struct cndm_ring *cndm_create_rq(struct cndm_priv *priv)
|
||||||
{
|
{
|
||||||
struct cndm_ring *rq;
|
struct cndm_ring *rq;
|
||||||
@@ -69,7 +71,7 @@ int cndm_open_rq(struct cndm_ring *rq, struct cndm_priv *priv, struct cndm_cq *c
|
|||||||
rq->priv = priv;
|
rq->priv = priv;
|
||||||
rq->cq = cq;
|
rq->cq = cq;
|
||||||
cq->src_ring = rq;
|
cq->src_ring = rq;
|
||||||
// cq->handler = cndm_rx_irq;
|
cq->handler = cndm_rq_cq_handler;
|
||||||
|
|
||||||
rq->prod_ptr = 0;
|
rq->prod_ptr = 0;
|
||||||
rq->cons_ptr = 0;
|
rq->cons_ptr = 0;
|
||||||
@@ -163,6 +165,21 @@ void cndm_close_rq(struct cndm_ring *rq)
|
|||||||
rq->priv = NULL;
|
rq->priv = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cndm_is_rq_ring_empty(const struct cndm_ring *rq)
|
||||||
|
{
|
||||||
|
return rq->prod_ptr == rq->cons_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cndm_is_rq_ring_full(const struct cndm_ring *rq)
|
||||||
|
{
|
||||||
|
return (rq->prod_ptr - rq->cons_ptr) >= rq->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cndm_rq_write_prod_ptr(const struct cndm_ring *rq)
|
||||||
|
{
|
||||||
|
iowrite32(rq->prod_ptr & 0xffff, rq->db_addr);
|
||||||
|
}
|
||||||
|
|
||||||
static void cndm_free_rx_desc(struct cndm_ring *rq, int index)
|
static void cndm_free_rx_desc(struct cndm_ring *rq, int index)
|
||||||
{
|
{
|
||||||
struct cndm_priv *priv = rq->priv;
|
struct cndm_priv *priv = rq->priv;
|
||||||
@@ -185,7 +202,7 @@ int cndm_free_rx_buf(struct cndm_ring *rq)
|
|||||||
u32 index;
|
u32 index;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
|
|
||||||
while (rq->prod_ptr != rq->cons_ptr) {
|
while (!cndm_is_rq_ring_empty(rq)) {
|
||||||
index = rq->cons_ptr & rq->size_mask;
|
index = rq->cons_ptr & rq->size_mask;
|
||||||
cndm_free_rx_desc(rq, index);
|
cndm_free_rx_desc(rq, index);
|
||||||
rq->cons_ptr++;
|
rq->cons_ptr++;
|
||||||
@@ -247,7 +264,7 @@ int cndm_refill_rx_buffers(struct cndm_ring *rq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dma_wmb();
|
dma_wmb();
|
||||||
iowrite32(rq->prod_ptr & 0xffff, rq->db_addr);
|
cndm_rq_write_prod_ptr(rq);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -332,10 +349,16 @@ rx_drop:
|
|||||||
rq->cons_ptr = cons_ptr;
|
rq->cons_ptr = cons_ptr;
|
||||||
|
|
||||||
cndm_refill_rx_buffers(rq);
|
cndm_refill_rx_buffers(rq);
|
||||||
|
cndm_cq_write_cons_ptr(cq);
|
||||||
|
|
||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cndm_rq_cq_handler(struct cndm_cq *cq)
|
||||||
|
{
|
||||||
|
napi_schedule_irqoff(&cq->napi);
|
||||||
|
}
|
||||||
|
|
||||||
int cndm_poll_rx_cq(struct napi_struct *napi, int budget)
|
int cndm_poll_rx_cq(struct napi_struct *napi, int budget)
|
||||||
{
|
{
|
||||||
struct cndm_cq *cq = container_of(napi, struct cndm_cq, napi);
|
struct cndm_cq *cq = container_of(napi, struct cndm_cq, napi);
|
||||||
@@ -348,7 +371,7 @@ int cndm_poll_rx_cq(struct napi_struct *napi, int budget)
|
|||||||
|
|
||||||
napi_complete(napi);
|
napi_complete(napi);
|
||||||
|
|
||||||
// TODO re-enable interrupts
|
cndm_cq_write_cons_ptr_arm(cq);
|
||||||
|
|
||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ Authors:
|
|||||||
|
|
||||||
#include "cndm.h"
|
#include "cndm.h"
|
||||||
|
|
||||||
|
static void cndm_sq_cq_handler(struct cndm_cq *cq);
|
||||||
|
|
||||||
struct cndm_ring *cndm_create_sq(struct cndm_priv *priv)
|
struct cndm_ring *cndm_create_sq(struct cndm_priv *priv)
|
||||||
{
|
{
|
||||||
struct cndm_ring *sq;
|
struct cndm_ring *sq;
|
||||||
@@ -69,7 +71,7 @@ int cndm_open_sq(struct cndm_ring *sq, struct cndm_priv *priv, struct cndm_cq *c
|
|||||||
sq->priv = priv;
|
sq->priv = priv;
|
||||||
sq->cq = cq;
|
sq->cq = cq;
|
||||||
cq->src_ring = sq;
|
cq->src_ring = sq;
|
||||||
// cq->handler = cndm_tx_irq;
|
cq->handler = cndm_sq_cq_handler;
|
||||||
|
|
||||||
sq->prod_ptr = 0;
|
sq->prod_ptr = 0;
|
||||||
sq->cons_ptr = 0;
|
sq->cons_ptr = 0;
|
||||||
@@ -152,6 +154,21 @@ void cndm_close_sq(struct cndm_ring *sq)
|
|||||||
sq->priv = NULL;
|
sq->priv = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cndm_is_sq_ring_empty(const struct cndm_ring *sq)
|
||||||
|
{
|
||||||
|
return sq->prod_ptr == sq->cons_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cndm_is_sq_ring_full(const struct cndm_ring *sq)
|
||||||
|
{
|
||||||
|
return (sq->prod_ptr - sq->cons_ptr) >= sq->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cndm_sq_write_prod_ptr(const struct cndm_ring *sq)
|
||||||
|
{
|
||||||
|
iowrite32(sq->prod_ptr & 0xffff, sq->db_addr);
|
||||||
|
}
|
||||||
|
|
||||||
static void cndm_free_tx_desc(struct cndm_ring *sq, int index, int napi_budget)
|
static void cndm_free_tx_desc(struct cndm_ring *sq, int index, int napi_budget)
|
||||||
{
|
{
|
||||||
struct cndm_priv *priv = sq->priv;
|
struct cndm_priv *priv = sq->priv;
|
||||||
@@ -173,7 +190,7 @@ int cndm_free_tx_buf(struct cndm_ring *sq)
|
|||||||
u32 index;
|
u32 index;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
|
|
||||||
while (sq->prod_ptr != sq->cons_ptr) {
|
while (!cndm_is_sq_ring_empty(sq)) {
|
||||||
index = sq->cons_ptr & sq->size_mask;
|
index = sq->cons_ptr & sq->size_mask;
|
||||||
cndm_free_tx_desc(sq, index, 0);
|
cndm_free_tx_desc(sq, index, 0);
|
||||||
sq->cons_ptr++;
|
sq->cons_ptr++;
|
||||||
@@ -229,12 +246,19 @@ static int cndm_process_tx_cq(struct cndm_cq *cq, int napi_budget)
|
|||||||
cq->cons_ptr = cq_cons_ptr;
|
cq->cons_ptr = cq_cons_ptr;
|
||||||
sq->cons_ptr = cons_ptr;
|
sq->cons_ptr = cons_ptr;
|
||||||
|
|
||||||
|
cndm_cq_write_cons_ptr(cq);
|
||||||
|
|
||||||
if (netif_tx_queue_stopped(sq->tx_queue) && (done != 0 || sq->prod_ptr == sq->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);
|
netif_tx_wake_queue(sq->tx_queue);
|
||||||
|
|
||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cndm_sq_cq_handler(struct cndm_cq *cq)
|
||||||
|
{
|
||||||
|
napi_schedule_irqoff(&cq->napi);
|
||||||
|
}
|
||||||
|
|
||||||
int cndm_poll_tx_cq(struct napi_struct *napi, int budget)
|
int cndm_poll_tx_cq(struct napi_struct *napi, int budget)
|
||||||
{
|
{
|
||||||
struct cndm_cq *cq = container_of(napi, struct cndm_cq, napi);
|
struct cndm_cq *cq = container_of(napi, struct cndm_cq, napi);
|
||||||
@@ -247,7 +271,7 @@ int cndm_poll_tx_cq(struct napi_struct *napi, int budget)
|
|||||||
|
|
||||||
napi_complete(napi);
|
napi_complete(napi);
|
||||||
|
|
||||||
// TODO re-enable interrupts
|
cndm_cq_write_cons_ptr_arm(cq);
|
||||||
|
|
||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
@@ -315,7 +339,7 @@ int cndm_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dma_wmb();
|
dma_wmb();
|
||||||
iowrite32(sq->prod_ptr & 0xffff, sq->db_addr);
|
cndm_sq_write_prod_ptr(sq);
|
||||||
|
|
||||||
return NETDEV_TX_OK;
|
return NETDEV_TX_OK;
|
||||||
|
|
||||||
|
|||||||
@@ -335,8 +335,10 @@ cndm_micro_dp_mgr #(
|
|||||||
.SYS_CLK_PER_NS_DEN(SYS_CLK_PER_NS_DEN),
|
.SYS_CLK_PER_NS_DEN(SYS_CLK_PER_NS_DEN),
|
||||||
|
|
||||||
// Queue configuration
|
// Queue configuration
|
||||||
.WQN_W(WQN_W),
|
.EQN_W(CQN_W),
|
||||||
.CQN_W(CQN_W),
|
.CQN_W(CQN_W),
|
||||||
|
.SQN_W(WQN_W),
|
||||||
|
.RQN_W(WQN_W),
|
||||||
|
|
||||||
// PTP configuration
|
// PTP configuration
|
||||||
.PTP_EN(PTP_TS_EN),
|
.PTP_EN(PTP_TS_EN),
|
||||||
|
|||||||
@@ -335,8 +335,10 @@ cndm_micro_dp_mgr #(
|
|||||||
.SYS_CLK_PER_NS_DEN(SYS_CLK_PER_NS_DEN),
|
.SYS_CLK_PER_NS_DEN(SYS_CLK_PER_NS_DEN),
|
||||||
|
|
||||||
// Queue configuration
|
// Queue configuration
|
||||||
.WQN_W(WQN_W),
|
.EQN_W(CQN_W),
|
||||||
.CQN_W(CQN_W),
|
.CQN_W(CQN_W),
|
||||||
|
.SQN_W(WQN_W),
|
||||||
|
.RQN_W(WQN_W),
|
||||||
|
|
||||||
// PTP configuration
|
// PTP configuration
|
||||||
.PTP_EN(PTP_TS_EN),
|
.PTP_EN(PTP_TS_EN),
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ Authors:
|
|||||||
* Corundum-micro completion write module
|
* Corundum-micro completion write module
|
||||||
*/
|
*/
|
||||||
module cndm_micro_cpl_wr #(
|
module cndm_micro_cpl_wr #(
|
||||||
parameter CQN_W = 5
|
parameter CQN_W = 5,
|
||||||
|
parameter logic IS_CQ = 1'b1,
|
||||||
|
parameter logic IS_EQ = 1'b0,
|
||||||
|
parameter logic CQ_IRQ = IS_CQ
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
input wire logic clk,
|
input wire logic clk,
|
||||||
@@ -45,28 +48,54 @@ module cndm_micro_cpl_wr #(
|
|||||||
*/
|
*/
|
||||||
taxi_axis_if.src m_axis_irq,
|
taxi_axis_if.src m_axis_irq,
|
||||||
|
|
||||||
taxi_axis_if.snk s_axis_cpl
|
/*
|
||||||
|
* Completion input
|
||||||
|
*/
|
||||||
|
taxi_axis_if.snk s_axis_cpl,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event input
|
||||||
|
*/
|
||||||
|
taxi_axis_if.snk s_axis_event,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event output
|
||||||
|
*/
|
||||||
|
taxi_axis_if.src m_axis_event
|
||||||
);
|
);
|
||||||
|
|
||||||
localparam DMA_ADDR_W = dma_wr_desc_req.DST_ADDR_W;
|
localparam DMA_ADDR_W = dma_wr_desc_req.DST_ADDR_W;
|
||||||
|
|
||||||
localparam IRQN_W = m_axis_irq.DATA_W;
|
localparam IRQN_W = m_axis_irq.DATA_W;
|
||||||
|
|
||||||
|
typedef enum logic [2:0] {
|
||||||
|
QTYPE_EQ,
|
||||||
|
QTYPE_CQ,
|
||||||
|
QTYPE_SQ,
|
||||||
|
QTYPE_RQ
|
||||||
|
} qtype_t;
|
||||||
|
|
||||||
logic [CQN_W-1:0] cq_req_cqn_reg = '0;
|
logic [CQN_W-1:0] cq_req_cqn_reg = '0;
|
||||||
|
logic [2:0] cq_req_qtype_reg = '0;
|
||||||
logic cq_req_valid_reg = 1'b0;
|
logic cq_req_valid_reg = 1'b0;
|
||||||
logic cq_req_ready;
|
logic cq_req_ready;
|
||||||
logic [IRQN_W-1:0] cq_rsp_irqn;
|
|
||||||
logic [DMA_ADDR_W-1:0] cq_rsp_addr;
|
logic [DMA_ADDR_W-1:0] cq_rsp_addr;
|
||||||
logic cq_rsp_phase_tag;
|
logic cq_rsp_phase_tag;
|
||||||
logic cq_rsp_error;
|
logic cq_rsp_error;
|
||||||
logic cq_rsp_valid;
|
logic cq_rsp_valid;
|
||||||
logic cq_rsp_ready_reg = 1'b0;
|
logic cq_rsp_ready_reg = 1'b0;
|
||||||
|
|
||||||
|
logic [CQN_W-1:0] notify_req_qn_reg = '0;
|
||||||
|
logic notify_req_valid_reg = 1'b0;
|
||||||
|
logic notify_req_ready;
|
||||||
|
|
||||||
cndm_micro_queue_state #(
|
cndm_micro_queue_state #(
|
||||||
.QN_W(CQN_W),
|
.QN_W(CQN_W),
|
||||||
.DQN_W(IRQN_W),
|
.DQN_W(IRQN_W),
|
||||||
.IS_CQ(1),
|
.IS_CQ(IS_CQ || !IS_EQ),
|
||||||
.QTYPE_EN(0),
|
.IS_EQ(IS_EQ),
|
||||||
|
.CQ_IRQ(CQ_IRQ),
|
||||||
|
.QTYPE_EN(IS_CQ && IS_EQ),
|
||||||
.QE_SIZE(16),
|
.QE_SIZE(16),
|
||||||
.DMA_ADDR_W(DMA_ADDR_W)
|
.DMA_ADDR_W(DMA_ADDR_W)
|
||||||
)
|
)
|
||||||
@@ -89,16 +118,33 @@ cq_mgr_inst (
|
|||||||
* Queue management interface
|
* Queue management interface
|
||||||
*/
|
*/
|
||||||
.req_qn(cq_req_cqn_reg),
|
.req_qn(cq_req_cqn_reg),
|
||||||
.req_qtype('0),
|
.req_qtype(cq_req_qtype_reg),
|
||||||
.req_valid(cq_req_valid_reg),
|
.req_valid(cq_req_valid_reg),
|
||||||
.req_ready(cq_req_ready),
|
.req_ready(cq_req_ready),
|
||||||
.rsp_qn(),
|
.rsp_qn(),
|
||||||
.rsp_dqn(cq_rsp_irqn),
|
.rsp_dqn(),
|
||||||
.rsp_addr(cq_rsp_addr),
|
.rsp_addr(cq_rsp_addr),
|
||||||
.rsp_phase_tag(cq_rsp_phase_tag),
|
.rsp_phase_tag(cq_rsp_phase_tag),
|
||||||
.rsp_error(cq_rsp_error),
|
.rsp_error(cq_rsp_error),
|
||||||
.rsp_valid(cq_rsp_valid),
|
.rsp_valid(cq_rsp_valid),
|
||||||
.rsp_ready(cq_rsp_ready_reg)
|
.rsp_ready(cq_rsp_ready_reg),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notification interface
|
||||||
|
*/
|
||||||
|
.notify_req_qn(notify_req_qn_reg),
|
||||||
|
.notify_req_valid(notify_req_valid_reg),
|
||||||
|
.notify_req_ready(notify_req_ready),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupts
|
||||||
|
*/
|
||||||
|
.m_axis_irq(m_axis_irq),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event output
|
||||||
|
*/
|
||||||
|
.m_axis_event(m_axis_event)
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef enum logic [1:0] {
|
typedef enum logic [1:0] {
|
||||||
@@ -111,20 +157,11 @@ state_t state_reg = STATE_IDLE;
|
|||||||
|
|
||||||
logic phase_tag_reg = 1'b0;
|
logic phase_tag_reg = 1'b0;
|
||||||
|
|
||||||
logic [IRQN_W-1:0] m_axis_irq_irqn_reg = '0;
|
logic [127:0] data_reg = '0;
|
||||||
logic m_axis_irq_tvalid_reg = 1'b0;
|
|
||||||
|
|
||||||
assign m_axis_irq.tdata = m_axis_irq_irqn_reg;
|
|
||||||
assign m_axis_irq.tkeep = '1;
|
|
||||||
assign m_axis_irq.tstrb = m_axis_irq.tkeep;
|
|
||||||
assign m_axis_irq.tvalid = m_axis_irq_tvalid_reg;
|
|
||||||
assign m_axis_irq.tlast = 1'b1;
|
|
||||||
assign m_axis_irq.tid = '0;
|
|
||||||
assign m_axis_irq.tdest = '0;
|
|
||||||
assign m_axis_irq.tuser = '0;
|
|
||||||
|
|
||||||
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
s_axis_cpl.tready <= 1'b0;
|
s_axis_cpl.tready <= 1'b0;
|
||||||
|
s_axis_event.tready <= 1'b0;
|
||||||
|
|
||||||
dma_wr_desc_req.req_src_sel <= '0;
|
dma_wr_desc_req.req_src_sel <= '0;
|
||||||
dma_wr_desc_req.req_src_asid <= '0;
|
dma_wr_desc_req.req_src_asid <= '0;
|
||||||
@@ -142,16 +179,27 @@ always_ff @(posedge clk) begin
|
|||||||
cq_req_valid_reg <= cq_req_valid_reg && !cq_req_ready;
|
cq_req_valid_reg <= cq_req_valid_reg && !cq_req_ready;
|
||||||
cq_rsp_ready_reg <= 1'b0;
|
cq_rsp_ready_reg <= 1'b0;
|
||||||
|
|
||||||
m_axis_irq_tvalid_reg <= m_axis_irq_tvalid_reg && !m_axis_irq.tready;
|
notify_req_valid_reg <= notify_req_valid_reg && !notify_req_ready;
|
||||||
|
|
||||||
case (state_reg)
|
case (state_reg)
|
||||||
STATE_IDLE: begin
|
STATE_IDLE: begin
|
||||||
dma_wr_desc_req.req_src_addr <= '0;
|
dma_wr_desc_req.req_src_addr <= '0;
|
||||||
|
|
||||||
cq_req_cqn_reg <= s_axis_cpl.tdest;
|
if (IS_EQ && s_axis_event.tvalid && !s_axis_event.tready && (!notify_req_valid_reg || notify_req_ready)) begin
|
||||||
|
data_reg <= s_axis_event.tdata;
|
||||||
if (s_axis_cpl.tvalid && !s_axis_cpl.tready) begin
|
cq_req_cqn_reg <= s_axis_event.tdest;
|
||||||
|
cq_req_qtype_reg <= QTYPE_EQ;
|
||||||
cq_req_valid_reg <= 1'b1;
|
cq_req_valid_reg <= 1'b1;
|
||||||
|
notify_req_qn_reg <= s_axis_event.tdest;
|
||||||
|
s_axis_event.tready <= 1'b1;
|
||||||
|
state_reg <= STATE_QUERY_CQ;
|
||||||
|
end else if ((IS_CQ || !IS_EQ) && s_axis_cpl.tvalid && !s_axis_cpl.tready && (!notify_req_valid_reg || notify_req_ready)) begin
|
||||||
|
data_reg <= s_axis_cpl.tdata;
|
||||||
|
cq_req_cqn_reg <= s_axis_cpl.tdest;
|
||||||
|
cq_req_qtype_reg <= QTYPE_CQ;
|
||||||
|
cq_req_valid_reg <= 1'b1;
|
||||||
|
notify_req_qn_reg <= s_axis_cpl.tdest;
|
||||||
|
s_axis_cpl.tready <= 1'b1;
|
||||||
state_reg <= STATE_QUERY_CQ;
|
state_reg <= STATE_QUERY_CQ;
|
||||||
end else begin
|
end else begin
|
||||||
state_reg <= STATE_IDLE;
|
state_reg <= STATE_IDLE;
|
||||||
@@ -164,13 +212,11 @@ always_ff @(posedge clk) begin
|
|||||||
if (cq_rsp_valid && cq_rsp_ready_reg) begin
|
if (cq_rsp_valid && cq_rsp_ready_reg) begin
|
||||||
cq_rsp_ready_reg <= 1'b0;
|
cq_rsp_ready_reg <= 1'b0;
|
||||||
|
|
||||||
m_axis_irq_irqn_reg <= cq_rsp_irqn;
|
|
||||||
dma_wr_desc_req.req_dst_addr <= cq_rsp_addr;
|
dma_wr_desc_req.req_dst_addr <= cq_rsp_addr;
|
||||||
phase_tag_reg <= cq_rsp_phase_tag;
|
phase_tag_reg <= cq_rsp_phase_tag;
|
||||||
|
|
||||||
if (cq_rsp_error) begin
|
if (cq_rsp_error) begin
|
||||||
// drop completion
|
// drop completion
|
||||||
s_axis_cpl.tready <= 1'b1;
|
|
||||||
state_reg <= STATE_IDLE;
|
state_reg <= STATE_IDLE;
|
||||||
end else begin
|
end else begin
|
||||||
dma_wr_desc_req.req_valid <= 1'b1;
|
dma_wr_desc_req.req_valid <= 1'b1;
|
||||||
@@ -180,8 +226,7 @@ always_ff @(posedge clk) begin
|
|||||||
end
|
end
|
||||||
STATE_WRITE_DATA: begin
|
STATE_WRITE_DATA: begin
|
||||||
if (dma_wr_desc_sts.sts_valid) begin
|
if (dma_wr_desc_sts.sts_valid) begin
|
||||||
s_axis_cpl.tready <= 1'b1;
|
notify_req_valid_reg <= 1'b1;
|
||||||
m_axis_irq_tvalid_reg <= 1'b1;
|
|
||||||
state_reg <= STATE_IDLE;
|
state_reg <= STATE_IDLE;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -194,7 +239,6 @@ always_ff @(posedge clk) begin
|
|||||||
state_reg <= STATE_IDLE;
|
state_reg <= STATE_IDLE;
|
||||||
cq_req_valid_reg <= 1'b0;
|
cq_req_valid_reg <= 1'b0;
|
||||||
cq_rsp_ready_reg <= 1'b0;
|
cq_rsp_ready_reg <= 1'b0;
|
||||||
m_axis_irq_tvalid_reg <= 1'b0;
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -207,7 +251,7 @@ localparam SEG_BE_W = dma_ram_rd.SEG_BE_W;
|
|||||||
if (SEGS*SEG_DATA_W < 128)
|
if (SEGS*SEG_DATA_W < 128)
|
||||||
$fatal(0, "Total segmented interface width must be at least 128 (instance %m)");
|
$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, s_axis_cpl.tdata[126:0]});
|
wire [SEGS-1:0][SEG_DATA_W-1:0] ram_data = (SEG_DATA_W*SEGS)'({phase_tag_reg, data_reg[126:0]});
|
||||||
|
|
||||||
for (genvar n = 0; n < SEGS; n = n + 1) begin
|
for (genvar n = 0; n < SEGS; n = n + 1) begin
|
||||||
|
|
||||||
|
|||||||
@@ -66,10 +66,15 @@ logic wq_rsp_error;
|
|||||||
logic wq_rsp_valid;
|
logic wq_rsp_valid;
|
||||||
logic wq_rsp_ready_reg = 1'b0;
|
logic wq_rsp_ready_reg = 1'b0;
|
||||||
|
|
||||||
|
taxi_axis_if axis_irq_stub();
|
||||||
|
taxi_axis_if axis_event_stub();
|
||||||
|
|
||||||
cndm_micro_queue_state #(
|
cndm_micro_queue_state #(
|
||||||
.QN_W(WQN_W),
|
.QN_W(WQN_W),
|
||||||
.DQN_W(CQN_W),
|
.DQN_W(CQN_W),
|
||||||
.IS_CQ(0),
|
.IS_CQ(0),
|
||||||
|
.IS_EQ(0),
|
||||||
|
.CQ_IRQ(0),
|
||||||
.QTYPE_EN(1),
|
.QTYPE_EN(1),
|
||||||
.QE_SIZE(16),
|
.QE_SIZE(16),
|
||||||
.DMA_ADDR_W(DMA_ADDR_W)
|
.DMA_ADDR_W(DMA_ADDR_W)
|
||||||
@@ -102,7 +107,24 @@ wq_mgr_inst (
|
|||||||
.rsp_phase_tag(),
|
.rsp_phase_tag(),
|
||||||
.rsp_error(wq_rsp_error),
|
.rsp_error(wq_rsp_error),
|
||||||
.rsp_valid(wq_rsp_valid),
|
.rsp_valid(wq_rsp_valid),
|
||||||
.rsp_ready(wq_rsp_ready_reg)
|
.rsp_ready(wq_rsp_ready_reg),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notification interface
|
||||||
|
*/
|
||||||
|
.notify_req_qn('0),
|
||||||
|
.notify_req_valid(1'b0),
|
||||||
|
.notify_req_ready(),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupts
|
||||||
|
*/
|
||||||
|
.m_axis_irq(axis_irq_stub),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event output
|
||||||
|
*/
|
||||||
|
.m_axis_event(axis_event_stub)
|
||||||
);
|
);
|
||||||
|
|
||||||
taxi_dma_desc_if #(
|
taxi_dma_desc_if #(
|
||||||
|
|||||||
@@ -33,8 +33,15 @@ module cndm_micro_dp_mgr #
|
|||||||
parameter SYS_CLK_PER_NS_DEN = 1,
|
parameter SYS_CLK_PER_NS_DEN = 1,
|
||||||
|
|
||||||
// Queue configuration
|
// Queue configuration
|
||||||
parameter WQN_W = 5,
|
parameter EQN_W = 5,
|
||||||
parameter CQN_W = WQN_W,
|
parameter CQN_W = 5,
|
||||||
|
parameter SQN_W = 5,
|
||||||
|
parameter RQN_W = 5,
|
||||||
|
parameter EQE_VER = 1,
|
||||||
|
parameter CQE_VER = 1,
|
||||||
|
parameter SQE_VER = 1,
|
||||||
|
parameter RQE_VER = 1,
|
||||||
|
parameter LOG_MAX_WQ_SZ = 15,
|
||||||
|
|
||||||
// PTP configuration
|
// PTP configuration
|
||||||
parameter logic PTP_EN = 1'b1,
|
parameter logic PTP_EN = 1'b1,
|
||||||
@@ -47,8 +54,10 @@ module cndm_micro_dp_mgr #
|
|||||||
parameter PORT_BASE_ADDR_HOST = 0,
|
parameter PORT_BASE_ADDR_HOST = 0,
|
||||||
parameter PORT_STRIDE = 'h10000,
|
parameter PORT_STRIDE = 'h10000,
|
||||||
parameter WQ_REG_STRIDE = 32,
|
parameter WQ_REG_STRIDE = 32,
|
||||||
parameter QM_OFFSET = 'h0000,
|
parameter EQM_OFFSET = 'h4000,
|
||||||
parameter CQM_OFFSET = 'h4000,
|
parameter CQM_OFFSET = 'h4000,
|
||||||
|
parameter SQM_OFFSET = 'h0000,
|
||||||
|
parameter RQM_OFFSET = 'h0000,
|
||||||
parameter PORT_CTRL_OFFSET = 'h8000
|
parameter PORT_CTRL_OFFSET = 'h8000
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
@@ -166,6 +175,13 @@ wire [31:0] cmd_ram_rd_data = cmd_ram[cmd_ram_rd_addr];
|
|||||||
// ID ROM
|
// ID ROM
|
||||||
localparam ID_PAGES = 3;
|
localparam ID_PAGES = 3;
|
||||||
localparam ID_AW = $clog2((ID_PAGES+1)*8);
|
localparam ID_AW = $clog2((ID_PAGES+1)*8);
|
||||||
|
|
||||||
|
// detect sharing between EQ/CQ and SQ/RQ (same queue manager)
|
||||||
|
localparam EQ_POOL = 1;
|
||||||
|
localparam CQ_POOL = EQ_POOL + (EQM_OFFSET == CQM_OFFSET ? 0 : 1);
|
||||||
|
localparam SQ_POOL = CQ_POOL + 1;
|
||||||
|
localparam RQ_POOL = SQ_POOL + (SQM_OFFSET == RQM_OFFSET ? 0 : 1);
|
||||||
|
|
||||||
logic [31:0] id_rom[(ID_PAGES+1)*8] = '{
|
logic [31:0] id_rom[(ID_PAGES+1)*8] = '{
|
||||||
// Common
|
// Common
|
||||||
0, // 0: status
|
0, // 0: status
|
||||||
@@ -213,28 +229,28 @@ logic [31:0] id_rom[(ID_PAGES+1)*8] = '{
|
|||||||
0, // 23
|
0, // 23
|
||||||
// Page 2: Resources
|
// Page 2: Resources
|
||||||
{ // 24
|
{ // 24
|
||||||
8'd0, // [31:24] EQE_VER
|
8'(EQE_VER), // [31:24] EQE_VER
|
||||||
8'd0, // [23:16] EQ_POOL
|
8'(EQ_POOL), // [23:16] EQ_POOL
|
||||||
8'd0, // [15:8] LOG_MAX_EQ_SZ
|
8'(LOG_MAX_WQ_SZ), // [15:8] LOG_MAX_EQ_SZ
|
||||||
8'd0 // [7:0] LOG_MAX_EQ
|
8'(EQN_W) // [7:0] LOG_MAX_EQ
|
||||||
},
|
},
|
||||||
{ // 25
|
{ // 25
|
||||||
8'd1, // [31:24] CQE_VER
|
8'(CQE_VER), // [31:24] CQE_VER
|
||||||
8'd0, // [23:16] CQ_POOL
|
8'(CQ_POOL), // [23:16] CQ_POOL
|
||||||
8'd15, // [15:8] LOG_MAX_CQ_SZ
|
8'(LOG_MAX_WQ_SZ), // [15:8] LOG_MAX_CQ_SZ
|
||||||
8'(CQN_W) // [7:0] LOG_MAX_CQ
|
8'(CQN_W) // [7:0] LOG_MAX_CQ
|
||||||
},
|
},
|
||||||
{ // 26
|
{ // 26
|
||||||
8'd1, // [31:24] SQE_VER
|
8'(SQE_VER), // [31:24] SQE_VER
|
||||||
8'd1, // [23:16] SQ_POOL
|
8'(SQ_POOL), // [23:16] SQ_POOL
|
||||||
8'd15, // [15:8] LOG_MAX_SQ_SZ
|
8'(LOG_MAX_WQ_SZ), // [15:8] LOG_MAX_SQ_SZ
|
||||||
8'(WQN_W) // [7:0] LOG_MAX_SQ
|
8'(SQN_W) // [7:0] LOG_MAX_SQ
|
||||||
},
|
},
|
||||||
{ // 27
|
{ // 27
|
||||||
8'd1, // [31:24] RQE_VER
|
8'(RQE_VER), // [31:24] RQE_VER
|
||||||
8'd1, // [23:16] RQ_POOL
|
8'(RQ_POOL), // [23:16] RQ_POOL
|
||||||
8'd15, // [15:8] LOG_MAX_RQ_SZ
|
8'(LOG_MAX_WQ_SZ), // [15:8] LOG_MAX_RQ_SZ
|
||||||
8'(WQN_W) // [7:0] LOG_MAX_RQ
|
8'(RQN_W) // [7:0] LOG_MAX_RQ
|
||||||
},
|
},
|
||||||
0, // 28
|
0, // 28
|
||||||
0, // 29
|
0, // 29
|
||||||
@@ -373,20 +389,22 @@ always_comb begin
|
|||||||
|
|
||||||
// determine block base address
|
// determine block base address
|
||||||
case (opcode_reg)
|
case (opcode_reg)
|
||||||
// // EQ
|
// EQ
|
||||||
// CMD_OP_CREATE_EQ:
|
CMD_OP_CREATE_EQ:
|
||||||
// begin
|
begin
|
||||||
// dw3_next = 0;
|
cnt_next = 2**EQN_W-1;
|
||||||
// dp_ptr_next = DP_APB_ADDR_W'({dw2_reg, 16'd0} | 'h8000) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
qtype_next = QTYPE_EQ;
|
||||||
// host_ptr_next = 32'({dw2_reg, 16'd0} | 'h8000) + PORT_BASE_ADDR_HOST;
|
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + EQM_OFFSET + PORT_BASE_ADDR_DP);
|
||||||
// end
|
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + EQM_OFFSET + PORT_BASE_ADDR_HOST;
|
||||||
// CMD_OP_MODIFY_EQ,
|
end
|
||||||
// CMD_OP_QUERY_EQ,
|
CMD_OP_MODIFY_EQ,
|
||||||
// CMD_OP_DESTROY_EQ:
|
CMD_OP_QUERY_EQ,
|
||||||
// begin
|
CMD_OP_DESTROY_EQ:
|
||||||
// dp_ptr_next = DP_APB_ADDR_W'({dw2_reg, 16'd0} | 'h8000) + DP_APB_ADDR_W'(PORT_BASE_ADDR_DP);
|
begin
|
||||||
// host_ptr_next = 32'({dw2_reg, 16'd0} | 'h8000) + PORT_BASE_ADDR_HOST;
|
qtype_next = QTYPE_EQ;
|
||||||
// end
|
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + EQM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_DP);
|
||||||
|
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + EQM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_HOST;
|
||||||
|
end
|
||||||
// CQ
|
// CQ
|
||||||
CMD_OP_CREATE_CQ:
|
CMD_OP_CREATE_CQ:
|
||||||
begin
|
begin
|
||||||
@@ -406,34 +424,34 @@ always_comb begin
|
|||||||
// SQ
|
// SQ
|
||||||
CMD_OP_CREATE_SQ:
|
CMD_OP_CREATE_SQ:
|
||||||
begin
|
begin
|
||||||
cnt_next = 2**WQN_W-1;
|
cnt_next = 2**SQN_W-1;
|
||||||
qtype_next = QTYPE_SQ;
|
qtype_next = QTYPE_SQ;
|
||||||
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + PORT_BASE_ADDR_DP);
|
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + SQM_OFFSET + PORT_BASE_ADDR_DP);
|
||||||
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + PORT_BASE_ADDR_HOST;
|
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + SQM_OFFSET + PORT_BASE_ADDR_HOST;
|
||||||
end
|
end
|
||||||
CMD_OP_MODIFY_SQ,
|
CMD_OP_MODIFY_SQ,
|
||||||
CMD_OP_QUERY_SQ,
|
CMD_OP_QUERY_SQ,
|
||||||
CMD_OP_DESTROY_SQ:
|
CMD_OP_DESTROY_SQ:
|
||||||
begin
|
begin
|
||||||
qtype_next = QTYPE_SQ;
|
qtype_next = QTYPE_SQ;
|
||||||
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_DP);
|
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + SQM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_DP);
|
||||||
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_HOST;
|
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + SQM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_HOST;
|
||||||
end
|
end
|
||||||
// RQ
|
// RQ
|
||||||
CMD_OP_CREATE_RQ:
|
CMD_OP_CREATE_RQ:
|
||||||
begin
|
begin
|
||||||
cnt_next = 2**WQN_W-1;
|
cnt_next = 2**RQN_W-1;
|
||||||
qtype_next = QTYPE_RQ;
|
qtype_next = QTYPE_RQ;
|
||||||
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + PORT_BASE_ADDR_DP);
|
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + RQM_OFFSET + PORT_BASE_ADDR_DP);
|
||||||
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + PORT_BASE_ADDR_HOST;
|
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + RQM_OFFSET + PORT_BASE_ADDR_HOST;
|
||||||
end
|
end
|
||||||
CMD_OP_MODIFY_RQ,
|
CMD_OP_MODIFY_RQ,
|
||||||
CMD_OP_QUERY_RQ,
|
CMD_OP_QUERY_RQ,
|
||||||
CMD_OP_DESTROY_RQ:
|
CMD_OP_DESTROY_RQ:
|
||||||
begin
|
begin
|
||||||
qtype_next = QTYPE_RQ;
|
qtype_next = QTYPE_RQ;
|
||||||
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_DP);
|
dp_ptr_next = DP_APB_ADDR_W'((dw2_reg[15:0] * PORT_STRIDE) + RQM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_DP);
|
||||||
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + QM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_HOST;
|
host_ptr_next = (dw2_reg[15:0] * PORT_STRIDE) + RQM_OFFSET + (dw3_reg[15:0] * WQ_REG_STRIDE) + PORT_BASE_ADDR_HOST;
|
||||||
end
|
end
|
||||||
default: begin end
|
default: begin end
|
||||||
endcase
|
endcase
|
||||||
@@ -676,7 +694,11 @@ always_comb begin
|
|||||||
// reset queue 2
|
// reset queue 2
|
||||||
|
|
||||||
// store doorbell offset
|
// store doorbell offset
|
||||||
cmd_ram_wr_data = host_ptr_reg + 'h0008;
|
if (qtype_reg == QTYPE_SQ || qtype_reg == QTYPE_RQ) begin
|
||||||
|
cmd_ram_wr_data = host_ptr_reg + 'h0008;
|
||||||
|
end else begin
|
||||||
|
cmd_ram_wr_data = host_ptr_reg + 'h000C;
|
||||||
|
end
|
||||||
cmd_ram_wr_addr = 7;
|
cmd_ram_wr_addr = 7;
|
||||||
cmd_ram_wr_en = 1'b1;
|
cmd_ram_wr_en = 1'b1;
|
||||||
|
|
||||||
|
|||||||
@@ -483,8 +483,21 @@ cpl_mux_inst (
|
|||||||
.m_axis(axis_cpl)
|
.m_axis(axis_cpl)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
taxi_axis_if #(
|
||||||
|
.DATA_W(16*8),
|
||||||
|
.KEEP_EN(1),
|
||||||
|
.LAST_EN(1),
|
||||||
|
.ID_EN(0),
|
||||||
|
.DEST_EN(1),
|
||||||
|
.DEST_W(CQN_W),
|
||||||
|
.USER_EN(0)
|
||||||
|
) axis_event();
|
||||||
|
|
||||||
cndm_micro_cpl_wr #(
|
cndm_micro_cpl_wr #(
|
||||||
.CQN_W(CQN_W)
|
.CQN_W(CQN_W),
|
||||||
|
.IS_CQ(1),
|
||||||
|
.IS_EQ(1),
|
||||||
|
.CQ_IRQ(1)
|
||||||
)
|
)
|
||||||
cpl_wr_inst (
|
cpl_wr_inst (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
@@ -513,7 +526,20 @@ cpl_wr_inst (
|
|||||||
*/
|
*/
|
||||||
.m_axis_irq(m_axis_irq),
|
.m_axis_irq(m_axis_irq),
|
||||||
|
|
||||||
.s_axis_cpl(axis_cpl)
|
/*
|
||||||
|
* Completion input
|
||||||
|
*/
|
||||||
|
.s_axis_cpl(axis_cpl),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event input
|
||||||
|
*/
|
||||||
|
.s_axis_event(axis_event),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event output
|
||||||
|
*/
|
||||||
|
.m_axis_event(axis_event)
|
||||||
);
|
);
|
||||||
|
|
||||||
// TX path
|
// TX path
|
||||||
|
|||||||
@@ -19,39 +19,58 @@ module cndm_micro_queue_state #(
|
|||||||
parameter QN_W = 5,
|
parameter QN_W = 5,
|
||||||
parameter DQN_W = 5,
|
parameter DQN_W = 5,
|
||||||
parameter logic IS_CQ = 1'b0,
|
parameter logic IS_CQ = 1'b0,
|
||||||
parameter logic QTYPE_EN = !IS_CQ,
|
parameter logic IS_EQ = 1'b0,
|
||||||
|
parameter logic CQ_IRQ = IS_CQ,
|
||||||
|
parameter logic QTYPE_EN = 1'b1,
|
||||||
parameter QE_SIZE = 16,
|
parameter QE_SIZE = 16,
|
||||||
parameter DMA_ADDR_W = 64
|
parameter DMA_ADDR_W = 64
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
input wire logic clk,
|
input wire logic clk,
|
||||||
input wire logic rst,
|
input wire logic rst,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Control register interface
|
* Control register interface
|
||||||
*/
|
*/
|
||||||
taxi_axil_if.wr_slv s_axil_ctrl_wr,
|
taxi_axil_if.wr_slv s_axil_ctrl_wr,
|
||||||
taxi_axil_if.rd_slv s_axil_ctrl_rd,
|
taxi_axil_if.rd_slv s_axil_ctrl_rd,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Datapath control register interface
|
* Datapath control register interface
|
||||||
*/
|
*/
|
||||||
taxi_apb_if.slv s_apb_dp_ctrl,
|
taxi_apb_if.slv s_apb_dp_ctrl,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Queue management interface
|
* Queue management interface
|
||||||
*/
|
*/
|
||||||
input wire logic [QN_W-1:0] req_qn,
|
input wire logic [QN_W-1:0] req_qn,
|
||||||
input wire logic [2:0] req_qtype,
|
input wire logic [2:0] req_qtype,
|
||||||
input wire logic req_valid,
|
input wire logic req_valid,
|
||||||
output wire logic req_ready,
|
output wire logic req_ready,
|
||||||
output wire logic [QN_W-1:0] rsp_qn,
|
output wire logic [QN_W-1:0] rsp_qn,
|
||||||
output wire logic [DQN_W-1:0] rsp_dqn,
|
output wire logic [DQN_W-1:0] rsp_dqn,
|
||||||
output wire logic [DMA_ADDR_W-1:0] rsp_addr,
|
output wire logic [DMA_ADDR_W-1:0] rsp_addr,
|
||||||
output wire logic rsp_phase_tag,
|
output wire logic rsp_phase_tag,
|
||||||
output wire logic rsp_error,
|
output wire logic rsp_error,
|
||||||
output wire logic rsp_valid,
|
output wire logic rsp_valid,
|
||||||
input wire logic rsp_ready
|
input wire logic rsp_ready,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notification interface
|
||||||
|
*/
|
||||||
|
input wire logic [QN_W-1:0] notify_req_qn,
|
||||||
|
input wire logic notify_req_valid,
|
||||||
|
output wire logic notify_req_ready,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupts
|
||||||
|
*/
|
||||||
|
taxi_axis_if.src m_axis_irq,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event output
|
||||||
|
*/
|
||||||
|
taxi_axis_if.src m_axis_event
|
||||||
);
|
);
|
||||||
|
|
||||||
localparam PTR_W = 16;
|
localparam PTR_W = 16;
|
||||||
@@ -64,6 +83,12 @@ localparam AXIL_DATA_W = s_axil_ctrl_wr.DATA_W;
|
|||||||
localparam APB_ADDR_W = s_apb_dp_ctrl.ADDR_W;
|
localparam APB_ADDR_W = s_apb_dp_ctrl.ADDR_W;
|
||||||
localparam APB_DATA_W = s_apb_dp_ctrl.DATA_W;
|
localparam APB_DATA_W = s_apb_dp_ctrl.DATA_W;
|
||||||
|
|
||||||
|
localparam IRQN_W = m_axis_irq.DATA_W;
|
||||||
|
|
||||||
|
localparam EQN_W = m_axis_event.DEST_W;
|
||||||
|
localparam EVENT_DATA_W = 64;
|
||||||
|
localparam EVENT_DEST_W = m_axis_event.DEST_W;
|
||||||
|
|
||||||
// check configuration
|
// check configuration
|
||||||
if (s_axil_ctrl_rd.DATA_W != 32 || s_axil_ctrl_wr.DATA_W != 32)
|
if (s_axil_ctrl_rd.DATA_W != 32 || s_axil_ctrl_wr.DATA_W != 32)
|
||||||
$fatal(0, "Error: AXI data width must be 32 (instance %m)");
|
$fatal(0, "Error: AXI data width must be 32 (instance %m)");
|
||||||
@@ -77,6 +102,13 @@ if (s_apb_dp_ctrl.DATA_W != 32)
|
|||||||
if (s_apb_dp_ctrl.ADDR_W < ADDR_W)
|
if (s_apb_dp_ctrl.ADDR_W < ADDR_W)
|
||||||
$fatal(0, "Error: APB address width is insufficient (instance %m)");
|
$fatal(0, "Error: APB address width is insufficient (instance %m)");
|
||||||
|
|
||||||
|
typedef enum logic [2:0] {
|
||||||
|
QTYPE_EQ,
|
||||||
|
QTYPE_CQ,
|
||||||
|
QTYPE_SQ,
|
||||||
|
QTYPE_RQ
|
||||||
|
} qtype_t;
|
||||||
|
|
||||||
logic s_axil_ctrl_awready_reg = 1'b0, s_axil_ctrl_awready_next;
|
logic s_axil_ctrl_awready_reg = 1'b0, s_axil_ctrl_awready_next;
|
||||||
logic s_axil_ctrl_wready_reg = 1'b0, s_axil_ctrl_wready_next;
|
logic s_axil_ctrl_wready_reg = 1'b0, s_axil_ctrl_wready_next;
|
||||||
logic s_axil_ctrl_bvalid_reg = 1'b0, s_axil_ctrl_bvalid_next;
|
logic s_axil_ctrl_bvalid_reg = 1'b0, s_axil_ctrl_bvalid_next;
|
||||||
@@ -130,8 +162,43 @@ assign rsp_phase_tag = rsp_phase_tag_reg;
|
|||||||
assign rsp_error = rsp_error_reg;
|
assign rsp_error = rsp_error_reg;
|
||||||
assign rsp_valid = rsp_valid_reg;
|
assign rsp_valid = rsp_valid_reg;
|
||||||
|
|
||||||
|
logic notify_req_ready_reg = 1'b0, notify_req_ready_next;
|
||||||
|
|
||||||
|
assign notify_req_ready = notify_req_ready_reg;
|
||||||
|
|
||||||
|
logic [IRQN_W-1:0] m_axis_irq_irqn_reg = '0, m_axis_irq_irqn_next;
|
||||||
|
logic m_axis_irq_tvalid_reg = 1'b0, m_axis_irq_tvalid_next;
|
||||||
|
|
||||||
|
assign m_axis_irq.tdata = m_axis_irq_irqn_reg;
|
||||||
|
assign m_axis_irq.tkeep = '1;
|
||||||
|
assign m_axis_irq.tstrb = m_axis_irq.tkeep;
|
||||||
|
assign m_axis_irq.tvalid = m_axis_irq_tvalid_reg;
|
||||||
|
assign m_axis_irq.tlast = 1'b1;
|
||||||
|
assign m_axis_irq.tid = '0;
|
||||||
|
assign m_axis_irq.tdest = '0;
|
||||||
|
assign m_axis_irq.tuser = '0;
|
||||||
|
|
||||||
|
logic [EVENT_DATA_W-1:0] m_axis_event_tdata_reg = '0, m_axis_event_tdata_next;
|
||||||
|
logic [EQN_W-1:0] m_axis_event_tdest_reg = '0, m_axis_event_tdest_next;
|
||||||
|
logic m_axis_event_tvalid_reg = 1'b0, m_axis_event_tvalid_next;
|
||||||
|
|
||||||
|
assign m_axis_event.tdata = m_axis_event.DATA_W'(m_axis_event_tdata_reg);
|
||||||
|
assign m_axis_event.tkeep = '1;
|
||||||
|
assign m_axis_event.tstrb = m_axis_event.tkeep;
|
||||||
|
assign m_axis_event.tvalid = m_axis_event_tvalid_reg;
|
||||||
|
assign m_axis_event.tlast = 1'b1;
|
||||||
|
assign m_axis_event.tid = '0;
|
||||||
|
assign m_axis_event.tdest = m_axis_event_tdest_reg;
|
||||||
|
assign m_axis_event.tuser = '0;
|
||||||
|
|
||||||
logic [2**QN_W-1:0] queue_enable_reg = '0;
|
logic [2**QN_W-1:0] queue_enable_reg = '0;
|
||||||
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
||||||
|
logic queue_mem_arm[2**QN_W] = '{default: '0};
|
||||||
|
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
||||||
|
logic queue_mem_fire[2**QN_W] = '{default: '0};
|
||||||
|
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
||||||
|
logic queue_mem_cq_irq[2**QN_W] = '{default: '0};
|
||||||
|
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
||||||
logic [2:0] queue_mem_qtype[2**QN_W] = '{default: '0};
|
logic [2:0] queue_mem_qtype[2**QN_W] = '{default: '0};
|
||||||
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
||||||
logic [DQN_W-1:0] queue_mem_dqn[2**QN_W] = '{default: '0};
|
logic [DQN_W-1:0] queue_mem_dqn[2**QN_W] = '{default: '0};
|
||||||
@@ -148,6 +215,9 @@ logic queue_mem_wr_en;
|
|||||||
logic [QN_W-1:0] queue_mem_addr;
|
logic [QN_W-1:0] queue_mem_addr;
|
||||||
|
|
||||||
wire queue_mem_rd_enable = queue_enable_reg[queue_mem_addr];
|
wire queue_mem_rd_enable = queue_enable_reg[queue_mem_addr];
|
||||||
|
wire queue_mem_rd_arm = queue_mem_arm[queue_mem_addr];
|
||||||
|
wire queue_mem_rd_fire = queue_mem_fire[queue_mem_addr];
|
||||||
|
wire queue_mem_rd_cq_irq = queue_mem_cq_irq[queue_mem_addr];
|
||||||
wire [2:0] queue_mem_rd_qtype = queue_mem_qtype[queue_mem_addr];
|
wire [2:0] queue_mem_rd_qtype = queue_mem_qtype[queue_mem_addr];
|
||||||
wire [DQN_W-1:0] queue_mem_rd_dqn = queue_mem_dqn[queue_mem_addr];
|
wire [DQN_W-1:0] queue_mem_rd_dqn = queue_mem_dqn[queue_mem_addr];
|
||||||
wire [3:0] queue_mem_rd_log_size = queue_mem_log_size[queue_mem_addr];
|
wire [3:0] queue_mem_rd_log_size = queue_mem_log_size[queue_mem_addr];
|
||||||
@@ -155,7 +225,13 @@ wire [DMA_ADDR_W-1:0] queue_mem_rd_base_addr = queue_mem_base_addr[queue_mem_add
|
|||||||
wire [PTR_W-1:0] queue_mem_rd_prod_ptr = queue_mem_prod_ptr[queue_mem_addr];
|
wire [PTR_W-1:0] queue_mem_rd_prod_ptr = queue_mem_prod_ptr[queue_mem_addr];
|
||||||
wire [PTR_W-1:0] queue_mem_rd_cons_ptr = queue_mem_cons_ptr[queue_mem_addr];
|
wire [PTR_W-1:0] queue_mem_rd_cons_ptr = queue_mem_cons_ptr[queue_mem_addr];
|
||||||
|
|
||||||
|
wire queue_mem_rd_status_empty = queue_mem_rd_prod_ptr == queue_mem_rd_cons_ptr;
|
||||||
|
wire queue_mem_rd_status_full = ($unsigned(queue_mem_rd_prod_ptr - queue_mem_rd_cons_ptr) & ({PTR_W{1'b1}} << queue_mem_rd_log_size)) != 0;
|
||||||
|
|
||||||
logic queue_mem_wr_enable;
|
logic queue_mem_wr_enable;
|
||||||
|
logic queue_mem_wr_arm;
|
||||||
|
logic queue_mem_wr_fire;
|
||||||
|
logic queue_mem_wr_cq_irq;
|
||||||
logic [2:0] queue_mem_wr_qtype;
|
logic [2:0] queue_mem_wr_qtype;
|
||||||
logic [DQN_W-1:0] queue_mem_wr_dqn;
|
logic [DQN_W-1:0] queue_mem_wr_dqn;
|
||||||
logic [3:0] queue_mem_wr_log_size;
|
logic [3:0] queue_mem_wr_log_size;
|
||||||
@@ -163,6 +239,8 @@ logic [DMA_ADDR_W-1:0] queue_mem_wr_base_addr;
|
|||||||
logic [PTR_W-1:0] queue_mem_wr_prod_ptr;
|
logic [PTR_W-1:0] queue_mem_wr_prod_ptr;
|
||||||
logic [PTR_W-1:0] queue_mem_wr_cons_ptr;
|
logic [PTR_W-1:0] queue_mem_wr_cons_ptr;
|
||||||
|
|
||||||
|
logic [QN_W-1:0] scrub_ptr_reg = '0, scrub_ptr_next;
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
s_axil_ctrl_awready_next = 1'b0;
|
s_axil_ctrl_awready_next = 1'b0;
|
||||||
s_axil_ctrl_wready_next = 1'b0;
|
s_axil_ctrl_wready_next = 1'b0;
|
||||||
@@ -183,10 +261,22 @@ always_comb begin
|
|||||||
rsp_error_next = rsp_error_reg;
|
rsp_error_next = rsp_error_reg;
|
||||||
rsp_valid_next = rsp_valid_reg && !rsp_ready;
|
rsp_valid_next = rsp_valid_reg && !rsp_ready;
|
||||||
|
|
||||||
|
notify_req_ready_next = 1'b0;
|
||||||
|
|
||||||
|
m_axis_irq_irqn_next = m_axis_irq_irqn_reg;
|
||||||
|
m_axis_irq_tvalid_next = m_axis_irq_tvalid_reg && !m_axis_irq.tready;
|
||||||
|
|
||||||
|
m_axis_event_tdata_next = m_axis_event_tdata_reg;
|
||||||
|
m_axis_event_tdest_next = m_axis_event_tdest_reg;
|
||||||
|
m_axis_event_tvalid_next = m_axis_event_tvalid_reg && !m_axis_event.tready;
|
||||||
|
|
||||||
queue_mem_wr_en = 1'b0;
|
queue_mem_wr_en = 1'b0;
|
||||||
queue_mem_addr = '0;
|
queue_mem_addr = '0;
|
||||||
|
|
||||||
queue_mem_wr_enable = queue_mem_rd_enable;
|
queue_mem_wr_enable = queue_mem_rd_enable;
|
||||||
|
queue_mem_wr_arm = queue_mem_rd_arm;
|
||||||
|
queue_mem_wr_fire = queue_mem_rd_fire;
|
||||||
|
queue_mem_wr_cq_irq = queue_mem_rd_cq_irq;
|
||||||
queue_mem_wr_qtype = queue_mem_rd_qtype;
|
queue_mem_wr_qtype = queue_mem_rd_qtype;
|
||||||
queue_mem_wr_dqn = queue_mem_rd_dqn;
|
queue_mem_wr_dqn = queue_mem_rd_dqn;
|
||||||
queue_mem_wr_log_size = queue_mem_rd_log_size;
|
queue_mem_wr_log_size = queue_mem_rd_log_size;
|
||||||
@@ -194,12 +284,7 @@ always_comb begin
|
|||||||
queue_mem_wr_prod_ptr = queue_mem_rd_prod_ptr;
|
queue_mem_wr_prod_ptr = queue_mem_rd_prod_ptr;
|
||||||
queue_mem_wr_cons_ptr = queue_mem_rd_cons_ptr;
|
queue_mem_wr_cons_ptr = queue_mem_rd_cons_ptr;
|
||||||
|
|
||||||
// terminate AXI lite writes
|
scrub_ptr_next = scrub_ptr_reg;
|
||||||
if (IS_CQ && s_axil_ctrl_wr.awvalid && s_axil_ctrl_wr.wvalid && !s_axil_ctrl_bvalid_reg) begin
|
|
||||||
s_axil_ctrl_awready_next = 1'b1;
|
|
||||||
s_axil_ctrl_wready_next = 1'b1;
|
|
||||||
s_axil_ctrl_bvalid_next = 1'b1;
|
|
||||||
end
|
|
||||||
|
|
||||||
// terminate AXI lite reads
|
// terminate AXI lite reads
|
||||||
if (s_axil_ctrl_rd.arvalid && !s_axil_ctrl_rvalid_reg) begin
|
if (s_axil_ctrl_rd.arvalid && !s_axil_ctrl_rvalid_reg) begin
|
||||||
@@ -209,7 +294,7 @@ always_comb begin
|
|||||||
s_axil_ctrl_rvalid_next = 1'b1;
|
s_axil_ctrl_rvalid_next = 1'b1;
|
||||||
end
|
end
|
||||||
|
|
||||||
if (!IS_CQ && s_axil_ctrl_wr.awvalid && s_axil_ctrl_wr.wvalid && !s_axil_ctrl_bvalid_reg) begin
|
if (s_axil_ctrl_wr.awvalid && s_axil_ctrl_wr.wvalid && !s_axil_ctrl_bvalid_reg) begin
|
||||||
// AXI lite write
|
// AXI lite write
|
||||||
s_axil_ctrl_awready_next = 1'b1;
|
s_axil_ctrl_awready_next = 1'b1;
|
||||||
s_axil_ctrl_wready_next = 1'b1;
|
s_axil_ctrl_wready_next = 1'b1;
|
||||||
@@ -219,7 +304,19 @@ always_comb begin
|
|||||||
queue_mem_addr = s_axil_ctrl_awaddr_queue_index;
|
queue_mem_addr = s_axil_ctrl_awaddr_queue_index;
|
||||||
|
|
||||||
case (s_axil_ctrl_awaddr_reg_index)
|
case (s_axil_ctrl_awaddr_reg_index)
|
||||||
3'd2: queue_mem_wr_prod_ptr = s_axil_ctrl_wr.wdata[15:0];
|
3'd2: begin
|
||||||
|
if (!IS_CQ && !IS_EQ) begin
|
||||||
|
queue_mem_wr_prod_ptr = s_axil_ctrl_wr.wdata[15:0];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
3'd3: begin
|
||||||
|
if (IS_CQ || IS_EQ) begin
|
||||||
|
queue_mem_wr_cons_ptr = s_axil_ctrl_wr.wdata[15:0];
|
||||||
|
if (s_axil_ctrl_wr.wdata[31]) begin
|
||||||
|
queue_mem_wr_arm = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
default: begin end
|
default: begin end
|
||||||
endcase
|
endcase
|
||||||
|
|
||||||
@@ -236,12 +333,24 @@ always_comb begin
|
|||||||
case (s_apb_dp_ctrl_paddr_reg_index)
|
case (s_apb_dp_ctrl_paddr_reg_index)
|
||||||
3'd0: begin
|
3'd0: begin
|
||||||
queue_mem_wr_enable = s_apb_dp_ctrl.pwdata[0];
|
queue_mem_wr_enable = s_apb_dp_ctrl.pwdata[0];
|
||||||
|
queue_mem_wr_arm = s_apb_dp_ctrl.pwdata[1];
|
||||||
queue_mem_wr_log_size = s_apb_dp_ctrl.pwdata[19:16];
|
queue_mem_wr_log_size = s_apb_dp_ctrl.pwdata[19:16];
|
||||||
queue_mem_wr_qtype = 3'(s_apb_dp_ctrl.pwdata[23:20]);
|
queue_mem_wr_qtype = 3'(s_apb_dp_ctrl.pwdata[23:20]);
|
||||||
|
|
||||||
|
queue_mem_wr_fire = 1'b0;
|
||||||
|
end
|
||||||
|
3'd1: begin
|
||||||
|
queue_mem_wr_dqn = s_apb_dp_ctrl.pwdata[DQN_W-1:0];
|
||||||
|
queue_mem_wr_cq_irq = s_apb_dp_ctrl.pwdata[31];
|
||||||
end
|
end
|
||||||
3'd1: queue_mem_wr_dqn = s_apb_dp_ctrl.pwdata[DQN_W-1:0];
|
|
||||||
3'd2: queue_mem_wr_prod_ptr = s_apb_dp_ctrl.pwdata[15:0];
|
3'd2: queue_mem_wr_prod_ptr = s_apb_dp_ctrl.pwdata[15:0];
|
||||||
3'd3: queue_mem_wr_cons_ptr = s_apb_dp_ctrl.pwdata[15:0];
|
3'd3: begin
|
||||||
|
queue_mem_wr_cons_ptr = s_apb_dp_ctrl.pwdata[15:0];
|
||||||
|
if (s_apb_dp_ctrl.pwdata[31]) begin
|
||||||
|
// rearm
|
||||||
|
queue_mem_wr_arm = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
3'd6: queue_mem_wr_base_addr[31:0] = s_apb_dp_ctrl.pwdata;
|
3'd6: queue_mem_wr_base_addr[31:0] = s_apb_dp_ctrl.pwdata;
|
||||||
3'd7: queue_mem_wr_base_addr[63:32] = s_apb_dp_ctrl.pwdata;
|
3'd7: queue_mem_wr_base_addr[63:32] = s_apb_dp_ctrl.pwdata;
|
||||||
default: begin end
|
default: begin end
|
||||||
@@ -251,17 +360,29 @@ always_comb begin
|
|||||||
case (s_apb_dp_ctrl_paddr_reg_index)
|
case (s_apb_dp_ctrl_paddr_reg_index)
|
||||||
3'd0: begin
|
3'd0: begin
|
||||||
s_apb_dp_ctrl_prdata_next[0] = queue_mem_rd_enable;
|
s_apb_dp_ctrl_prdata_next[0] = queue_mem_rd_enable;
|
||||||
|
s_apb_dp_ctrl_prdata_next[1] = (IS_CQ || IS_EQ) ? queue_mem_rd_arm : 1'b0;
|
||||||
s_apb_dp_ctrl_prdata_next[19:16] = queue_mem_rd_log_size;
|
s_apb_dp_ctrl_prdata_next[19:16] = queue_mem_rd_log_size;
|
||||||
s_apb_dp_ctrl_prdata_next[23:20] = 4'(queue_mem_rd_qtype);
|
s_apb_dp_ctrl_prdata_next[23:20] = QTYPE_EN ? 4'(queue_mem_rd_qtype) : '0;
|
||||||
end
|
end
|
||||||
3'd1: s_apb_dp_ctrl_prdata_next = 32'(queue_mem_rd_dqn);
|
3'd1: begin
|
||||||
3'd2: s_apb_dp_ctrl_prdata_next[15:0] = queue_mem_rd_prod_ptr;
|
s_apb_dp_ctrl_prdata_next[30:0] = 31'(queue_mem_rd_dqn);
|
||||||
3'd3: s_apb_dp_ctrl_prdata_next[15:0] = IS_CQ ? '0 : queue_mem_rd_cons_ptr;
|
s_apb_dp_ctrl_prdata_next[31] = (IS_CQ && CQ_IRQ) ? queue_mem_rd_cq_irq : 1'b0;
|
||||||
|
end
|
||||||
|
3'd2: s_apb_dp_ctrl_prdata_next = 32'(queue_mem_rd_prod_ptr);
|
||||||
|
3'd3: s_apb_dp_ctrl_prdata_next = 32'(queue_mem_rd_cons_ptr);
|
||||||
3'd6: s_apb_dp_ctrl_prdata_next = queue_mem_rd_base_addr[31:0];
|
3'd6: s_apb_dp_ctrl_prdata_next = queue_mem_rd_base_addr[31:0];
|
||||||
3'd7: s_apb_dp_ctrl_prdata_next = queue_mem_rd_base_addr[63:32];
|
3'd7: s_apb_dp_ctrl_prdata_next = queue_mem_rd_base_addr[63:32];
|
||||||
default: begin end
|
default: begin end
|
||||||
endcase
|
endcase
|
||||||
|
|
||||||
|
end else if (notify_req_valid && !notify_req_ready) begin
|
||||||
|
// notify request
|
||||||
|
notify_req_ready_next = 1'b1;
|
||||||
|
|
||||||
|
queue_mem_addr = notify_req_qn;
|
||||||
|
queue_mem_wr_fire = 1'b1;
|
||||||
|
|
||||||
|
queue_mem_wr_en = 1'b1;
|
||||||
end else if (req_valid && !req_ready && (!rsp_valid || rsp_ready)) begin
|
end else if (req_valid && !req_ready && (!rsp_valid || rsp_ready)) begin
|
||||||
// completion enqueue request
|
// completion enqueue request
|
||||||
req_ready_next = 1'b1;
|
req_ready_next = 1'b1;
|
||||||
@@ -271,13 +392,15 @@ always_comb begin
|
|||||||
rsp_qn_next = req_qn;
|
rsp_qn_next = req_qn;
|
||||||
rsp_dqn_next = queue_mem_rd_dqn;
|
rsp_dqn_next = queue_mem_rd_dqn;
|
||||||
rsp_error_next = !queue_mem_rd_enable || (QTYPE_EN && req_qtype != queue_mem_rd_qtype);
|
rsp_error_next = !queue_mem_rd_enable || (QTYPE_EN && req_qtype != queue_mem_rd_qtype);
|
||||||
if (IS_CQ) begin
|
if (IS_CQ || IS_EQ) begin
|
||||||
rsp_addr_next = queue_mem_rd_base_addr + DMA_ADDR_W'(16'(queue_mem_rd_prod_ptr & ({16{1'b1}} >> (16 - queue_mem_rd_log_size))) * QE_SIZE);
|
rsp_addr_next = queue_mem_rd_base_addr + DMA_ADDR_W'(16'(queue_mem_rd_prod_ptr & ({16{1'b1}} >> (16 - queue_mem_rd_log_size))) * QE_SIZE);
|
||||||
rsp_phase_tag_next = !queue_mem_rd_prod_ptr[queue_mem_rd_log_size];
|
rsp_phase_tag_next = !queue_mem_rd_prod_ptr[queue_mem_rd_log_size];
|
||||||
|
if (queue_mem_rd_status_full)
|
||||||
|
rsp_error_next = 1'b1;
|
||||||
queue_mem_wr_prod_ptr = queue_mem_rd_prod_ptr + 1;
|
queue_mem_wr_prod_ptr = queue_mem_rd_prod_ptr + 1;
|
||||||
end else begin
|
end else begin
|
||||||
rsp_addr_next = queue_mem_rd_base_addr + DMA_ADDR_W'(16'(queue_mem_rd_cons_ptr & ({16{1'b1}} >> (16 - queue_mem_rd_log_size))) * QE_SIZE);
|
rsp_addr_next = queue_mem_rd_base_addr + DMA_ADDR_W'(16'(queue_mem_rd_cons_ptr & ({16{1'b1}} >> (16 - queue_mem_rd_log_size))) * QE_SIZE);
|
||||||
if (queue_mem_rd_prod_ptr == queue_mem_rd_cons_ptr)
|
if (queue_mem_rd_status_empty)
|
||||||
rsp_error_next = 1'b1;
|
rsp_error_next = 1'b1;
|
||||||
queue_mem_wr_cons_ptr = queue_mem_rd_cons_ptr + 1;
|
queue_mem_wr_cons_ptr = queue_mem_rd_cons_ptr + 1;
|
||||||
end
|
end
|
||||||
@@ -286,6 +409,44 @@ always_comb begin
|
|||||||
if (!rsp_error_next) begin
|
if (!rsp_error_next) begin
|
||||||
queue_mem_wr_en = 1'b1;
|
queue_mem_wr_en = 1'b1;
|
||||||
end
|
end
|
||||||
|
end else begin
|
||||||
|
// scrub
|
||||||
|
|
||||||
|
queue_mem_addr = scrub_ptr_reg;
|
||||||
|
|
||||||
|
if ((IS_CQ || IS_EQ) && queue_mem_rd_enable && queue_mem_rd_arm && queue_mem_rd_fire) begin
|
||||||
|
if ((IS_CQ && !IS_EQ && (!CQ_IRQ || !queue_mem_rd_cq_irq)) || (QTYPE_EN && queue_mem_rd_qtype == QTYPE_CQ && (!CQ_IRQ || !queue_mem_rd_cq_irq))) begin
|
||||||
|
// event - only for CQ
|
||||||
|
if (!m_axis_event_tvalid_reg || m_axis_event.tready) begin
|
||||||
|
// fire in the hole
|
||||||
|
|
||||||
|
m_axis_event_tdata_next = '0;
|
||||||
|
m_axis_event_tdata_next[15:0] = '0; // rsvd
|
||||||
|
m_axis_event_tdata_next[31:16] = '0; // CPL
|
||||||
|
m_axis_event_tdata_next[63:32] = 32'(scrub_ptr_reg); // CQN
|
||||||
|
m_axis_event_tdest_next = EQN_W'(queue_mem_rd_dqn);
|
||||||
|
m_axis_event_tvalid_next = 1'b1;
|
||||||
|
|
||||||
|
queue_mem_wr_arm = 1'b0;
|
||||||
|
queue_mem_wr_fire = 1'b0;
|
||||||
|
queue_mem_wr_en = 1'b1;
|
||||||
|
end
|
||||||
|
end else if ((!IS_CQ && IS_EQ) || (IS_CQ && !IS_EQ && (CQ_IRQ && queue_mem_rd_cq_irq)) || (QTYPE_EN && (queue_mem_rd_qtype == QTYPE_EQ || (queue_mem_rd_qtype == QTYPE_CQ && (CQ_IRQ && queue_mem_rd_cq_irq))))) begin
|
||||||
|
// interrupt - EQ or CQ, but CQ requires config bit set to select interrupts
|
||||||
|
if (!m_axis_irq_tvalid_reg || m_axis_irq.tready) begin
|
||||||
|
// fire in the hole
|
||||||
|
|
||||||
|
m_axis_irq_irqn_next = IRQN_W'(queue_mem_rd_dqn);
|
||||||
|
m_axis_irq_tvalid_next = 1'b1;
|
||||||
|
|
||||||
|
queue_mem_wr_arm = 1'b0;
|
||||||
|
queue_mem_wr_fire = 1'b0;
|
||||||
|
queue_mem_wr_en = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scrub_ptr_next = scrub_ptr_reg + 1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -309,8 +470,22 @@ always @(posedge clk) begin
|
|||||||
rsp_error_reg <= rsp_error_next;
|
rsp_error_reg <= rsp_error_next;
|
||||||
rsp_valid_reg <= rsp_valid_next;
|
rsp_valid_reg <= rsp_valid_next;
|
||||||
|
|
||||||
|
notify_req_ready_reg <= notify_req_ready_next;
|
||||||
|
|
||||||
|
m_axis_irq_irqn_reg <= m_axis_irq_irqn_next;
|
||||||
|
m_axis_irq_tvalid_reg <= m_axis_irq_tvalid_next;
|
||||||
|
|
||||||
|
m_axis_event_tdata_reg <= m_axis_event_tdata_next;
|
||||||
|
m_axis_event_tdest_reg <= m_axis_event_tdest_next;
|
||||||
|
m_axis_event_tvalid_reg <= m_axis_event_tvalid_next;
|
||||||
|
|
||||||
|
scrub_ptr_reg <= scrub_ptr_next;
|
||||||
|
|
||||||
if (queue_mem_wr_en) begin
|
if (queue_mem_wr_en) begin
|
||||||
queue_enable_reg[queue_mem_addr] <= queue_mem_wr_enable;
|
queue_enable_reg[queue_mem_addr] <= queue_mem_wr_enable;
|
||||||
|
queue_mem_arm[queue_mem_addr] <= queue_mem_wr_arm;
|
||||||
|
queue_mem_fire[queue_mem_addr] <= queue_mem_wr_fire;
|
||||||
|
queue_mem_cq_irq[queue_mem_addr] <= queue_mem_wr_cq_irq;
|
||||||
queue_mem_qtype[queue_mem_addr] <= queue_mem_wr_qtype;
|
queue_mem_qtype[queue_mem_addr] <= queue_mem_wr_qtype;
|
||||||
queue_mem_dqn[queue_mem_addr] <= queue_mem_wr_dqn;
|
queue_mem_dqn[queue_mem_addr] <= queue_mem_wr_dqn;
|
||||||
queue_mem_log_size[queue_mem_addr] <= queue_mem_wr_log_size;
|
queue_mem_log_size[queue_mem_addr] <= queue_mem_wr_log_size;
|
||||||
@@ -332,6 +507,14 @@ always @(posedge clk) begin
|
|||||||
req_ready_reg <= 1'b0;
|
req_ready_reg <= 1'b0;
|
||||||
rsp_valid_reg <= 1'b0;
|
rsp_valid_reg <= 1'b0;
|
||||||
|
|
||||||
|
notify_req_ready_reg <= 1'b0;
|
||||||
|
|
||||||
|
m_axis_irq_tvalid_reg <= 1'b0;
|
||||||
|
|
||||||
|
m_axis_event_tvalid_reg <= 1'b0;
|
||||||
|
|
||||||
|
scrub_ptr_reg <= '0;
|
||||||
|
|
||||||
queue_enable_reg <= '0;
|
queue_enable_reg <= '0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ import logging
|
|||||||
import struct
|
import struct
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
|
import cocotb
|
||||||
from cocotb.queue import Queue
|
from cocotb.queue import Queue
|
||||||
|
from cocotb.triggers import RisingEdge
|
||||||
|
|
||||||
|
|
||||||
# Command opcodes
|
# Command opcodes
|
||||||
@@ -61,19 +63,18 @@ CNDM_CMD_PTP_FLG_OFFSET_FNS = 0x00000010
|
|||||||
CNDM_CMD_PTP_FLG_SET_PERIOD = 0x00000080
|
CNDM_CMD_PTP_FLG_SET_PERIOD = 0x00000080
|
||||||
|
|
||||||
|
|
||||||
class Cq:
|
class Eq:
|
||||||
def __init__(self, driver, port):
|
def __init__(self, driver, port):
|
||||||
self.driver = driver
|
self.driver = driver
|
||||||
self.log = driver.log
|
self.log = driver.log
|
||||||
|
|
||||||
self.port = port
|
self.port = port
|
||||||
self.irqn = None
|
|
||||||
|
|
||||||
self.log_size = 0
|
self.log_size = 0
|
||||||
self.size = 0
|
self.size = 0
|
||||||
self.size_mask = 0
|
self.size_mask = 0
|
||||||
self.stride = 0
|
self.stride = 0
|
||||||
self.cqn = None
|
self.eqn = None
|
||||||
self.enabled = False
|
self.enabled = False
|
||||||
|
|
||||||
self.buf_size = 0
|
self.buf_size = 0
|
||||||
@@ -81,23 +82,19 @@ class Cq:
|
|||||||
self.buf_dma = 0
|
self.buf_dma = 0
|
||||||
self.buf = None
|
self.buf = None
|
||||||
|
|
||||||
self.eq = None
|
self.irqn = None
|
||||||
|
|
||||||
self.src_ring = None
|
self.cq_table = {}
|
||||||
self.handler = None
|
|
||||||
|
|
||||||
self.cons_ptr = None
|
self.cons_ptr = None
|
||||||
|
|
||||||
self.db_offset = None
|
self.db_offset = None
|
||||||
|
|
||||||
self.hw_regs = self.driver.hw_regs
|
self.hw_regs = self.driver.hw_regs
|
||||||
|
|
||||||
async def open(self, irqn, size):
|
async def open(self, irqn, size):
|
||||||
if self.cqn is not None:
|
if self.eqn is not None:
|
||||||
raise Exception("Already open")
|
raise Exception("Already open")
|
||||||
|
|
||||||
self.irqn = irqn
|
|
||||||
|
|
||||||
self.log_size = size.bit_length() - 1
|
self.log_size = size.bit_length() - 1
|
||||||
self.size = 2**self.log_size
|
self.size = 2**self.log_size
|
||||||
self.size_mask = self.size-1
|
self.size_mask = self.size-1
|
||||||
@@ -112,13 +109,177 @@ class Cq:
|
|||||||
|
|
||||||
self.cons_ptr = 0
|
self.cons_ptr = 0
|
||||||
|
|
||||||
|
self.irqn = irqn
|
||||||
|
|
||||||
|
self.cq_table = {}
|
||||||
|
|
||||||
|
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLQQLLLL",
|
||||||
|
0, # rsvd
|
||||||
|
CNDM_CMD_OP_CREATE_EQ, # opcode
|
||||||
|
0x00000000, # flags
|
||||||
|
self.port.index, # port
|
||||||
|
0, # eqn
|
||||||
|
self.irqn, # irqn
|
||||||
|
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.eqn = rsp_unpacked[4]
|
||||||
|
self.db_offset = rsp_unpacked[8]
|
||||||
|
|
||||||
|
if self.db_offset == 0:
|
||||||
|
self.eqn = None
|
||||||
|
self.db_offset = None
|
||||||
|
self.log.error("Failed to allocate EQ")
|
||||||
|
return
|
||||||
|
|
||||||
|
await self.write_cons_ptr_arm()
|
||||||
|
|
||||||
|
self.log.info("Opened EQ %d", self.eqn)
|
||||||
|
self.log.info("Using doorbell at offset 0x%08x", self.db_offset)
|
||||||
|
|
||||||
|
self.enabled = True
|
||||||
|
|
||||||
|
async def close(self):
|
||||||
|
if self.eqn is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.enabled = False
|
||||||
|
|
||||||
|
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLQQLLLL",
|
||||||
|
0, # rsvd
|
||||||
|
CNDM_CMD_OP_DESTROY_EQ, # opcode
|
||||||
|
0x00000000, # flags
|
||||||
|
self.port.index, # port
|
||||||
|
self.eqn, # eqn
|
||||||
|
0, # irqn
|
||||||
|
0, # pd
|
||||||
|
0, # size
|
||||||
|
0, # dboffs
|
||||||
|
0, # base addr
|
||||||
|
0, # ptr2
|
||||||
|
0, # prod_ptr
|
||||||
|
0, # cons_ptr
|
||||||
|
0, # rsvd
|
||||||
|
0, # rsvd
|
||||||
|
))
|
||||||
|
|
||||||
|
self.eqn = None
|
||||||
|
|
||||||
|
# TODO free buffer
|
||||||
|
|
||||||
|
def attach_cq(self, cq):
|
||||||
|
self.cq_table[cq.cqn] = cq
|
||||||
|
|
||||||
|
def detach_cq(self, cq):
|
||||||
|
del self.cq_table[cq.cqn]
|
||||||
|
|
||||||
|
async def write_cons_ptr(self):
|
||||||
|
await self.hw_regs.write_dword(self.db_offset, self.cons_ptr & 0xffff)
|
||||||
|
|
||||||
|
async def write_cons_ptr_arm(self):
|
||||||
|
await self.hw_regs.write_dword(self.db_offset, (self.cons_ptr & 0xffff) | 0x80000000)
|
||||||
|
|
||||||
|
async def process_eq(self):
|
||||||
|
self.log.info("Process EQ")
|
||||||
|
|
||||||
|
eq_cons_ptr = self.cons_ptr
|
||||||
|
eq_index = eq_cons_ptr & self.size_mask
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# event_data = struct.unpack_from("<HHLLLLLLL", self.buf, eq_index*self.stride)
|
||||||
|
event_data = struct.unpack_from("<HHLLL", self.buf, eq_index*self.stride)
|
||||||
|
|
||||||
|
self.log.info("EQ %d index %d data: %s", self.eqn, eq_index, repr(event_data))
|
||||||
|
|
||||||
|
if bool(event_data[-1] & 0x80000000) == bool(eq_cons_ptr & self.size):
|
||||||
|
self.log.info("EQ %d empty", self.eqn)
|
||||||
|
break
|
||||||
|
|
||||||
|
if event_data[1] == 0x0000:
|
||||||
|
# completion
|
||||||
|
self.log.info("Event from CQ %d", event_data[2])
|
||||||
|
cq = self.cq_table[event_data[2]]
|
||||||
|
await cq.handler(cq)
|
||||||
|
|
||||||
|
eq_cons_ptr += 1
|
||||||
|
eq_index = eq_cons_ptr & self.size_mask
|
||||||
|
|
||||||
|
self.cons_ptr = eq_cons_ptr
|
||||||
|
await self.write_cons_ptr_arm()
|
||||||
|
|
||||||
|
|
||||||
|
class Cq:
|
||||||
|
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.stride = 0
|
||||||
|
self.cqn = None
|
||||||
|
self.enabled = False
|
||||||
|
|
||||||
|
self.buf_size = 0
|
||||||
|
self.buf_region = None
|
||||||
|
self.buf_dma = 0
|
||||||
|
self.buf = None
|
||||||
|
|
||||||
|
self.eq = None
|
||||||
|
self.irqn = None
|
||||||
|
|
||||||
|
self.src_ring = None
|
||||||
|
self.handler = None
|
||||||
|
|
||||||
|
self.cons_ptr = None
|
||||||
|
|
||||||
|
self.db_offset = None
|
||||||
|
self.hw_regs = self.driver.hw_regs
|
||||||
|
|
||||||
|
async def open(self, eq, size):
|
||||||
|
if self.cqn 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.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
|
||||||
|
|
||||||
|
if isinstance(eq, Eq):
|
||||||
|
self.eq = eq
|
||||||
|
dqn = eq.eqn
|
||||||
|
else:
|
||||||
|
self.irqn = eq
|
||||||
|
dqn = eq | 0x80000000
|
||||||
|
|
||||||
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLQQLLLL",
|
rsp = await self.driver.exec_cmd(struct.pack("<HHLLLLLLLQQLLLL",
|
||||||
0, # rsvd
|
0, # rsvd
|
||||||
CNDM_CMD_OP_CREATE_CQ, # opcode
|
CNDM_CMD_OP_CREATE_CQ, # opcode
|
||||||
0x00000000, # flags
|
0x00000000, # flags
|
||||||
self.port.index, # port
|
self.port.index, # port
|
||||||
0, # cqn
|
0, # cqn
|
||||||
self.irqn, # eqn
|
dqn, # eqn
|
||||||
0, # pd
|
0, # pd
|
||||||
self.log_size, # size
|
self.log_size, # size
|
||||||
0, # dboffs
|
0, # dboffs
|
||||||
@@ -141,7 +302,13 @@ class Cq:
|
|||||||
self.log.error("Failed to allocate CQ")
|
self.log.error("Failed to allocate CQ")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if self.eq:
|
||||||
|
self.eq.attach_cq(self)
|
||||||
|
|
||||||
|
await self.write_cons_ptr_arm()
|
||||||
|
|
||||||
self.log.info("Opened CQ %d", self.cqn)
|
self.log.info("Opened CQ %d", self.cqn)
|
||||||
|
self.log.info("Using doorbell at offset 0x%08x", self.db_offset)
|
||||||
|
|
||||||
self.enabled = True
|
self.enabled = True
|
||||||
|
|
||||||
@@ -173,6 +340,12 @@ class Cq:
|
|||||||
|
|
||||||
# TODO free buffer
|
# TODO free buffer
|
||||||
|
|
||||||
|
async def write_cons_ptr(self):
|
||||||
|
await self.hw_regs.write_dword(self.db_offset, self.cons_ptr & 0xffff)
|
||||||
|
|
||||||
|
async def write_cons_ptr_arm(self):
|
||||||
|
await self.hw_regs.write_dword(self.db_offset, (self.cons_ptr & 0xffff) | 0x80000000)
|
||||||
|
|
||||||
|
|
||||||
class Sq:
|
class Sq:
|
||||||
def __init__(self, driver, port):
|
def __init__(self, driver, port):
|
||||||
@@ -203,7 +376,6 @@ class Sq:
|
|||||||
self.bytes = 0
|
self.bytes = 0
|
||||||
|
|
||||||
self.db_offset = None
|
self.db_offset = None
|
||||||
|
|
||||||
self.hw_regs = self.driver.hw_regs
|
self.hw_regs = self.driver.hw_regs
|
||||||
|
|
||||||
async def open(self, cq, size):
|
async def open(self, cq, size):
|
||||||
@@ -261,6 +433,7 @@ class Sq:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.log.info("Opened SQ %d (CQ %d)", self.sqn, cq.cqn)
|
self.log.info("Opened SQ %d (CQ %d)", self.sqn, cq.cqn)
|
||||||
|
self.log.info("Using doorbell at offset 0x%08x", self.db_offset)
|
||||||
|
|
||||||
self.enabled = True
|
self.enabled = True
|
||||||
|
|
||||||
@@ -292,6 +465,15 @@ class Sq:
|
|||||||
|
|
||||||
# TODO free buffer
|
# TODO free buffer
|
||||||
|
|
||||||
|
def is_ring_empty(self):
|
||||||
|
return self.prod_ptr == self.cons_ptr
|
||||||
|
|
||||||
|
def is_ring_full(self):
|
||||||
|
return ((self.prod_ptr - self.cons_ptr) & 0xffffffff) > self.size
|
||||||
|
|
||||||
|
async def write_prod_ptr(self):
|
||||||
|
await self.hw_regs.write_dword(self.db_offset, self.prod_ptr & 0xffff)
|
||||||
|
|
||||||
async def start_xmit(self, data):
|
async def start_xmit(self, data):
|
||||||
headroom = 10
|
headroom = 10
|
||||||
tx_buf = self.driver.alloc_pkt()
|
tx_buf = self.driver.alloc_pkt()
|
||||||
@@ -301,7 +483,7 @@ class Sq:
|
|||||||
struct.pack_into('<xxxxLQ', self.buf, 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.tx_info[index] = tx_buf
|
||||||
self.prod_ptr += 1
|
self.prod_ptr += 1
|
||||||
await self.hw_regs.write_dword(self.db_offset, self.prod_ptr & 0xffff)
|
await self.write_prod_ptr()
|
||||||
|
|
||||||
def free_tx_desc(self, index):
|
def free_tx_desc(self, index):
|
||||||
pkt = self.tx_info[index]
|
pkt = self.tx_info[index]
|
||||||
@@ -309,7 +491,7 @@ class Sq:
|
|||||||
self.tx_info[index] = None
|
self.tx_info[index] = None
|
||||||
|
|
||||||
def free_tx_buf(self):
|
def free_tx_buf(self):
|
||||||
while self.cons_ptr != self.txq_prod:
|
while not self.is_ring_empty():
|
||||||
index = self.cons_ptr & self.size_mask
|
index = self.cons_ptr & self.size_mask
|
||||||
self.free_tx_desc(index)
|
self.free_tx_desc(index)
|
||||||
self.cons_ptr += 1
|
self.cons_ptr += 1
|
||||||
@@ -345,6 +527,8 @@ class Sq:
|
|||||||
cq.cons_ptr = cq_cons_ptr
|
cq.cons_ptr = cq_cons_ptr
|
||||||
sq.cons_ptr = cons_ptr
|
sq.cons_ptr = cons_ptr
|
||||||
|
|
||||||
|
await cq.write_cons_ptr_arm()
|
||||||
|
|
||||||
|
|
||||||
class Rq:
|
class Rq:
|
||||||
def __init__(self, driver, port):
|
def __init__(self, driver, port):
|
||||||
@@ -375,7 +559,6 @@ class Rq:
|
|||||||
self.bytes = 0
|
self.bytes = 0
|
||||||
|
|
||||||
self.db_offset = None
|
self.db_offset = None
|
||||||
|
|
||||||
self.hw_regs = self.driver.hw_regs
|
self.hw_regs = self.driver.hw_regs
|
||||||
|
|
||||||
async def open(self, cq, size):
|
async def open(self, cq, size):
|
||||||
@@ -433,6 +616,7 @@ class Rq:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.log.info("Opened RQ %d (CQ %d)", self.rqn, cq.cqn)
|
self.log.info("Opened RQ %d (CQ %d)", self.rqn, cq.cqn)
|
||||||
|
self.log.info("Using doorbell at offset 0x%08x", self.db_offset)
|
||||||
|
|
||||||
self.enabled = True
|
self.enabled = True
|
||||||
|
|
||||||
@@ -466,13 +650,22 @@ class Rq:
|
|||||||
|
|
||||||
# TODO free buffer
|
# TODO free buffer
|
||||||
|
|
||||||
|
def is_ring_empty(self):
|
||||||
|
return self.prod_ptr == self.cons_ptr
|
||||||
|
|
||||||
|
def is_ring_full(self):
|
||||||
|
return ((self.prod_ptr - self.cons_ptr) & 0xffffffff) > self.size
|
||||||
|
|
||||||
|
async def write_prod_ptr(self):
|
||||||
|
await self.hw_regs.write_dword(self.db_offset, self.prod_ptr & 0xffff)
|
||||||
|
|
||||||
def free_rx_desc(self, index):
|
def free_rx_desc(self, index):
|
||||||
pkt = self.rx_info[index]
|
pkt = self.rx_info[index]
|
||||||
self.driver.free_pkt(pkt)
|
self.driver.free_pkt(pkt)
|
||||||
self.rx_info[index] = None
|
self.rx_info[index] = None
|
||||||
|
|
||||||
def free_rx_buf(self):
|
def free_rx_buf(self):
|
||||||
while self.cons_ptr != self.prod_ptr:
|
while not self.is_ring_empty():
|
||||||
index = self.cons_ptr & self.size_mask
|
index = self.cons_ptr & self.size_mask
|
||||||
self.free_rx_desc(index)
|
self.free_rx_desc(index)
|
||||||
self.cons_ptr += 1
|
self.cons_ptr += 1
|
||||||
@@ -496,7 +689,7 @@ class Rq:
|
|||||||
self.prepare_rx_desc(self.prod_ptr & self.size_mask)
|
self.prepare_rx_desc(self.prod_ptr & self.size_mask)
|
||||||
self.prod_ptr += 1
|
self.prod_ptr += 1
|
||||||
|
|
||||||
await self.hw_regs.write_dword(self.db_offset, self.prod_ptr & 0xffff)
|
await self.write_prod_ptr()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def process_rx_cq(cq):
|
async def process_rx_cq(cq):
|
||||||
@@ -537,6 +730,7 @@ class Rq:
|
|||||||
rq.cons_ptr = cons_ptr
|
rq.cons_ptr = cons_ptr
|
||||||
|
|
||||||
await rq.refill_rx_buffers()
|
await rq.refill_rx_buffers()
|
||||||
|
await cq.write_cons_ptr_arm()
|
||||||
|
|
||||||
|
|
||||||
class Port:
|
class Port:
|
||||||
@@ -546,6 +740,9 @@ class Port:
|
|||||||
self.index = index
|
self.index = index
|
||||||
self.hw_regs = driver.hw_regs
|
self.hw_regs = driver.hw_regs
|
||||||
|
|
||||||
|
self.eq_count = 1
|
||||||
|
self.eq = []
|
||||||
|
|
||||||
self.rxq_count = 1
|
self.rxq_count = 1
|
||||||
self.rxq = []
|
self.rxq = []
|
||||||
|
|
||||||
@@ -555,12 +752,17 @@ class Port:
|
|||||||
self.rx_queue = Queue()
|
self.rx_queue = Queue()
|
||||||
|
|
||||||
async def init(self):
|
async def init(self):
|
||||||
|
for k in range(self.eq_count):
|
||||||
|
eq = Eq(self.driver, self)
|
||||||
|
await eq.open(self.index, 256)
|
||||||
|
self.eq.append(eq)
|
||||||
|
|
||||||
await self.open()
|
await self.open()
|
||||||
|
|
||||||
async def open(self):
|
async def open(self):
|
||||||
for k in range(self.rxq_count):
|
for k in range(self.rxq_count):
|
||||||
cq = Cq(self.driver, self)
|
cq = Cq(self.driver, self)
|
||||||
await cq.open(self.index, 256)
|
await cq.open(self.eq[0], 256)
|
||||||
|
|
||||||
q = Rq(self.driver, self)
|
q = Rq(self.driver, self)
|
||||||
await q.open(cq, 256)
|
await q.open(cq, 256)
|
||||||
@@ -569,7 +771,7 @@ class Port:
|
|||||||
|
|
||||||
for k in range(self.txq_count):
|
for k in range(self.txq_count):
|
||||||
cq = Cq(self.driver, self)
|
cq = Cq(self.driver, self)
|
||||||
await cq.open(self.index, 256)
|
await cq.open(self.eq[0], 256)
|
||||||
|
|
||||||
q = Sq(self.driver, self)
|
q = Sq(self.driver, self)
|
||||||
await q.open(cq, 256)
|
await q.open(cq, 256)
|
||||||
@@ -585,12 +787,36 @@ class Port:
|
|||||||
async def recv_nowait(self):
|
async def recv_nowait(self):
|
||||||
return self.rx_queue.get_nowait()
|
return self.rx_queue.get_nowait()
|
||||||
|
|
||||||
async def interrupt_handler(self):
|
|
||||||
self.log.info("Interrupt")
|
class Interrupt:
|
||||||
for q in self.rxq:
|
def __init__(self, index, handler=None):
|
||||||
await q.cq.handler(q.cq)
|
self.index = index
|
||||||
for q in self.txq:
|
self.queue = Queue()
|
||||||
await q.cq.handler(q.cq)
|
self.handler = handler
|
||||||
|
self.signal = None
|
||||||
|
|
||||||
|
cocotb.start_soon(self._run())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_edge(cls, index, signal, handler=None):
|
||||||
|
obj = cls(index, handler)
|
||||||
|
obj.signal = signal
|
||||||
|
cocotb.start_soon(obj._run_edge())
|
||||||
|
return obj
|
||||||
|
|
||||||
|
async def interrupt(self):
|
||||||
|
self.queue.put_nowait(None)
|
||||||
|
|
||||||
|
async def _run(self):
|
||||||
|
while True:
|
||||||
|
await self.queue.get()
|
||||||
|
if self.handler:
|
||||||
|
await self.handler(self.index)
|
||||||
|
|
||||||
|
async def _run_edge(self):
|
||||||
|
while True:
|
||||||
|
await RisingEdge(self.signal)
|
||||||
|
await self.interrupt()
|
||||||
|
|
||||||
|
|
||||||
class Driver:
|
class Driver:
|
||||||
@@ -601,6 +827,8 @@ class Driver:
|
|||||||
self.pool = None
|
self.pool = None
|
||||||
self.hw_regs = None
|
self.hw_regs = None
|
||||||
|
|
||||||
|
self.irq_list = []
|
||||||
|
|
||||||
self.port_count = None
|
self.port_count = None
|
||||||
|
|
||||||
self.ports = []
|
self.ports = []
|
||||||
@@ -656,6 +884,12 @@ class Driver:
|
|||||||
|
|
||||||
self.hw_regs = dev.bar_window[0]
|
self.hw_regs = dev.bar_window[0]
|
||||||
|
|
||||||
|
# set up MSI
|
||||||
|
for index in range(32):
|
||||||
|
irq = Interrupt(index, self.interrupt_handler)
|
||||||
|
self.dev.request_irq(index, irq.interrupt)
|
||||||
|
self.irq_list.append(irq)
|
||||||
|
|
||||||
await self.init_common()
|
await self.init_common()
|
||||||
|
|
||||||
async def init_common(self):
|
async def init_common(self):
|
||||||
@@ -853,7 +1087,6 @@ class Driver:
|
|||||||
for k in range(self.port_count):
|
for k in range(self.port_count):
|
||||||
port = Port(self, k)
|
port = Port(self, k)
|
||||||
await port.init()
|
await port.init()
|
||||||
self.dev.request_irq(k, port.interrupt_handler)
|
|
||||||
|
|
||||||
self.ports.append(port)
|
self.ports.append(port)
|
||||||
|
|
||||||
@@ -912,6 +1145,24 @@ class Driver:
|
|||||||
a[k] = await self.hw_regs.read_dword(0x10040+k*4)
|
a[k] = await self.hw_regs.read_dword(0x10040+k*4)
|
||||||
return a.tobytes()
|
return a.tobytes()
|
||||||
|
|
||||||
|
async def interrupt_handler(self, irqn):
|
||||||
|
self.log.info("Interrupt handler start (IRQ %d)", irqn)
|
||||||
|
for p in self.ports:
|
||||||
|
if p.eq:
|
||||||
|
# using EQs
|
||||||
|
for eq in p.eq:
|
||||||
|
if eq.irqn == irqn:
|
||||||
|
await eq.process_eq()
|
||||||
|
else:
|
||||||
|
# using IRQs directly from CQs
|
||||||
|
for q in p.rxq:
|
||||||
|
if q.cq.irqn == irqn:
|
||||||
|
await q.cq.handler(q.cq)
|
||||||
|
for q in p.txq:
|
||||||
|
if q.cq.irqn == irqn:
|
||||||
|
await q.cq.handler(q.cq)
|
||||||
|
self.log.info("Interrupt handler end (IRQ %d)", irqn)
|
||||||
|
|
||||||
def alloc_pkt(self):
|
def alloc_pkt(self):
|
||||||
if self.free_packets:
|
if self.free_packets:
|
||||||
return self.free_packets.popleft()
|
return self.free_packets.popleft()
|
||||||
|
|||||||
Reference in New Issue
Block a user