mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
enic: re-establish V2 VF admin channel and PF registration after reset
The reset paths (enic_reset/enic_tx_hang_reset) tore down and re-opened the V2 admin/MBOX channel only for the PF: the close/reopen was gated on enic_sriov_enabled() && vf_type == ENIC_VF_TYPE_V2, which is never true on a VF (vf_type is set only on the PF; VFs are identified by enic_is_sriov_vf_v2()). A VF-initiated reset therefore left the VF admin QP wiped by the reset but never re-opened, and the VF never re-registered with the PF, so VF<->PF MBOX traffic (currently link state) stopped working until the VF was re-probed. Factor the decision into enic_has_admin_chan() (true for a V2 PF while SR-IOV is enabled and for every V2 VF) and the reopen sequence into enic_admin_chan_reopen(). For a VF the helper additionally re-runs the probe-time handshake (enic_mbox_vf_capability_check() + enic_mbox_vf_register()) so the PF learns about the VF again; for a PF it re-pushes the current link state as before. Before reopening, invalidate the VF's local registration flag. The reset only wipes the VF's admin QP, not the PF's software vf_state (that changes only via the register/unregister MBOX handlers), so the PF may still hold a stale "registered" until the VF re-registers. Locally, a failed reopen or re-handshake must not leave a stale registered state that a later teardown would try to unregister over a dead channel. Signed-off-by: Satish Kharat <satishkh@cisco.com> Link: https://patch.msgid.link/20260812-enic-sriov-v2-admin-channel-v2-v13-11-b3809e448aba@cisco.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
b2dfdc966b
commit
885f462fe9
|
|
@ -2181,6 +2181,74 @@ static void enic_set_api_busy(struct enic *enic, bool busy)
|
|||
spin_unlock(&enic->enic_api_lock);
|
||||
}
|
||||
|
||||
/* The admin/MBOX channel exists on a V2 PF while SR-IOV is enabled and on
|
||||
* every V2 VF. A reset wipes the admin WQ/RQ/CQ, so such devices must tear
|
||||
* the channel down before the reset and re-establish it afterwards.
|
||||
*/
|
||||
static bool enic_has_admin_chan(struct enic *enic)
|
||||
{
|
||||
return enic_is_sriov_vf_v2(enic) ||
|
||||
(enic_sriov_enabled(enic) && enic->vf_type == ENIC_VF_TYPE_V2);
|
||||
}
|
||||
|
||||
/* 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
|
||||
* handshake (the reset wiped the VF's admin QP, so the VF must register
|
||||
* again), or for a PF re-push the current link state to registered VFs.
|
||||
*/
|
||||
static void enic_admin_chan_reopen(struct enic *enic)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Install the MBOX receive handler and reset the sequence number
|
||||
* before opening the channel, so the handler is in place before the
|
||||
* admin interrupt is unmasked and no early completion is dropped.
|
||||
*/
|
||||
enic_mbox_init(enic);
|
||||
|
||||
/* A reset destroys the VF's local admin QP, so the VF can no longer
|
||||
* rely on its previous registration. The PF may retain stale software
|
||||
* registration state until the VF successfully registers again.
|
||||
* Clear the local flag before reopening so a failed reopen or
|
||||
* re-handshake cannot leave the VF believing it has a usable PF
|
||||
* registration over a dead channel.
|
||||
*/
|
||||
if (enic_is_sriov_vf_v2(enic))
|
||||
enic->vf_registered = false;
|
||||
|
||||
err = enic_admin_channel_open(enic);
|
||||
if (err) {
|
||||
netdev_err(enic->netdev,
|
||||
"admin channel reopen after reset failed: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (enic_is_sriov_vf_v2(enic)) {
|
||||
err = enic_mbox_vf_capability_check(enic);
|
||||
if (err) {
|
||||
netdev_err(enic->netdev,
|
||||
"MBOX capability check after reset failed: %d\n",
|
||||
err);
|
||||
enic_admin_channel_close(enic);
|
||||
return;
|
||||
}
|
||||
err = enic_mbox_vf_register(enic);
|
||||
if (err) {
|
||||
netdev_err(enic->netdev,
|
||||
"MBOX VF re-registration after reset failed: %d\n",
|
||||
err);
|
||||
enic_admin_channel_close(enic);
|
||||
}
|
||||
} else {
|
||||
/* 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 now.
|
||||
*/
|
||||
schedule_work(&enic->link_notify_work);
|
||||
}
|
||||
}
|
||||
|
||||
static void enic_reset(struct work_struct *work)
|
||||
{
|
||||
struct enic *enic = container_of(work, struct enic, reset);
|
||||
|
|
@ -2199,8 +2267,7 @@ static void enic_reset(struct work_struct *work)
|
|||
* 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)
|
||||
if (enic_has_admin_chan(enic))
|
||||
enic_admin_channel_close(enic);
|
||||
|
||||
enic_stop(enic->netdev);
|
||||
|
|
@ -2214,25 +2281,13 @@ static void enic_reset(struct work_struct *work)
|
|||
|
||||
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.
|
||||
/* Re-establish the admin/MBOX channel after the data path is back up.
|
||||
* It was fully torn down by enic_admin_channel_close() above;
|
||||
* enic_admin_chan_reopen() reopens it and, for a PF re-pushes link
|
||||
* state, or for a VF re-runs the probe-time PF handshake.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (enic_has_admin_chan(enic))
|
||||
enic_admin_chan_reopen(enic);
|
||||
|
||||
/* Allow infiniband to fiddle with the device again */
|
||||
enic_set_api_busy(enic, false);
|
||||
|
|
@ -2255,8 +2310,7 @@ static void enic_tx_hang_reset(struct work_struct *work)
|
|||
* 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)
|
||||
if (enic_has_admin_chan(enic))
|
||||
enic_admin_channel_close(enic);
|
||||
|
||||
enic_dev_hang_notify(enic);
|
||||
|
|
@ -2271,25 +2325,13 @@ static void enic_tx_hang_reset(struct work_struct *work)
|
|||
|
||||
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.
|
||||
/* Re-establish the admin/MBOX channel after the data path is back up.
|
||||
* It was fully torn down by enic_admin_channel_close() above;
|
||||
* enic_admin_chan_reopen() reopens it and, for a PF re-pushes link
|
||||
* state, or for a VF re-runs the probe-time PF handshake.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (enic_has_admin_chan(enic))
|
||||
enic_admin_chan_reopen(enic);
|
||||
|
||||
/* Allow infiniband to fiddle with the device again */
|
||||
enic_set_api_busy(enic, false);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user