[PATCH net v2 2/2] enic: require DEVCMD2 and set the V2 VF mailbox source
flat view
DORMANTno replies
From: Satish Kharat <satishkh@cisco.com>
Date: 2026-10-22 11:57:46
Subsystem:
cisco vic ethernet nic driver, networking drivers, the rest · Maintainers:
Satish Kharat, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
V2 VFs currently transmit mailbox source zero. A deployed async PF checks
that field against the sender identity obtained from CQ metadata, so VFs
other than VF zero cannot register with that PF.
Require DEVCMD2 for V2 PF support and V2 VF probe, preserving the DEVCMD1
fallback for ordinary PF Ethernet, V1 and usNIC. Query CMD_SRIOV_STATS_GET
after the admin channel is enabled and before the first VF request. Its
logical VF index is the zero-based index used by the CQ metadata protocol;
validate its version and sentinel, then use it as the VF mailbox source.
Keep the coherent statistics target for the vNIC lifetime. Extend the
DEVCMD2 transport with an optional per-call observation of NOT_POSTED,
POSTED or COMPLETED. A posted statistics command without a result leaves
its target unresolved. A later blocking QP command result fences that
target through command ordering, including a firmware error result.
Pre-submission errors, posted timeouts and NOWAIT posting do not establish
completion. This keeps transport completion separate from command success
and admin WQ/RQ queue-stop proof.
On an unresolved probe failure retain the inert control owner and target
through final containment instead of freeing memory which the command may
still write. Refuse reuse of an unresolved statistics target.
Fixes: 1f0c856b5963 ("enic: add MBOX core send and receive for admin channel")
Signed-off-by: Satish Kharat <satishkh@cisco.com>
---
drivers/net/ethernet/cisco/enic/enic.h | 5 ++
drivers/net/ethernet/cisco/enic/enic_admin.c | 15 ++++-
drivers/net/ethernet/cisco/enic/enic_dev.c | 21 +++++++
drivers/net/ethernet/cisco/enic/enic_dev.h | 2 +
drivers/net/ethernet/cisco/enic/enic_main.c | 45 +++++++++++++-
drivers/net/ethernet/cisco/enic/enic_mbox.c | 12 +++-
drivers/net/ethernet/cisco/enic/vnic_dev.c | 85 ++++++++++++++++++++++++++-
drivers/net/ethernet/cisco/enic/vnic_dev.h | 15 +++++
drivers/net/ethernet/cisco/enic/vnic_devcmd.h | 34 +++++++++++
9 files changed, 226 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h
index 4bf30d78383b..77c251bc3c99 100644
--- a/drivers/net/ethernet/cisco/enic/enic.h
+++ b/drivers/net/ethernet/cisco/enic/enic.h@@ -271,6 +271,11 @@ struct enic { u16 num_vfs; enum enic_vf_type vf_type; bool vf_registered; + u16 vf_id; + /* A CMD_SRIOV_STATS_GET timeout leaves its persistent coherent target + * device-owned until a later serialized command completes. + */ + bool sriov_stats_dma_unresolved; u32 pf_cap_version; unsigned int enable_count; spinlock_t enic_api_lock;
diff --git a/drivers/net/ethernet/cisco/enic/enic_admin.c b/drivers/net/ethernet/cisco/enic/enic_admin.c
index 4325c6d9c30e..4eb17e88d368 100644
--- a/drivers/net/ethernet/cisco/enic/enic_admin.c
+++ b/drivers/net/ethernet/cisco/enic/enic_admin.c@@ -401,12 +401,23 @@ static void enic_admin_teardown_intr(struct enic *enic) static int enic_admin_qp_type_set(struct enic *enic, u32 enable) { + enum vnic_devcmd2_status status; u64 a0 = QP_TYPE_ADMIN, a1 = enable; int wait = 1000; int err; spin_lock_bh(&enic->devcmd_lock); - err = vnic_dev_cmd(enic->vdev, CMD_QP_TYPE_SET, &a0, &a1, wait); + if (vnic_dev_uses_devcmd2(enic->vdev)) { + err = vnic_dev_cmd2_status(enic->vdev, CMD_QP_TYPE_SET, + &a0, &a1, wait, &status); + /* Ordered completion fences the earlier statistics DMA target, + * including an error result. Admin queues still need RUNNING == 0. + */ + if (status == VNIC_DEVCMD2_COMPLETED) + WRITE_ONCE(enic->sriov_stats_dma_unresolved, false); + } else { + err = vnic_dev_cmd(enic->vdev, CMD_QP_TYPE_SET, &a0, &a1, wait); + } spin_unlock_bh(&enic->devcmd_lock); return err;
@@ -547,6 +558,8 @@ int enic_admin_channel_open(struct enic *enic) "Refusing to reopen poisoned admin channel\n"); return -EIO; } + if (READ_ONCE(enic->sriov_stats_dma_unresolved)) + return -EBUSY; /* Keep MBOX sends disabled for the entire open sequence. It is * cleared only after every resource is allocated and enabled below, * so any early error return here leaves sends disabled and a
diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.c b/drivers/net/ethernet/cisco/enic/enic_dev.c
index 659787f73cf1..3a5cdeca1048 100644
--- a/drivers/net/ethernet/cisco/enic/enic_dev.c
+++ b/drivers/net/ethernet/cisco/enic/enic_dev.c@@ -171,6 +171,27 @@ int enic_dev_intr_coal_timer_info(struct enic *enic) return err; } +int enic_dev_sriov_stats(struct enic *enic, + struct vnic_sriov_stats **stats) +{ + enum vnic_devcmd2_status status; + int err; + + *stats = NULL; + spin_lock_bh(&enic->devcmd_lock); + if (READ_ONCE(enic->sriov_stats_dma_unresolved)) { + err = -EBUSY; + goto unlock; + } + err = vnic_dev_sriov_stats(enic->vdev, stats, &status); + if (status == VNIC_DEVCMD2_POSTED) + WRITE_ONCE(enic->sriov_stats_dma_unresolved, true); +unlock: + spin_unlock_bh(&enic->devcmd_lock); + + return err; +} + /* rtnl lock is held */ int enic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid) {
diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.h b/drivers/net/ethernet/cisco/enic/enic_dev.h
index 698d0cb02064..4bd67578801f 100644
--- a/drivers/net/ethernet/cisco/enic/enic_dev.h
+++ b/drivers/net/ethernet/cisco/enic/enic_dev.h@@ -40,6 +40,8 @@ int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic); int enic_dev_enable(struct enic *enic); int enic_dev_disable(struct enic *enic); int enic_dev_intr_coal_timer_info(struct enic *enic); +int enic_dev_sriov_stats(struct enic *enic, + struct vnic_sriov_stats **stats); int enic_dev_status_to_errno(int devcmd_status); #endif /* _ENIC_DEV_H_ */
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index 838b6dc837ee..846221937ab1 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c@@ -2203,6 +2203,12 @@ static bool enic_has_admin_chan(struct enic *enic) (enic_sriov_enabled(enic) && enic->vf_type == ENIC_VF_TYPE_V2); } +static bool enic_control_dma_unresolved(struct enic *enic) +{ + return enic_admin_channel_is_quarantined(enic) || + READ_ONCE(enic->sriov_stats_dma_unresolved); +} + /* Re-establish the admin/MBOX channel after a reset has re-created the data * path. Mirrors the relevant part of the probe / SR-IOV-enable sequence: * reinitialise MBOX and reopen the channel, then for a VF re-run the PF
@@ -2878,6 +2884,12 @@ static void enic_sriov_detect_vf_type(struct enic *enic) if (enic->vf_type != ENIC_VF_TYPE_V2) return; + if (!vnic_dev_uses_devcmd2(enic->vdev)) { + dev_warn(&pdev->dev, + "SR-IOV V2 requires DEVCMD2; disabling V2 support\n"); + enic->vf_type = ENIC_VF_TYPE_NONE; + return; + } /* A successful command means firmware recognizes * VIC_FEATURE_SRIOV; supported_versions is available
@@ -3035,6 +3047,7 @@ enic_sriov_configure(struct pci_dev *pdev, int num_vfs) static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + struct vnic_sriov_stats *sriov_stats; struct device *dev = &pdev->dev; struct net_device *netdev; struct enic *enic;
@@ -3062,6 +3075,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) enic = netdev_priv(netdev); enic->netdev = netdev; enic->pdev = pdev; + WRITE_ONCE(enic->vf_id, ENIC_MBOX_DST_PF); spin_lock_init(&enic->vf_link_state_lock); /* Setup PCI resources
@@ -3129,6 +3143,12 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_out_vnic_unregister; + if (enic_is_sriov_vf_v2(enic) && + !vnic_dev_uses_devcmd2(enic->vdev)) { + dev_err(dev, "SR-IOV V2 VF requires DEVCMD2\n"); + err = -EOPNOTSUPP; + goto err_out_vnic_unregister; + } #ifdef CONFIG_PCI_IOV enic_sriov_detect_vf_type(enic);
@@ -3238,6 +3258,9 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * unmasks the admin interrupt so an early completion is not dropped. */ if (enic_is_sriov_vf_v2(enic)) { + u32 stats_ver; + u16 vf_id; + enic_mbox_init(enic); err = enic_admin_channel_open(enic); if (err) {
@@ -3245,6 +3268,23 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) "Failed to open admin channel: %d\n", err); goto err_out_dev_deinit; } + err = enic_dev_sriov_stats(enic, &sriov_stats); + if (err) { + dev_err(dev, "Failed to get SR-IOV statistics: %d\n", err); + goto err_out_admin_close; + } + /* Snapshot the coherent fields after the command's DMA barrier. */ + stats_ver = le32_to_cpu(sriov_stats->ver); + vf_id = le16_to_cpu(sriov_stats->vf_index); + if (stats_ver != VNIC_SRIOV_STATS_VERSION || + vf_id == ENIC_MBOX_DST_PF) { + dev_err(dev, + "Invalid SR-IOV statistics version %u VF index %#x\n", + stats_ver, vf_id); + err = -EINVAL; + goto err_out_admin_close; + } + WRITE_ONCE(enic->vf_id, vf_id); err = enic_mbox_vf_capability_check(enic); if (err) { dev_err(dev,
@@ -3257,6 +3297,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) "MBOX VF registration failed: %d\n", err); goto err_out_admin_close; } + dev_info(dev, "V2 VF registered, VF index %u\n", vf_id); } netif_set_real_num_tx_queues(netdev, enic->wq_count);
@@ -3412,7 +3453,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } #endif err_out_vnic_unregister: - if (enic_admin_channel_is_quarantined(enic)) { + if (enic_control_dma_unresolved(enic)) { /* Normal generic cleanup and CMD_CLOSE have already run. Retain * only the inert admin/control owners and their PCI reservation. */
@@ -3486,7 +3527,7 @@ static void enic_remove(struct pci_dev *pdev) enic_dev_deinit(enic); vnic_dev_close(enic->vdev); kfree(enic->pp); - if (enic_admin_channel_is_quarantined(enic)) { + if (enic_control_dma_unresolved(enic)) { /* All generic queues and CPU entry points followed ordinary * teardown. No admin buffer can return from the network stack. * Pin the PCI object for the reservation's owner-name pointer;
diff --git a/drivers/net/ethernet/cisco/enic/enic_mbox.c b/drivers/net/ethernet/cisco/enic/enic_mbox.c
index e106ee7d411d..1716da29eee7 100644
--- a/drivers/net/ethernet/cisco/enic/enic_mbox.c
+++ b/drivers/net/ethernet/cisco/enic/enic_mbox.c@@ -18,10 +18,17 @@ #define ENIC_MBOX_POLL_TIMEOUT_US 5000000 #define ENIC_MBOX_POLL_INTERVAL_US 100 -static void enic_mbox_fill_hdr(struct enic_mbox_hdr *hdr, u8 msg_type, +static void enic_mbox_fill_hdr(struct enic *enic, struct enic_mbox_hdr *hdr, + u8 msg_type, u16 dst_vnic_id, u16 msg_len, u64 msg_num) { + u16 src_vnic_id = ENIC_MBOX_DST_PF; + + if (enic_is_sriov_vf_v2(enic)) + src_vnic_id = READ_ONCE(enic->vf_id); + memset(hdr, 0, sizeof(*hdr)); + hdr->src_vnic_id = cpu_to_le16(src_vnic_id); hdr->dst_vnic_id = cpu_to_le16(dst_vnic_id); hdr->msg_type = msg_type; hdr->msg_len = cpu_to_le16(msg_len);
@@ -85,7 +92,8 @@ static int enic_mbox_send_msg_id(struct enic *enic, u8 msg_type, reply_expected = true; } - enic_mbox_fill_hdr(buf, msg_type, dst_vnic_id, total_len, msg_num); + enic_mbox_fill_hdr(enic, buf, msg_type, dst_vnic_id, total_len, + msg_num); if (payload_len) { void *dst = buf + sizeof(struct enic_mbox_hdr);
diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.c b/drivers/net/ethernet/cisco/enic/vnic_dev.c
index c8d657e97094..92eec1455ceb 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_dev.c
+++ b/drivers/net/ethernet/cisco/enic/vnic_dev.c@@ -287,8 +287,9 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, return -ETIMEDOUT; } -static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, - int wait) +static int _vnic_dev_cmd2_status(struct vnic_dev *vdev, + enum vnic_devcmd_cmd cmd, int wait, + enum vnic_devcmd2_status *status) { struct devcmd2_controller *dc2c = vdev->devcmd2; struct devcmd2_result *result;
@@ -298,6 +299,9 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, u32 fetch_index, new_posted; u32 posted = dc2c->posted; + if (status) + *status = VNIC_DEVCMD2_NOT_POSTED; + fetch_index = ioread32(&dc2c->wq_ctrl->fetch_index); if (fetch_index == 0xFFFFFFFF)
@@ -326,6 +330,8 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, wmb(); iowrite32(new_posted, &dc2c->wq_ctrl->posted_index); dc2c->posted = new_posted; + if (status) + *status = VNIC_DEVCMD2_POSTED; if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT) return 0;
@@ -340,7 +346,10 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, } for (delay = 0; delay < wait; delay++) { - if (result->color == color) { + if (READ_ONCE(result->color) == color) { + dma_rmb(); + if (status) + *status = VNIC_DEVCMD2_COMPLETED; if (result->error) { err = result->error; if (err != ERR_ECMDUNKNOWN ||
@@ -363,6 +372,31 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, return -ETIMEDOUT; } +static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, + int wait) +{ + return _vnic_dev_cmd2_status(vdev, cmd, wait, NULL); +} + +int vnic_dev_cmd2_status(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, + u64 *a0, u64 *a1, int wait, + enum vnic_devcmd2_status *status) +{ + int err; + + *status = VNIC_DEVCMD2_NOT_POSTED; + if (!vdev->devcmd2 || vdev->proxy != PROXY_NONE) + return -EOPNOTSUPP; + + memset(vdev->args, 0, sizeof(vdev->args)); + vdev->args[0] = *a0; + vdev->args[1] = *a1; + err = _vnic_dev_cmd2_status(vdev, cmd, wait, status); + *a0 = vdev->args[0]; + *a1 = vdev->args[1]; + return err; +} + static int vnic_dev_init_devcmd1(struct vnic_dev *vdev) { vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0);
@@ -1046,6 +1080,11 @@ void vnic_dev_unregister(struct vnic_dev *vdev) dma_free_coherent(&vdev->pdev->dev, sizeof(struct vnic_stats), vdev->stats, vdev->stats_pa); + if (vdev->sriov_stats) + dma_free_coherent(&vdev->pdev->dev, + sizeof(struct vnic_sriov_stats), + vdev->sriov_stats, + vdev->sriov_stats_pa); if (vdev->fw_info) dma_free_coherent(&vdev->pdev->dev, sizeof(struct vnic_devcmd_fw_info),
@@ -1088,6 +1127,11 @@ struct pci_dev *vnic_dev_get_pdev(struct vnic_dev *vdev) } EXPORT_SYMBOL(vnic_dev_get_pdev); +bool vnic_dev_uses_devcmd2(struct vnic_dev *vdev) +{ + return vdev->devcmd2; +} + int vnic_devcmd_init(struct vnic_dev *vdev) { void __iomem *res;
@@ -1295,3 +1339,38 @@ int vnic_dev_capable_rss_hash_type(struct vnic_dev *vdev, u8 *rss_hash_type) return 0; } + +int vnic_dev_sriov_stats(struct vnic_dev *vdev, + struct vnic_sriov_stats **stats, + enum vnic_devcmd2_status *status) +{ + u64 a0, a1; + int err; + + *stats = NULL; + *status = VNIC_DEVCMD2_NOT_POSTED; + if (!vdev->sriov_stats) { + vdev->sriov_stats = + dma_alloc_coherent(&vdev->pdev->dev, + sizeof(*vdev->sriov_stats), + &vdev->sriov_stats_pa, + GFP_ATOMIC); + if (!vdev->sriov_stats) + return -ENOMEM; + } + + memset(vdev->sriov_stats, 0, sizeof(*vdev->sriov_stats)); + a0 = vdev->sriov_stats_pa; + a1 = sizeof(*vdev->sriov_stats); + err = vnic_dev_cmd2_status(vdev, CMD_SRIOV_STATS_GET, &a0, &a1, + 1000, status); + if (!err) { + /* Order CPU reads from the coherent target after command + * completion. + */ + dma_rmb(); + *stats = vdev->sriov_stats; + } + + return err; +}
diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.h b/drivers/net/ethernet/cisco/enic/vnic_dev.h
index 7fdd8c661c99..6a4d7ce3b636 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_dev.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_dev.h@@ -93,6 +93,8 @@ struct vnic_dev { dma_addr_t linkstatus_pa; struct vnic_stats *stats; dma_addr_t stats_pa; + struct vnic_sriov_stats *sriov_stats; + dma_addr_t sriov_stats_pa; struct vnic_devcmd_fw_info *fw_info; dma_addr_t fw_info_pa; enum vnic_proxy_type proxy;
@@ -106,6 +108,12 @@ struct vnic_dev { struct vnic_stats; +enum vnic_devcmd2_status { + VNIC_DEVCMD2_NOT_POSTED, + VNIC_DEVCMD2_POSTED, + VNIC_DEVCMD2_COMPLETED, +}; + void *vnic_dev_priv(struct vnic_dev *vdev); unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, enum vnic_res_type type);
@@ -118,6 +126,9 @@ void vnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring); int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait); +int vnic_dev_cmd2_status(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, + u64 *a0, u64 *a1, int wait, + enum vnic_devcmd2_status *status); void vnic_dev_cmd_proxy_by_index_start(struct vnic_dev *vdev, u16 index); void vnic_dev_cmd_proxy_end(struct vnic_dev *vdev); int vnic_dev_fw_info(struct vnic_dev *vdev,
@@ -163,6 +174,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar, unsigned int num_bars); struct pci_dev *vnic_dev_get_pdev(struct vnic_dev *vdev); +bool vnic_dev_uses_devcmd2(struct vnic_dev *vdev); int vnic_dev_init_prov2(struct vnic_dev *vdev, u8 *buf, u32 len); int vnic_dev_enable2(struct vnic_dev *vdev, int active); int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status);
@@ -177,5 +189,8 @@ int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, u8 overlay, int vnic_dev_get_supported_feature_ver(struct vnic_dev *vdev, u8 feature, u64 *supported_versions, u64 *a1); int vnic_dev_capable_rss_hash_type(struct vnic_dev *vdev, u8 *rss_hash_type); +int vnic_dev_sriov_stats(struct vnic_dev *vdev, + struct vnic_sriov_stats **stats, + enum vnic_devcmd2_status *status); #endif /* _VNIC_DEV_H_ */
diff --git a/drivers/net/ethernet/cisco/enic/vnic_devcmd.h b/drivers/net/ethernet/cisco/enic/vnic_devcmd.h
index 90ca06691ebd..9f397df88c50 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_devcmd.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_devcmd.h@@ -461,6 +461,14 @@ enum vnic_devcmd_cmd { * in: (u32) a1 = enable (1) / disable (0) */ CMD_QP_TYPE_SET = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 97), + + /* + * Get SR-IOV capabilities, resource usage, and this function's logical + * VF index. + * in: (u64) a0 = DMA address of struct vnic_sriov_stats + * in: (u32) a1 = length of the buffer + */ + CMD_SRIOV_STATS_GET = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 98), }; #define QP_TYPE_ADMIN 0
@@ -468,6 +476,32 @@ enum vnic_devcmd_cmd { #define QP_ENABLE 1 #define QP_DISABLE 0 +#define VNIC_SRIOV_STATS_VERSION 1 + +struct vnic_sriov_stats { + __le32 ver; + u8 sriov_vlan_membership_cap; + u8 sriov_vlan_membership_enabled; + u8 sriov_rss_vf_full_cap; + u8 sriov_host_rx_stats; + __le32 ig_classifier0_tcam_cfg; + __le32 ig_classifier0_tcam_free; + __le32 eg_classifier0_tcam_cfg; + __le32 eg_classifier0_tcam_free; + __le32 ig_classifier1_tcam_cfg; + __le32 ig_classifier1_tcam_free; + __le32 eg_classifier1_tcam_cfg; + __le32 eg_classifier1_tcam_free; + __le32 sriov_ig_flow_table_cfg; + __le32 sriov_ig_flow_table_free; + __le32 sriov_eg_flow_table_cfg; + __le32 sriov_eg_flow_table_free; + u8 admin_qp_ready[32]; + __le16 vf_index; + __le16 reserved1; + __le32 reserved2[256 - 23]; +}; + /* CMD_ENABLE2 flags */ #define CMD_ENABLE2_STANDBY 0x0 #define CMD_ENABLE2_ACTIVE 0x1
--
2.43.0