提交 fc18eaa0 编写于 作者: M Mitch Williams 提交者: 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: NMitch Williams <mitch.a.williams@intel.com>
Signed-off-by: NJesse Brandeburg <jesse.brandeburg@intel.com>
Tested-by: NKavindya Deegala <kavindya.s.deegala@intel.com>
Signed-off-by: NJeff Kirsher <jeffrey.t.kirsher@intel.com>
上级 805bd5bd
...@@ -543,6 +543,7 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, ...@@ -543,6 +543,7 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
int i40e_vsi_release(struct i40e_vsi *vsi); 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 *i40e_vsi_lookup(struct i40e_pf *pf, enum i40e_vsi_type type,
struct i40e_vsi *start_vsi); 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); 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, struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, u16 uplink_seid,
u16 downlink_seid, u8 enabled_tc); u16 downlink_seid, u8 enabled_tc);
......
...@@ -3110,7 +3110,7 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable) ...@@ -3110,7 +3110,7 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
* @vsi: the VSI being configured * @vsi: the VSI being configured
* @enable: start or stop the rings * @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; int ret;
......
...@@ -621,6 +621,9 @@ static void i40e_disable_vf_mappings(struct i40e_vf *vf) ...@@ -621,6 +621,9 @@ static void i40e_disable_vf_mappings(struct i40e_vf *vf)
static void i40e_free_vf_res(struct i40e_vf *vf) static void i40e_free_vf_res(struct i40e_vf *vf)
{ {
struct i40e_pf *pf = vf->pf; 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 */ /* free vsi & disconnect it from the parent uplink */
if (vf->lan_vsi_index) { if (vf->lan_vsi_index) {
...@@ -628,7 +631,34 @@ static void i40e_free_vf_res(struct i40e_vf *vf) ...@@ -628,7 +631,34 @@ static void i40e_free_vf_res(struct i40e_vf *vf)
vf->lan_vsi_index = 0; vf->lan_vsi_index = 0;
vf->lan_vsi_id = 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 /* reset some of the state varibles keeping
* track of the resources * track of the resources
*/ */
...@@ -670,6 +700,36 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf) ...@@ -670,6 +700,36 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf)
return ret; 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 * i40e_reset_vf
* @vf: pointer to the vf structure * @vf: pointer to the vf structure
...@@ -677,35 +737,36 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf) ...@@ -677,35 +737,36 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf)
* *
* reset the 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_pf *pf = vf->pf;
struct i40e_hw *hw = &pf->hw; struct i40e_hw *hw = &pf->hw;
u32 reg, reg_idx, msix_vf;
bool rsd = false; bool rsd = false;
u16 pf_queue_id; int i;
int i, j; u32 reg;
/* warn the VF */ /* warn the VF */
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_INPROGRESS);
clear_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states); clear_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states);
/* PF triggers VFR only when VF requests, in case of /* In the case of a VFLR, the HW has already reset the VF and we
* VFLR, HW triggers VFR * just need to clean up, so don't hit the VFRTRIG register.
*/ */
if (!flr) { if (!flr) {
/* reset vf using VPGEN_VFRTRIG reg */ /* 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); wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
i40e_flush(hw); 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 /* poll VPGEN_VFRSTAT reg to make sure
* that reset is complete * 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 reset requires driver to first reset the
* vf & than poll the status register to make sure * vf & than poll the status register to make sure
* that the requested op was completed * that the requested op was completed
...@@ -720,84 +781,29 @@ int i40e_reset_vf(struct i40e_vf *vf, bool flr) ...@@ -720,84 +781,29 @@ int i40e_reset_vf(struct i40e_vf *vf, bool flr)
} }
if (!rsd) 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); vf->vf_id);
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_COMPLETED);
/* 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);
}
/* clear the reset bit in the VPGEN_VFRTRIG reg */ /* clear the reset bit in the VPGEN_VFRTRIG reg */
reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id)); reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id));
reg &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK; reg &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg); 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 */ /* 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); i40e_flush(hw);
return ret;
} }
/** /**
...@@ -909,11 +915,8 @@ static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) ...@@ -909,11 +915,8 @@ static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
/* assign default capabilities */ /* assign default capabilities */
set_bit(I40E_VIRTCHNL_VF_CAP_L2, &vfs[i].vf_caps); set_bit(I40E_VIRTCHNL_VF_CAP_L2, &vfs[i].vf_caps);
/* vf resources get allocated during reset */
ret = i40e_alloc_vf_res(&vfs[i]); i40e_reset_vf(&vfs[i], false);
i40e_reset_vf(&vfs[i], true);
if (ret)
break;
/* enable vf vplan_qtable mappings */ /* enable vf vplan_qtable mappings */
i40e_enable_vf_mappings(&vfs[i]); i40e_enable_vf_mappings(&vfs[i]);
...@@ -1140,12 +1143,10 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf) ...@@ -1140,12 +1143,10 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf)
* unlike other virtchnl messages, pf driver * unlike other virtchnl messages, pf driver
* doesn't send the response back to the vf * 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)) if (test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states))
return -ENOENT; i40e_reset_vf(vf, false);
return 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, ...@@ -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); ret = i40e_vc_get_vf_resources_msg(vf);
break; break;
case I40E_VIRTCHNL_OP_RESET_VF: case I40E_VIRTCHNL_OP_RESET_VF:
ret = i40e_vc_reset_vf_msg(vf); i40e_vc_reset_vf_msg(vf);
ret = 0;
break; break;
case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
ret = i40e_vc_config_promiscuous_mode_msg(vf, msg, msglen); ret = i40e_vc_config_promiscuous_mode_msg(vf, msg, msglen);
...@@ -1950,19 +1952,7 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf) ...@@ -1950,19 +1952,7 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf)
/* clear the bit in GLGEN_VFLRSTAT */ /* clear the bit in GLGEN_VFLRSTAT */
wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx)); wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx));
if (i40e_reset_vf(vf, true)) 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);
} }
} }
......
...@@ -104,7 +104,7 @@ int i40e_pci_sriov_configure(struct pci_dev *dev, int num_vfs); ...@@ -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, int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode,
u32 v_retval, u8 *msg, u16 msglen); u32 v_retval, u8 *msg, u16 msglen);
int i40e_vc_process_vflr_event(struct i40e_pf *pf); 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); void i40e_vc_notify_vf_reset(struct i40e_vf *vf);
/* vf configuration related iplink handlers */ /* vf configuration related iplink handlers */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册