Commit fc18eaa0 authored by Mitch Williams's avatar Mitch Williams Committed by Jeff Kirsher

i40e: refactor VF reset flow

Fix the VF reset flow so that it works on real hardware. After
discussions with the HW team, the reset flow has been changed
somewhat.

- Change the i40e_reset_vf function to a void type, and fix
  up the callers to reflect this.
- Move the MSI-X disable code to i40e_free_vf_res since it must
  be done every time the VF is freed, regardless of whether or
  not it is reset.
- Ensure that the PCIe bus is quiet before polling the reset bit.
- Don't clear the VFGEN_RSTAT1 register at the beginning as it is
  cleared by the reset.
- Poll longer for the reset to be done.
- Disable the queues using an existing function rather than
  rolling our own.
- Free and reallocate the VSI after reset to avoid rx hang.

Change-Id: I11e2590431cb73e8663714d1cc5b23d59b809033
Signed-off-by: default avatarMitch Williams <mitch.a.williams@intel.com>
Signed-off-by: default avatarJesse Brandeburg <jesse.brandeburg@intel.com>
Tested-by: default avatarKavindya Deegala <kavindya.s.deegala@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 805bd5bd
......@@ -543,6 +543,7 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
int i40e_vsi_release(struct i40e_vsi *vsi);
struct i40e_vsi *i40e_vsi_lookup(struct i40e_pf *pf, enum i40e_vsi_type type,
struct i40e_vsi *start_vsi);
int i40e_vsi_control_rings(struct i40e_vsi *vsi, bool enable);
int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count);
struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, u16 uplink_seid,
u16 downlink_seid, u8 enabled_tc);
......
......@@ -3110,7 +3110,7 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
* @vsi: the VSI being configured
* @enable: start or stop the rings
**/
static int i40e_vsi_control_rings(struct i40e_vsi *vsi, bool request)
int i40e_vsi_control_rings(struct i40e_vsi *vsi, bool request)
{
int ret;
......
......@@ -621,6 +621,9 @@ static void i40e_disable_vf_mappings(struct i40e_vf *vf)
static void i40e_free_vf_res(struct i40e_vf *vf)
{
struct i40e_pf *pf = vf->pf;
struct i40e_hw *hw = &pf->hw;
u32 reg_idx, reg;
int i, msix_vf;
/* free vsi & disconnect it from the parent uplink */
if (vf->lan_vsi_index) {
......@@ -628,7 +631,34 @@ static void i40e_free_vf_res(struct i40e_vf *vf)
vf->lan_vsi_index = 0;
vf->lan_vsi_id = 0;
}
msix_vf = pf->hw.func_caps.num_msix_vectors_vf + 1;
/* disable interrupts so the VF starts in a known state */
for (i = 0; i < msix_vf; i++) {
/* format is same for both registers */
if (0 == i)
reg_idx = I40E_VFINT_DYN_CTL0(vf->vf_id);
else
reg_idx = I40E_VFINT_DYN_CTLN(((msix_vf - 1) *
(vf->vf_id))
+ (i - 1));
wr32(hw, reg_idx, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
i40e_flush(hw);
}
/* clear the irq settings */
for (i = 0; i < msix_vf; i++) {
/* format is same for both registers */
if (0 == i)
reg_idx = I40E_VPINT_LNKLST0(vf->vf_id);
else
reg_idx = I40E_VPINT_LNKLSTN(((msix_vf - 1) *
(vf->vf_id))
+ (i - 1));
reg = (I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK |
I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
wr32(hw, reg_idx, reg);
i40e_flush(hw);
}
/* reset some of the state varibles keeping
* track of the resources
*/
......@@ -670,6 +700,36 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf)
return ret;
}
#define VF_DEVICE_STATUS 0xAA
#define VF_TRANS_PENDING_MASK 0x20
/**
* i40e_quiesce_vf_pci
* @vf: pointer to the vf structure
*
* Wait for VF PCI transactions to be cleared after reset. Returns -EIO
* if the transactions never clear.
**/
static int i40e_quiesce_vf_pci(struct i40e_vf *vf)
{
struct i40e_pf *pf = vf->pf;
struct i40e_hw *hw = &pf->hw;
int vf_abs_id, i;
u32 reg;
reg = rd32(hw, I40E_PF_VT_PFALLOC);
vf_abs_id = vf->vf_id + (reg & I40E_PF_VT_PFALLOC_FIRSTVF_MASK);
wr32(hw, I40E_PF_PCI_CIAA,
VF_DEVICE_STATUS | (vf_abs_id << I40E_PF_PCI_CIAA_VF_NUM_SHIFT));
for (i = 0; i < 100; i++) {
reg = rd32(hw, I40E_PF_PCI_CIAD);
if ((reg & VF_TRANS_PENDING_MASK) == 0)
return 0;
udelay(1);
}
return -EIO;
}
/**
* i40e_reset_vf
* @vf: pointer to the vf structure
......@@ -677,35 +737,36 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf)
*
* reset the vf
**/
int i40e_reset_vf(struct i40e_vf *vf, bool flr)
void i40e_reset_vf(struct i40e_vf *vf, bool flr)
{
int ret = -ENOENT;
struct i40e_pf *pf = vf->pf;
struct i40e_hw *hw = &pf->hw;
u32 reg, reg_idx, msix_vf;
bool rsd = false;
u16 pf_queue_id;
int i, j;
int i;
u32 reg;
/* warn the VF */
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_INPROGRESS);
clear_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states);
/* PF triggers VFR only when VF requests, in case of
* VFLR, HW triggers VFR
/* In the case of a VFLR, the HW has already reset the VF and we
* just need to clean up, so don't hit the VFRTRIG register.
*/
if (!flr) {
/* reset vf using VPGEN_VFRTRIG reg */
reg = I40E_VPGEN_VFRTRIG_VFSWR_MASK;
reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id));
reg |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
i40e_flush(hw);
}
if (i40e_quiesce_vf_pci(vf))
dev_err(&pf->pdev->dev, "VF %d PCI transactions stuck\n",
vf->vf_id);
/* poll VPGEN_VFRSTAT reg to make sure
* that reset is complete
*/
for (i = 0; i < 4; i++) {
for (i = 0; i < 100; i++) {
/* vf reset requires driver to first reset the
* vf & than poll the status register to make sure
* that the requested op was completed
......@@ -720,84 +781,29 @@ int i40e_reset_vf(struct i40e_vf *vf, bool flr)
}
if (!rsd)
dev_err(&pf->pdev->dev, "VF reset check timeout %d\n",
dev_err(&pf->pdev->dev, "VF reset check timeout on VF %d\n",
vf->vf_id);
/* fast disable qps */
for (j = 0; j < pf->vsi[vf->lan_vsi_index]->num_queue_pairs; j++) {
ret = i40e_ctrl_vsi_tx_queue(vf, vf->lan_vsi_index, j,
I40E_QUEUE_CTRL_FASTDISABLE);
ret = i40e_ctrl_vsi_rx_queue(vf, vf->lan_vsi_index, j,
I40E_QUEUE_CTRL_FASTDISABLE);
}
/* Queue enable/disable requires driver to
* first reset the vf & than poll the status register
* to make sure that the requested op was completed
* successfully
*/
udelay(10);
for (j = 0; j < pf->vsi[vf->lan_vsi_index]->num_queue_pairs; j++) {
ret = i40e_ctrl_vsi_tx_queue(vf, vf->lan_vsi_index, j,
I40E_QUEUE_CTRL_FASTDISABLECHECK);
if (ret)
dev_info(&pf->pdev->dev,
"Queue control check failed on Tx queue %d of VSI %d VF %d\n",
j, vf->lan_vsi_index, vf->vf_id);
ret = i40e_ctrl_vsi_rx_queue(vf, vf->lan_vsi_index, j,
I40E_QUEUE_CTRL_FASTDISABLECHECK);
if (ret)
dev_info(&pf->pdev->dev,
"Queue control check failed on Rx queue %d of VSI %d VF %d\n",
j, vf->lan_vsi_index, vf->vf_id);
}
/* clear the irq settings */
msix_vf = pf->hw.func_caps.num_msix_vectors_vf;
for (i = 0; i < msix_vf; i++) {
/* format is same for both registers */
if (0 == i)
reg_idx = I40E_VPINT_LNKLST0(vf->vf_id);
else
reg_idx = I40E_VPINT_LNKLSTN(((msix_vf - 1) *
(vf->vf_id))
+ (i - 1));
reg = (I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK |
I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
wr32(hw, reg_idx, reg);
i40e_flush(hw);
}
/* disable interrupts so the VF starts in a known state */
for (i = 0; i < msix_vf; i++) {
/* format is same for both registers */
if (0 == i)
reg_idx = I40E_VFINT_DYN_CTL0(vf->vf_id);
else
reg_idx = I40E_VFINT_DYN_CTLN(((msix_vf - 1) *
(vf->vf_id))
+ (i - 1));
wr32(hw, reg_idx, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
i40e_flush(hw);
}
/* set the defaults for the rqctl & tqctl registers */
reg = (I40E_QINT_RQCTL_NEXTQ_INDX_MASK | I40E_QINT_RQCTL_ITR_INDX_MASK |
I40E_QINT_RQCTL_NEXTQ_TYPE_MASK);
for (j = 0; j < pf->vsi[vf->lan_vsi_index]->num_queue_pairs; j++) {
pf_queue_id = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_index, j);
wr32(hw, I40E_QINT_RQCTL(pf_queue_id), reg);
wr32(hw, I40E_QINT_TQCTL(pf_queue_id), reg);
}
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_COMPLETED);
/* clear the reset bit in the VPGEN_VFRTRIG reg */
reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id));
reg &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
/* On initial reset, we won't have any queues */
if (vf->lan_vsi_index == 0)
goto complete_reset;
i40e_vsi_control_rings(pf->vsi[vf->lan_vsi_index], false);
complete_reset:
/* reallocate vf resources to reset the VSI state */
i40e_free_vf_res(vf);
mdelay(10);
i40e_alloc_vf_res(vf);
i40e_enable_vf_mappings(vf);
/* tell the VF the reset is done */
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_COMPLETED);
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE);
i40e_flush(hw);
return ret;
}
/**
......@@ -909,11 +915,8 @@ static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
/* assign default capabilities */
set_bit(I40E_VIRTCHNL_VF_CAP_L2, &vfs[i].vf_caps);
ret = i40e_alloc_vf_res(&vfs[i]);
i40e_reset_vf(&vfs[i], true);
if (ret)
break;
/* vf resources get allocated during reset */
i40e_reset_vf(&vfs[i], false);
/* enable vf vplan_qtable mappings */
i40e_enable_vf_mappings(&vfs[i]);
......@@ -1140,12 +1143,10 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf)
* unlike other virtchnl messages, pf driver
* doesn't send the response back to the vf
**/
static int i40e_vc_reset_vf_msg(struct i40e_vf *vf)
static void i40e_vc_reset_vf_msg(struct i40e_vf *vf)
{
if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states))
return -ENOENT;
return i40e_reset_vf(vf, false);
if (test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states))
i40e_reset_vf(vf, false);
}
/**
......@@ -1879,7 +1880,8 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode,
ret = i40e_vc_get_vf_resources_msg(vf);
break;
case I40E_VIRTCHNL_OP_RESET_VF:
ret = i40e_vc_reset_vf_msg(vf);
i40e_vc_reset_vf_msg(vf);
ret = 0;
break;
case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
ret = i40e_vc_config_promiscuous_mode_msg(vf, msg, msglen);
......@@ -1950,19 +1952,7 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf)
/* clear the bit in GLGEN_VFLRSTAT */
wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx));
if (i40e_reset_vf(vf, true))
dev_err(&pf->pdev->dev,
"Unable to reset the VF %d\n", vf_id);
/* free up vf resources to destroy vsi state */
i40e_free_vf_res(vf);
/* allocate new vf resources with the default state */
if (i40e_alloc_vf_res(vf))
dev_err(&pf->pdev->dev,
"Unable to allocate VF resources %d\n",
vf_id);
i40e_enable_vf_mappings(vf);
i40e_reset_vf(vf, true);
}
}
......
......@@ -104,7 +104,7 @@ int i40e_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode,
u32 v_retval, u8 *msg, u16 msglen);
int i40e_vc_process_vflr_event(struct i40e_pf *pf);
int i40e_reset_vf(struct i40e_vf *vf, bool flr);
void i40e_reset_vf(struct i40e_vf *vf, bool flr);
void i40e_vc_notify_vf_reset(struct i40e_vf *vf);
/* vf configuration related iplink handlers */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment