mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
enic: add admin RQ buffer management
The admin receive queue needs pre-posted DMA buffers for incoming mailbox messages from VFs. Each buffer is a kzalloc'd region mapped for DMA (2048 bytes, sufficient for any MBOX message). Zeroing on allocation ensures that if a completion reports more bytes than hardware actually DMA-wrote, the parser reads zero padding rather than uninitialised heap contents. Add enic_admin_rq_fill(gfp) 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. The gfp_t parameter lets the caller pass the allocation context; both current callers -- channel open and the CQ-poll work handler that refills after draining (added in the next patch) -- run in process context and use GFP_KERNEL. Signed-off-by: Satish Kharat <satishkh@cisco.com> Link: https://patch.msgid.link/20260812-enic-sriov-v2-admin-channel-v2-v13-3-b3809e448aba@cisco.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
3258931d40
commit
a0da4ea750
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_wq.h"
|
||||
|
|
@ -34,10 +35,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, gfp_t gfp)
|
||||
{
|
||||
struct vnic_rq *rq = &enic->admin_rq;
|
||||
struct rq_enet_desc *desc;
|
||||
dma_addr_t dma_addr;
|
||||
void *buf;
|
||||
|
||||
buf = kzalloc(ENIC_ADMIN_BUF_SIZE, gfp);
|
||||
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, gfp_t gfp)
|
||||
{
|
||||
struct vnic_rq *rq = &enic->admin_rq;
|
||||
int err;
|
||||
|
||||
while (vnic_rq_desc_avail(rq) > 0) {
|
||||
err = enic_admin_rq_post_one(enic, gfp);
|
||||
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)
|
||||
|
|
@ -171,6 +225,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, GFP_KERNEL);
|
||||
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, QP_ENABLE);
|
||||
if (err) {
|
||||
netdev_err(enic->netdev,
|
||||
|
|
@ -188,6 +249,7 @@ int enic_admin_channel_open(struct enic *enic)
|
|||
netdev_warn(enic->netdev, "Failed to disable admin WQ\n");
|
||||
if (vnic_rq_disable(&enic->admin_rq))
|
||||
netdev_warn(enic->netdev, "Failed to disable admin RQ\n");
|
||||
enic_admin_rq_drain(enic);
|
||||
enic_admin_free_resources(enic);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -218,7 +280,7 @@ void enic_admin_channel_close(struct enic *enic)
|
|||
"Failed to disable admin RQ: %d\n", err);
|
||||
|
||||
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]);
|
||||
enic_admin_free_resources(enic);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user