From: Satish Kharat The admin receive queue needs pre-posted DMA buffers for incoming mailbox messages from VFs. Each buffer is a kmalloc'd region mapped for DMA (2048 bytes, sufficient for any MBOX message). Add enic_admin_rq_fill() to post buffers at open time, and enic_admin_rq_drain() to unmap and free them at close time. Wire both into the admin channel open/close paths. Signed-off-by: Satish Kharat --- drivers/net/ethernet/cisco/enic/enic_admin.c | 66 +++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_admin.c b/drivers/net/ethernet/cisco/enic/enic_admin.c index d1abe6a50095..a8fcd5f116d1 100644 --- a/drivers/net/ethernet/cisco/enic/enic_admin.c +++ b/drivers/net/ethernet/cisco/enic/enic_admin.c @@ -3,6 +3,7 @@ #include #include +#include #include "vnic_dev.h" #include "vnic_wq.h" @@ -23,10 +24,63 @@ static void enic_admin_wq_buf_clean(struct vnic_wq *wq, { } -/* No-op: admin RQ buffer teardown is handled in enic_admin_channel_close */ static void enic_admin_rq_buf_clean(struct vnic_rq *rq, struct vnic_rq_buf *buf) { + struct enic *enic = vnic_dev_priv(rq->vdev); + + if (!buf->os_buf) + return; + + dma_unmap_single(&enic->pdev->dev, buf->dma_addr, buf->len, + DMA_FROM_DEVICE); + kfree(buf->os_buf); + buf->os_buf = NULL; +} + +static int enic_admin_rq_post_one(struct enic *enic) +{ + struct vnic_rq *rq = &enic->admin_rq; + struct rq_enet_desc *desc; + dma_addr_t dma_addr; + void *buf; + + buf = kmalloc(ENIC_ADMIN_BUF_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + dma_addr = dma_map_single(&enic->pdev->dev, buf, ENIC_ADMIN_BUF_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(&enic->pdev->dev, dma_addr)) { + kfree(buf); + return -ENOMEM; + } + + desc = vnic_rq_next_desc(rq); + rq_enet_desc_enc(desc, (u64)dma_addr | VNIC_PADDR_TARGET, + RQ_ENET_TYPE_ONLY_SOP, ENIC_ADMIN_BUF_SIZE); + vnic_rq_post(rq, buf, 0, dma_addr, ENIC_ADMIN_BUF_SIZE, 0); + + return 0; +} + +static int enic_admin_rq_fill(struct enic *enic) +{ + struct vnic_rq *rq = &enic->admin_rq; + int err; + + while (vnic_rq_desc_avail(rq) > 0) { + err = enic_admin_rq_post_one(enic); + if (err) + return err; + } + + return 0; +} + +static void enic_admin_rq_drain(struct enic *enic) +{ + vnic_rq_clean(&enic->admin_rq, enic_admin_rq_buf_clean); } static int enic_admin_qp_type_set(struct enic *enic, u32 enable) @@ -138,6 +192,13 @@ int enic_admin_channel_open(struct enic *enic) vnic_wq_enable(&enic->admin_wq); vnic_rq_enable(&enic->admin_rq); + err = enic_admin_rq_fill(enic); + if (err) { + netdev_err(enic->netdev, + "Failed to fill admin RQ buffers: %d\n", err); + goto disable_queues; + } + err = enic_admin_qp_type_set(enic, 1); if (err) { netdev_err(enic->netdev, @@ -151,6 +212,7 @@ int enic_admin_channel_open(struct enic *enic) vnic_wq_disable(&enic->admin_wq); vnic_rq_disable(&enic->admin_rq); enic_admin_qp_type_set(enic, 0); + enic_admin_rq_drain(enic); enic_admin_free_resources(enic); return err; } @@ -166,7 +228,7 @@ void enic_admin_channel_close(struct enic *enic) enic_admin_qp_type_set(enic, 0); vnic_wq_clean(&enic->admin_wq, enic_admin_wq_buf_clean); - vnic_rq_clean(&enic->admin_rq, enic_admin_rq_buf_clean); + enic_admin_rq_drain(enic); vnic_cq_clean(&enic->admin_cq[0]); vnic_cq_clean(&enic->admin_cq[1]); vnic_intr_clean(&enic->admin_intr); -- 2.43.0