aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ixl/ixl_pf.h5
-rw-r--r--sys/dev/ixl/ixl_pf_iflib.c13
-rw-r--r--sys/dev/ixl/ixl_pf_iov.c150
-rw-r--r--sys/dev/ixl/ixl_pf_main.c13
4 files changed, 148 insertions, 33 deletions
diff --git a/sys/dev/ixl/ixl_pf.h b/sys/dev/ixl/ixl_pf.h
index 80583b152a1c..8d06738034a4 100644
--- a/sys/dev/ixl/ixl_pf.h
+++ b/sys/dev/ixl/ixl_pf.h
@@ -384,6 +384,11 @@ int ixl_prepare_for_reset(struct ixl_pf *pf, bool is_up);
int ixl_rebuild_hw_structs_after_reset(struct ixl_pf *, bool is_up);
int ixl_pf_reset(struct ixl_pf *);
+#ifdef PCI_IOV
+void ixl_notify_vfs_reset(struct ixl_pf *);
+int ixl_rebuild_vfs_after_reset(struct ixl_pf *);
+#endif
+
void ixl_set_queue_rx_itr(struct ixl_rx_queue *);
void ixl_set_queue_tx_itr(struct ixl_tx_queue *);
diff --git a/sys/dev/ixl/ixl_pf_iflib.c b/sys/dev/ixl/ixl_pf_iflib.c
index 98054a21c291..8289cc72bc64 100644
--- a/sys/dev/ixl/ixl_pf_iflib.c
+++ b/sys/dev/ixl/ixl_pf_iflib.c
@@ -937,6 +937,9 @@ ixl_prepare_for_reset(struct ixl_pf *pf, bool is_up)
device_t dev = pf->dev;
int error = 0;
+#ifdef PCI_IOV
+ ixl_notify_vfs_reset(pf);
+#endif
if (is_up)
ixl_if_stop(pf->vsi.ctx);
@@ -999,6 +1002,7 @@ ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf, bool is_up)
if (error) {
device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n",
error);
+ goto ixl_rebuild_hw_structs_after_reset_err;
}
error = ixl_switch_config(pf);
@@ -1033,6 +1037,15 @@ ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf, bool is_up)
/* Receive broadcast Ethernet frames */
i40e_aq_set_vsi_broadcast(&pf->hw, vsi->seid, TRUE, NULL);
+#ifdef PCI_IOV
+ if (pf->num_vfs != 0) {
+ error = ixl_rebuild_vfs_after_reset(pf);
+ if (error != 0)
+ device_printf(dev,
+ "Failed to rebuild one or more VFs: %d\n", error);
+ }
+#endif
+
/* Determine link state */
ixl_attach_get_link_status(pf);
diff --git a/sys/dev/ixl/ixl_pf_iov.c b/sys/dev/ixl/ixl_pf_iov.c
index 8a62876831d6..358210f0cc2f 100644
--- a/sys/dev/ixl/ixl_pf_iov.c
+++ b/sys/dev/ixl/ixl_pf_iov.c
@@ -81,6 +81,7 @@ static void ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf, void
static void ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
static int ixl_vf_reserve_queues(struct ixl_pf *pf, struct ixl_vf *vf, int num_queues);
static int ixl_config_pf_vsi_loopback(struct ixl_pf *pf, bool enable);
+static int ixl_setup_iov_switch(struct ixl_pf *pf);
static int ixl_adminq_err_to_errno(enum i40e_admin_queue_err err);
@@ -1979,18 +1980,132 @@ ixl_config_pf_vsi_loopback(struct ixl_pf *pf, bool enable)
return (error);
}
-int
-ixl_if_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params)
+static int
+ixl_setup_iov_switch(struct ixl_pf *pf)
{
- struct ixl_pf *pf = iflib_get_softc(ctx);
- device_t dev = iflib_get_dev(ctx);
struct i40e_hw *hw;
struct ixl_vsi *pf_vsi;
- enum i40e_status_code ret;
- int error, i;
+ enum i40e_status_code status;
+ int error;
hw = &pf->hw;
pf_vsi = &pf->vsi;
+ status = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid,
+ 1, false, &pf->veb_seid, false, NULL);
+ if (status != I40E_SUCCESS) {
+ error = ixl_adminq_err_to_errno(hw->aq.asq_last_status);
+ device_printf(pf->dev,
+ "i40e_aq_add_veb failed; status %s error %s\n",
+ i40e_stat_str(hw, status),
+ i40e_aq_str(hw, hw->aq.asq_last_status));
+ return (error);
+ }
+ if (pf->enable_vf_loopback) {
+ error = ixl_config_pf_vsi_loopback(pf, true);
+ if (error != 0)
+ goto fail;
+ }
+
+ /* Adding a VEB reinstalls the firmware's default PF filters. */
+ ixl_del_default_hw_filters(pf_vsi);
+ ixl_reconfigure_filters(pf_vsi);
+ return (0);
+
+fail:
+ i40e_aq_delete_element(hw, pf->veb_seid, NULL);
+ pf->veb_seid = 0;
+ return (error);
+}
+
+void
+ixl_notify_vfs_reset(struct ixl_pf *pf)
+{
+ struct virtchnl_pf_event event;
+ struct ixl_vf *vf;
+ int i;
+
+ if (pf->num_vfs == 0 || !i40e_check_asq_alive(&pf->hw))
+ return;
+ bzero(&event, sizeof(event));
+ event.event = VIRTCHNL_EVENT_RESET_IMPENDING;
+ event.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM;
+ for (i = 0; i < pf->num_vfs; i++) {
+ vf = &pf->vfs[i];
+ if (vf->vf_flags & VF_FLAG_ENABLED) {
+ ixl_send_vf_msg(pf, vf, VIRTCHNL_OP_EVENT,
+ I40E_SUCCESS, &event, sizeof(event));
+ }
+ }
+}
+
+int
+ixl_rebuild_vfs_after_reset(struct ixl_pf *pf)
+{
+ struct i40e_hw *hw;
+ struct ixl_vf *vf;
+ uint32_t vfrtrig;
+ int error, first_error, i;
+
+ hw = &pf->hw;
+ pf->veb_seid = 0;
+ for (i = 0; i < pf->num_vfs; i++) {
+ vf = &pf->vfs[i];
+ if (!(vf->vf_flags & VF_FLAG_ENABLED))
+ continue;
+
+ vf->vf_flags &= ~VF_FLAG_INITIALIZED;
+ vf->vsi.seid = 0;
+ vf->vsi.vsi_num = 0;
+ vf->vsi.num_tx_queues = 0;
+ vf->vsi.num_rx_queues = 0;
+ bzero(&vf->vsi.info, sizeof(vf->vsi.info));
+ ixl_pf_qmgr_clear_queue_flags(&vf->qtag);
+ ixl_free_filters(&vf->vsi.ftl);
+ vf->vsi.num_hw_filters = 0;
+ vf->vsi.num_macs = 0;
+ vf->vsi.num_vlans = 0;
+ bit_nclear(vf->vsi.vlans_map, 0,
+ IXL_VLANS_MAP_LEN - 1);
+ vf->num_mac_filters = 0;
+ }
+
+ error = ixl_setup_iov_switch(pf);
+ if (error != 0)
+ return (error);
+
+ first_error = 0;
+ for (i = 0; i < pf->num_vfs; i++) {
+ vf = &pf->vfs[i];
+ if (!(vf->vf_flags & VF_FLAG_ENABLED))
+ continue;
+
+ wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num),
+ VIRTCHNL_VFR_COMPLETED);
+ vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
+ vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
+ wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
+
+ error = ixl_vf_setup_vsi(pf, vf);
+ if (error != 0) {
+ device_printf(pf->dev,
+ "Failed to rebuild VF-%d: %d\n", i, error);
+ if (first_error == 0)
+ first_error = error;
+ continue;
+ }
+ ixl_vf_map_queues(pf, vf);
+ wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num),
+ VIRTCHNL_VFR_VFACTIVE);
+ }
+ ixl_flush(hw);
+ return (first_error);
+}
+
+int
+ixl_if_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params)
+{
+ struct ixl_pf *pf = iflib_get_softc(ctx);
+ int error, i;
pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT |
M_ZERO);
@@ -2001,28 +2116,9 @@ ixl_if_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params)
for (i = 0; i < num_vfs; i++)
sysctl_ctx_init(&pf->vfs[i].vsi.sysctl_ctx);
- /*
- * Add the VEB and ...
- * - do nothing: VEPA mode
- * - enable loopback mode on connected VSIs: VEB mode
- */
- ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid,
- 1, FALSE, &pf->veb_seid, FALSE, NULL);
- if (ret != I40E_SUCCESS) {
- error = hw->aq.asq_last_status;
- device_printf(dev, "i40e_aq_add_veb failed; status %s error %s",
- i40e_stat_str(hw, ret), i40e_aq_str(hw, error));
+ error = ixl_setup_iov_switch(pf);
+ if (error != 0)
goto fail;
- }
- if (pf->enable_vf_loopback)
- ixl_config_pf_vsi_loopback(pf, true);
-
- /*
- * Adding a VEB brings back the default MAC filter(s). Remove them,
- * and let the driver add the proper filters back.
- */
- ixl_del_default_hw_filters(pf_vsi);
- ixl_reconfigure_filters(pf_vsi);
pf->num_vfs = num_vfs;
return (0);
diff --git a/sys/dev/ixl/ixl_pf_main.c b/sys/dev/ixl/ixl_pf_main.c
index 674e45823cc4..cb6f64f66209 100644
--- a/sys/dev/ixl/ixl_pf_main.c
+++ b/sys/dev/ixl/ixl_pf_main.c
@@ -494,7 +494,7 @@ ixl_set_initial_advertised_speeds(struct ixl_pf *pf)
int
ixl_teardown_hw_structs(struct ixl_pf *pf)
{
- enum i40e_status_code status = 0;
+ enum i40e_status_code error, status = I40E_SUCCESS;
struct i40e_hw *hw = &pf->hw;
device_t dev = pf->dev;
@@ -505,20 +505,21 @@ ixl_teardown_hw_structs(struct ixl_pf *pf)
device_printf(dev,
"init: LAN HMC shutdown failure; status %s\n",
i40e_stat_str(hw, status));
- goto err_out;
}
}
/* Shutdown admin queue */
ixl_disable_intr0(hw);
- status = i40e_shutdown_adminq(hw);
- if (status)
+ error = i40e_shutdown_adminq(hw);
+ if (error) {
device_printf(dev,
"init: Admin Queue shutdown failure; status %s\n",
- i40e_stat_str(hw, status));
+ i40e_stat_str(hw, error));
+ if (status == I40E_SUCCESS)
+ status = error;
+ }
ixl_pf_qmgr_release(&pf->qmgr, &pf->qtag);
-err_out:
return (status);
}