mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 10:31:33 -04:00
enic: wire V2 SR-IOV enable with admin channel and MBOX
Extend enic_sriov_configure() to handle V2 SR-IOV VFs. When the PF detects V2 VF device IDs, the enable path allocates per-VF MBOX state, initializes the MBOX protocol, opens the admin channel, and then calls pci_enable_sriov(). The admin channel must be ready before VFs are created so that VF drivers can immediately begin the MBOX capability and registration handshake during their probe. The enic_sriov_configure() dispatcher and its V2 helpers (enic_sriov_v2_enable, enic_sriov_v2_disable) are defined here but intentionally not yet wired into struct pci_driver via .sriov_configure -- hence the __maybe_unused annotations. This series introduces only the admin channel and MBOX infrastructure; sysfs-driven V2 enable/disable will be activated in a follow-up patch by adding ".sriov_configure = enic_sriov_configure," to enic_driver. Because .sriov_configure is not registered yet, enic_sriov_configure() cannot run concurrently with the rtnl-protected reset paths (enic_reset(), enic_tx_hang_reset()) in this series, so there is no reachable locking race between SR-IOV enable/disable and reset. The follow-up patch that wires the callback will add the necessary serialization against those paths. Note that simply taking rtnl_lock() around the enable path is not viable, because pci_enable_sriov() triggers VF probe and register_netdev(), which themselves acquire rtnl; the wiring patch therefore uses finer-grained serialization. The disable path first clears ENIC_SRIOV_ENABLED and flushes the link-notify work, so no further VF link-state broadcast can run, then calls pci_disable_sriov() (VF drivers unregister via MBOX), closes the admin channel, and frees per-VF state. Clearing the flag and flushing the work before vf_state is freed closes a use-after-free window against the link-notify path. Notify registered VFs of PF link transitions: enic_link_check() schedules link_notify_work on each carrier up/down edge, and the work handler sends PF_LINK_STATE_NOTIF to the VFs from process context. The broadcast cannot run directly in enic_link_check() because the MBOX send path may sleep and link check runs in the notify timer/ISR context. On a V2 VF the admin-channel (PF) link-state notification is the sole authority for carrier state, so enic_link_check() returns early for such VFs. As a side effect the VF retains the firmware-provided static Rx interrupt coalescing (config.intr_timer_usec) rather than PF-driven speed-adaptive coalescing; this is intentional, as adaptive Rx coalescing is a PF-only responsibility for V2 VFs. Re-establish the admin/MBOX channel across a PF reset. enic_reset() and enic_tx_hang_reset() fully close the admin channel before the soft/hang reset (which wipes all hardware queues, including the admin WQ/RQ), then reopen it and re-run enic_mbox_init() after the data path is back up, and re-push the current link state to registered VFs. Reject VF port profile requests when V2 SR-IOV is active (enic_is_valid_pp_vf), since enic->pp is not reallocated for V2 VFs and the V2 protocol uses MBOX instead of port profiles. Update enic_remove() to run enic_dev_deinit() and vnic_dev_close() after SR-IOV teardown, so the PF device remains functional while VFs are being cleaned up. This ordering applies to both V1 and V2 SR-IOV paths. Restrict the probe-time SR-IOV auto-enable to the legacy VF types (V1 and usNIC). A V2-capable adapter whose firmware lacks V2 support is downgraded to ENIC_VF_TYPE_NONE, and V2 VFs require the admin channel which is only brought up via sysfs enic_sriov_configure(); neither must be auto-enabled through the legacy pci_enable_sriov() path at probe. Signed-off-by: Satish Kharat <satishkh@cisco.com> Link: https://patch.msgid.link/20260812-enic-sriov-v2-admin-channel-v2-v13-9-b3809e448aba@cisco.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
72b65c9405
commit
4ff204cef0
@@ -305,6 +305,7 @@ struct enic {
|
||||
struct vnic_intr admin_intr;
|
||||
struct delayed_work admin_poll_work;
|
||||
unsigned int admin_intr_index;
|
||||
struct work_struct link_notify_work;
|
||||
struct work_struct admin_msg_work;
|
||||
spinlock_t admin_msg_lock; /* protects admin_msg_list */
|
||||
struct list_head admin_msg_list;
|
||||
@@ -325,6 +326,7 @@ struct enic {
|
||||
*/
|
||||
struct completion mbox_comp;
|
||||
u8 mbox_expected_reply;
|
||||
bool mbox_initialized;
|
||||
|
||||
/* PF: per-VF MBOX state, allocated when SRIOV V2 is enabled */
|
||||
struct enic_vf_state {
|
||||
@@ -451,6 +453,7 @@ void enic_reset_addr_lists(struct enic *enic);
|
||||
int enic_sriov_enabled(struct enic *enic);
|
||||
int enic_is_valid_vf(struct enic *enic, int vf);
|
||||
int enic_is_dynamic(struct enic *enic);
|
||||
int enic_is_sriov_vf_v2(struct enic *enic);
|
||||
void enic_set_ethtool_ops(struct net_device *netdev);
|
||||
int __enic_set_rsskey(struct enic *enic);
|
||||
void enic_ext_cq(struct enic *enic);
|
||||
|
||||
@@ -639,6 +639,7 @@ void enic_admin_channel_close(struct enic *enic)
|
||||
|
||||
vnic_intr_mask(&enic->admin_intr);
|
||||
enic_admin_teardown_intr(enic);
|
||||
cancel_work_sync(&enic->link_notify_work);
|
||||
cancel_work_sync(&enic->admin_msg_work);
|
||||
enic_admin_msg_drain(enic);
|
||||
|
||||
@@ -658,6 +659,8 @@ void enic_admin_channel_close(struct enic *enic)
|
||||
vnic_cq_clean(&enic->admin_cq[0]);
|
||||
vnic_cq_clean(&enic->admin_cq[1]);
|
||||
vnic_intr_clean(&enic->admin_intr);
|
||||
|
||||
enic->admin_rq_handler = NULL;
|
||||
enic_admin_free_resources(enic);
|
||||
|
||||
enic->admin_chan_up = false;
|
||||
|
||||
@@ -60,6 +60,8 @@
|
||||
#include "enic_clsf.h"
|
||||
#include "enic_rq.h"
|
||||
#include "enic_wq.h"
|
||||
#include "enic_admin.h"
|
||||
#include "enic_mbox.h"
|
||||
|
||||
#define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ)
|
||||
|
||||
@@ -314,6 +316,11 @@ static int enic_is_sriov_vf(struct enic *enic)
|
||||
enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2;
|
||||
}
|
||||
|
||||
int enic_is_sriov_vf_v2(struct enic *enic)
|
||||
{
|
||||
return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF_V2;
|
||||
}
|
||||
|
||||
int enic_is_valid_vf(struct enic *enic, int vf)
|
||||
{
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
@@ -411,18 +418,50 @@ static void enic_set_rx_coal_setting(struct enic *enic)
|
||||
rx_coal->use_adaptive_rx_coalesce = 1;
|
||||
}
|
||||
|
||||
static void enic_link_notify_work_handler(struct work_struct *work)
|
||||
{
|
||||
struct enic *enic = container_of(work, struct enic,
|
||||
link_notify_work);
|
||||
u32 state;
|
||||
u16 i;
|
||||
|
||||
if (!enic_sriov_enabled(enic) || !enic->vf_state)
|
||||
return;
|
||||
|
||||
state = netif_carrier_ok(enic->netdev) ?
|
||||
ENIC_MBOX_LINK_STATE_ENABLE :
|
||||
ENIC_MBOX_LINK_STATE_DISABLE;
|
||||
|
||||
for (i = 0; i < enic->num_vfs; i++)
|
||||
enic_mbox_send_link_state(enic, i, state);
|
||||
}
|
||||
|
||||
static void enic_link_check(struct enic *enic)
|
||||
{
|
||||
int link_status = vnic_dev_link_status(enic->vdev);
|
||||
int carrier_ok = netif_carrier_ok(enic->netdev);
|
||||
int link_status;
|
||||
int carrier_ok;
|
||||
|
||||
/* A V2 SR-IOV VF's carrier is driven by PF link-state MBOX
|
||||
* notifications, not by its own vnic link status; skip the
|
||||
* autonomous check so it cannot flap the VF carrier.
|
||||
*/
|
||||
if (enic_is_sriov_vf_v2(enic))
|
||||
return;
|
||||
|
||||
link_status = vnic_dev_link_status(enic->vdev);
|
||||
carrier_ok = netif_carrier_ok(enic->netdev);
|
||||
|
||||
if (link_status && !carrier_ok) {
|
||||
netdev_info(enic->netdev, "Link UP\n");
|
||||
netif_carrier_on(enic->netdev);
|
||||
enic_set_rx_coal_setting(enic);
|
||||
if (enic_sriov_enabled(enic) && enic->vf_state)
|
||||
schedule_work(&enic->link_notify_work);
|
||||
} else if (!link_status && carrier_ok) {
|
||||
netdev_info(enic->netdev, "Link DOWN\n");
|
||||
netif_carrier_off(enic->netdev);
|
||||
if (enic_sriov_enabled(enic) && enic->vf_state)
|
||||
schedule_work(&enic->link_notify_work);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2154,15 +2193,47 @@ static void enic_reset(struct work_struct *work)
|
||||
/* Stop any activity from infiniband */
|
||||
enic_set_api_busy(enic, true);
|
||||
|
||||
/* Fully tear down the V2 admin/MBOX channel before the soft reset.
|
||||
* The reset wipes all hardware queues including the admin WQ/RQ;
|
||||
* closing first tells firmware to stop the admin QP (so it no longer
|
||||
* DMAs from the about-to-be-reset rings) and frees the admin resources
|
||||
* so they are cleanly re-allocated afterwards.
|
||||
*/
|
||||
if (enic_sriov_enabled(enic) &&
|
||||
enic->vf_type == ENIC_VF_TYPE_V2)
|
||||
enic_admin_channel_close(enic);
|
||||
|
||||
enic_stop(enic->netdev);
|
||||
|
||||
enic_dev_soft_reset(enic);
|
||||
enic_reset_addr_lists(enic);
|
||||
enic_init_vnic_resources(enic);
|
||||
enic_set_rss_nic_cfg(enic);
|
||||
enic_dev_set_ig_vlan_rewrite_mode(enic);
|
||||
enic_ext_cq(enic);
|
||||
|
||||
enic_open(enic->netdev);
|
||||
|
||||
/* Re-establish the admin/MBOX channel after the data path is back up,
|
||||
* mirroring the SR-IOV enable path (channel open + mbox init). The
|
||||
* channel was fully torn down by enic_admin_channel_close() above.
|
||||
*/
|
||||
if (enic_sriov_enabled(enic) &&
|
||||
enic->vf_type == ENIC_VF_TYPE_V2) {
|
||||
if (enic_admin_channel_open(enic)) {
|
||||
netdev_err(enic->netdev,
|
||||
"admin channel reopen after reset failed\n");
|
||||
} else {
|
||||
enic_mbox_init(enic);
|
||||
/* The link came back up during enic_open() above
|
||||
* while MBOX sends were still disabled (channel not
|
||||
* yet reopened), so that link-notify was dropped.
|
||||
* Re-push current link state to registered VFs now.
|
||||
*/
|
||||
schedule_work(&enic->link_notify_work);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow infiniband to fiddle with the device again */
|
||||
enic_set_api_busy(enic, false);
|
||||
|
||||
@@ -2180,16 +2251,46 @@ static void enic_tx_hang_reset(struct work_struct *work)
|
||||
/* Stop any activity from infiniband */
|
||||
enic_set_api_busy(enic, true);
|
||||
|
||||
/* Fully tear down the V2 admin/MBOX channel before the hang reset, for
|
||||
* the same reason as the soft reset path: stop the admin QP and free
|
||||
* the admin resources before the hardware queues are wiped.
|
||||
*/
|
||||
if (enic_sriov_enabled(enic) &&
|
||||
enic->vf_type == ENIC_VF_TYPE_V2)
|
||||
enic_admin_channel_close(enic);
|
||||
|
||||
enic_dev_hang_notify(enic);
|
||||
enic_stop(enic->netdev);
|
||||
|
||||
enic_dev_hang_reset(enic);
|
||||
enic_reset_addr_lists(enic);
|
||||
enic_init_vnic_resources(enic);
|
||||
enic_set_rss_nic_cfg(enic);
|
||||
enic_dev_set_ig_vlan_rewrite_mode(enic);
|
||||
enic_ext_cq(enic);
|
||||
|
||||
enic_open(enic->netdev);
|
||||
|
||||
/* Re-establish the admin/MBOX channel after the data path is back up,
|
||||
* mirroring the SR-IOV enable path (channel open + mbox init). The
|
||||
* channel was fully torn down by enic_admin_channel_close() above.
|
||||
*/
|
||||
if (enic_sriov_enabled(enic) &&
|
||||
enic->vf_type == ENIC_VF_TYPE_V2) {
|
||||
if (enic_admin_channel_open(enic)) {
|
||||
netdev_err(enic->netdev,
|
||||
"admin channel reopen after reset failed\n");
|
||||
} else {
|
||||
enic_mbox_init(enic);
|
||||
/* The link came back up during enic_open() above
|
||||
* while MBOX sends were still disabled (channel not
|
||||
* yet reopened), so that link-notify was dropped.
|
||||
* Re-push current link state to registered VFs now.
|
||||
*/
|
||||
schedule_work(&enic->link_notify_work);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow infiniband to fiddle with the device again */
|
||||
enic_set_api_busy(enic, false);
|
||||
|
||||
@@ -2200,6 +2301,8 @@ static void enic_tx_hang_reset(struct work_struct *work)
|
||||
|
||||
static int enic_set_intr_mode(struct enic *enic)
|
||||
{
|
||||
unsigned int admin_reserve = enic->has_admin_channel ? 1 : 0;
|
||||
unsigned int min_intr = ENIC_MSIX_MIN_INTR + admin_reserve;
|
||||
unsigned int i;
|
||||
int num_intr;
|
||||
|
||||
@@ -2210,12 +2313,12 @@ static int enic_set_intr_mode(struct enic *enic)
|
||||
*/
|
||||
|
||||
if (enic->config.intr_mode < 1 &&
|
||||
enic->intr_avail >= ENIC_MSIX_MIN_INTR) {
|
||||
enic->intr_avail >= min_intr) {
|
||||
for (i = 0; i < enic->intr_avail; i++)
|
||||
enic->msix_entry[i].entry = i;
|
||||
|
||||
num_intr = pci_enable_msix_range(enic->pdev, enic->msix_entry,
|
||||
ENIC_MSIX_MIN_INTR,
|
||||
min_intr,
|
||||
enic->intr_avail);
|
||||
if (num_intr > 0) {
|
||||
vnic_dev_set_intr_mode(enic->vdev,
|
||||
@@ -2310,7 +2413,13 @@ static int enic_adjust_resources(struct enic *enic)
|
||||
enic->cq_count = 2;
|
||||
enic->intr_count = enic->intr_avail;
|
||||
break;
|
||||
case VNIC_DEV_INTR_MODE_MSIX:
|
||||
case VNIC_DEV_INTR_MODE_MSIX: {
|
||||
/* Reserve one MSI-X slot for the admin channel interrupt
|
||||
* when V2 SR-IOV admin channel resources are present.
|
||||
*/
|
||||
unsigned int admin_reserve =
|
||||
enic->has_admin_channel ? 1 : 0;
|
||||
|
||||
/* Adjust the number of wqs/rqs/cqs/interrupts that will be
|
||||
* used based on which resource is the most constrained
|
||||
*/
|
||||
@@ -2319,7 +2428,8 @@ static int enic_adjust_resources(struct enic *enic)
|
||||
ENIC_RQ_MIN_DEFAULT);
|
||||
rq_avail = min3(enic->rq_avail, ENIC_RQ_MAX, rq_default);
|
||||
max_queues = min(enic->cq_avail,
|
||||
enic->intr_avail - ENIC_MSIX_RESERVED_INTR);
|
||||
enic->intr_avail - ENIC_MSIX_RESERVED_INTR -
|
||||
admin_reserve);
|
||||
if (wq_avail + rq_avail <= max_queues) {
|
||||
enic->rq_count = rq_avail;
|
||||
enic->wq_count = wq_avail;
|
||||
@@ -2337,6 +2447,7 @@ static int enic_adjust_resources(struct enic *enic)
|
||||
enic->intr_count = enic->cq_count + ENIC_MSIX_RESERVED_INTR;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dev_err(enic_get_dev(enic), "Unknown interrupt mode\n");
|
||||
return -EINVAL;
|
||||
@@ -2689,6 +2800,144 @@ static void enic_sriov_detect_vf_type(struct enic *enic)
|
||||
enic->vf_type = ENIC_VF_TYPE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static int __maybe_unused
|
||||
enic_sriov_v2_enable(struct enic *enic, int num_vfs)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!enic->has_admin_channel) {
|
||||
netdev_err(enic->netdev,
|
||||
"V2 SR-IOV requires admin channel resources\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
enic->vf_state = kcalloc(num_vfs, sizeof(*enic->vf_state), GFP_KERNEL);
|
||||
if (!enic->vf_state)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Install the MBOX receive handler before the admin interrupt is
|
||||
* unmasked in enic_admin_channel_open(), so no early completion is
|
||||
* dropped.
|
||||
*/
|
||||
enic_mbox_init(enic);
|
||||
|
||||
err = enic_admin_channel_open(enic);
|
||||
if (err) {
|
||||
netdev_err(enic->netdev,
|
||||
"Failed to open admin channel: %d\n", err);
|
||||
goto free_vf_state;
|
||||
}
|
||||
|
||||
enic->num_vfs = num_vfs;
|
||||
|
||||
err = pci_enable_sriov(enic->pdev, num_vfs);
|
||||
if (err) {
|
||||
netdev_err(enic->netdev,
|
||||
"pci_enable_sriov failed: %d\n", err);
|
||||
goto close_admin;
|
||||
}
|
||||
|
||||
enic->priv_flags |= ENIC_SRIOV_ENABLED;
|
||||
return num_vfs;
|
||||
|
||||
close_admin:
|
||||
enic->num_vfs = 0;
|
||||
enic_admin_channel_close(enic);
|
||||
free_vf_state:
|
||||
kfree(enic->vf_state);
|
||||
enic->vf_state = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void enic_sriov_v2_disable(struct enic *enic)
|
||||
{
|
||||
/* Stop new VF link-state broadcasts before tearing down vf_state.
|
||||
* Clearing ENIC_SRIOV_ENABLED makes enic_link_check() (called from
|
||||
* the notify timer/ISR) skip the VF notify path, and cancelling
|
||||
* link_notify_work ensures any already-queued broadcast has finished
|
||||
* before vf_state is freed, closing a use-after-free window.
|
||||
*/
|
||||
enic->priv_flags &= ~ENIC_SRIOV_ENABLED;
|
||||
cancel_work_sync(&enic->link_notify_work);
|
||||
|
||||
pci_disable_sriov(enic->pdev);
|
||||
enic_admin_channel_close(enic);
|
||||
kfree(enic->vf_state);
|
||||
enic->vf_state = NULL;
|
||||
enic->num_vfs = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* enic_sriov_configure() and its V2 helpers are defined but not yet wired
|
||||
* into enic_driver via .sriov_configure (see the __maybe_unused annotations);
|
||||
* V2 enable/disable is activated in a follow-up series. Because the callback
|
||||
* is not registered, it cannot run concurrently with the rtnl-protected reset
|
||||
* paths (enic_reset(), enic_tx_hang_reset()) yet. Serialization against those
|
||||
* paths is added together with the .sriov_configure wiring in that series.
|
||||
*/
|
||||
static int __maybe_unused
|
||||
enic_sriov_configure(struct pci_dev *pdev, int num_vfs)
|
||||
{
|
||||
struct net_device *netdev = pci_get_drvdata(pdev);
|
||||
struct enic *enic = netdev_priv(netdev);
|
||||
struct enic_port_profile *pp;
|
||||
int err;
|
||||
|
||||
if (num_vfs > 0) {
|
||||
if (enic->config.mq_subvnic_count) {
|
||||
netdev_err(netdev,
|
||||
"SR-IOV not supported with multi-queue sub-vnics\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (enic->vf_type == ENIC_VF_TYPE_NONE) {
|
||||
netdev_err(netdev,
|
||||
"SR-IOV not supported on this firmware version\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (enic->vf_type == ENIC_VF_TYPE_V2)
|
||||
return enic_sriov_v2_enable(enic, num_vfs);
|
||||
|
||||
pp = kcalloc(num_vfs, sizeof(*pp), GFP_KERNEL);
|
||||
if (!pp)
|
||||
return -ENOMEM;
|
||||
|
||||
err = pci_enable_sriov(pdev, num_vfs);
|
||||
if (err) {
|
||||
kfree(pp);
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(enic->pp);
|
||||
enic->pp = pp;
|
||||
enic->num_vfs = num_vfs;
|
||||
enic->priv_flags |= ENIC_SRIOV_ENABLED;
|
||||
return num_vfs;
|
||||
}
|
||||
|
||||
if (!enic_sriov_enabled(enic))
|
||||
return 0;
|
||||
|
||||
if (enic->vf_type == ENIC_VF_TYPE_V2) {
|
||||
enic_sriov_v2_disable(enic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pp = kzalloc_obj(*enic->pp, GFP_KERNEL);
|
||||
if (!pp)
|
||||
return -ENOMEM;
|
||||
|
||||
pci_disable_sriov(pdev);
|
||||
enic->num_vfs = 0;
|
||||
enic->priv_flags &= ~ENIC_SRIOV_ENABLED;
|
||||
|
||||
kfree(enic->pp);
|
||||
enic->pp = pp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
@@ -2787,12 +3036,23 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
goto err_out_vnic_unregister;
|
||||
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
/* Get number of subvnics */
|
||||
enic_sriov_detect_vf_type(enic);
|
||||
|
||||
/* Auto-enable SR-IOV only for the legacy VF types. V2 VFs require
|
||||
* the admin channel, which is not yet set up at probe time (V2 SR-IOV
|
||||
* will be enabled through the sysfs .sriov_configure callback once a
|
||||
* follow-up series wires it up); and a V2-capable device whose
|
||||
* firmware lacks V2 support is downgraded to ENIC_VF_TYPE_NONE by
|
||||
* enic_sriov_detect_vf_type() and must not be brought up through the
|
||||
* legacy pci_enable_sriov() path either.
|
||||
*/
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
|
||||
if (pos) {
|
||||
pci_read_config_word(pdev, pos + PCI_SRIOV_TOTAL_VF,
|
||||
&enic->num_vfs);
|
||||
if (enic->num_vfs) {
|
||||
if (enic->num_vfs &&
|
||||
(enic->vf_type == ENIC_VF_TYPE_V1 ||
|
||||
enic->vf_type == ENIC_VF_TYPE_USNIC)) {
|
||||
err = pci_enable_sriov(pdev, enic->num_vfs);
|
||||
if (err) {
|
||||
dev_err(dev, "SRIOV enable failed, aborting."
|
||||
@@ -2804,7 +3064,6 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
num_pps = enic->num_vfs;
|
||||
}
|
||||
}
|
||||
enic_sriov_detect_vf_type(enic);
|
||||
#endif
|
||||
|
||||
/* Allocate structure for port profiles */
|
||||
@@ -2881,6 +3140,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
INIT_WORK(&enic->reset, enic_reset);
|
||||
INIT_WORK(&enic->tx_hang_reset, enic_tx_hang_reset);
|
||||
INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work);
|
||||
INIT_WORK(&enic->link_notify_work, enic_link_notify_work_handler);
|
||||
|
||||
for (i = 0; i < enic->wq_count; i++)
|
||||
spin_lock_init(&enic->wq[i].lock);
|
||||
@@ -3034,14 +3294,16 @@ static void enic_remove(struct pci_dev *pdev)
|
||||
disable_work_sync(&enic->tx_hang_reset);
|
||||
disable_work_sync(&enic->change_mtu_work);
|
||||
unregister_netdev(netdev);
|
||||
enic_dev_deinit(enic);
|
||||
vnic_dev_close(enic->vdev);
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
if (enic_sriov_enabled(enic)) {
|
||||
pci_disable_sriov(pdev);
|
||||
enic->priv_flags &= ~ENIC_SRIOV_ENABLED;
|
||||
if (enic->vf_type == ENIC_VF_TYPE_V2)
|
||||
enic_sriov_v2_disable(enic);
|
||||
else
|
||||
pci_disable_sriov(pdev);
|
||||
}
|
||||
#endif
|
||||
enic_dev_deinit(enic);
|
||||
vnic_dev_close(enic->vdev);
|
||||
kfree(enic->pp);
|
||||
vnic_dev_unregister(enic->vdev);
|
||||
enic_iounmap(enic);
|
||||
|
||||
@@ -631,8 +631,17 @@ int enic_mbox_vf_unregister(struct enic *enic)
|
||||
|
||||
void enic_mbox_init(struct enic *enic)
|
||||
{
|
||||
/* mbox_lock and mbox_comp must be initialized exactly once per
|
||||
* device lifetime; the PF sriov_configure path can re-enter this
|
||||
* on each enable cycle where these primitives are already set up.
|
||||
*/
|
||||
if (!enic->mbox_initialized) {
|
||||
mutex_init(&enic->mbox_lock);
|
||||
init_completion(&enic->mbox_comp);
|
||||
enic->mbox_initialized = true;
|
||||
} else {
|
||||
reinit_completion(&enic->mbox_comp);
|
||||
}
|
||||
enic->mbox_msg_num = 0;
|
||||
mutex_init(&enic->mbox_lock);
|
||||
init_completion(&enic->mbox_comp);
|
||||
enic->admin_rq_handler = enic_mbox_recv_handler;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,11 @@ int enic_is_valid_pp_vf(struct enic *enic, int vf, int *err)
|
||||
if (vf != PORT_SELF_VF) {
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
if (enic_sriov_enabled(enic)) {
|
||||
/* V2 SR-IOV uses MBOX, not port profiles */
|
||||
if (enic->vf_type == ENIC_VF_TYPE_V2) {
|
||||
*err = -EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
if (vf < 0 || vf >= enic->num_vfs) {
|
||||
*err = -EINVAL;
|
||||
goto err_out;
|
||||
|
||||
@@ -59,6 +59,7 @@ int enic_get_vnic_config(struct enic *enic)
|
||||
GET_CONFIG(intr_timer_usec);
|
||||
GET_CONFIG(loop_tag);
|
||||
GET_CONFIG(num_arfs);
|
||||
GET_CONFIG(mq_subvnic_count);
|
||||
GET_CONFIG(max_rq_ring);
|
||||
GET_CONFIG(max_wq_ring);
|
||||
GET_CONFIG(max_cq_ring);
|
||||
|
||||
@@ -21,7 +21,9 @@ struct vnic_enet_config {
|
||||
u16 loop_tag;
|
||||
u16 vf_rq_count;
|
||||
u16 num_arfs;
|
||||
u8 reserved[66];
|
||||
u8 reserved1[32];
|
||||
u16 mq_subvnic_count;
|
||||
u8 reserved2[32];
|
||||
u32 max_rq_ring; // MAX RQ ring size
|
||||
u32 max_wq_ring; // MAX WQ ring size
|
||||
u32 max_cq_ring; // MAX CQ ring size
|
||||
|
||||
Reference in New Issue
Block a user