static int efx_ef10_probe_vf(struct efx_nic *efx)
{
int rc;
+ struct pci_dev *pci_dev_pf;
+
+ /* If the parent PF has no VF data structure, it doesn't know about this
+ * VF so fail probe. The VF needs to be re-created. This can happen
+ * if the PF driver is unloaded while the VF is assigned to a guest.
+ */
+ pci_dev_pf = efx->pci_dev->physfn;
+ if (pci_dev_pf) {
+ struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf);
+ struct efx_ef10_nic_data *nic_data_pf = efx_pf->nic_data;
+
+ if (!nic_data_pf->vf) {
+ netif_info(efx, drv, efx->net_dev,
+ "The VF cannot link to its parent PF; "
+ "please destroy and re-create the VF\n");
+ return -EBUSY;
+ }
+ }
rc = efx_ef10_probe(efx);
if (rc)
struct efx_ef10_nic_data *nic_data = efx->nic_data;
nic_data_p->vf[nic_data->vf_index].efx = efx;
+ nic_data_p->vf[nic_data->vf_index].pci_dev =
+ efx->pci_dev;
} else
netif_info(efx, drv, efx->net_dev,
"Could not get the PF id from VF\n");
for (i = 0; i < efx->vf_count; i++) {
struct ef10_vf *vf = nic_data->vf + i;
+ /* If VF is assigned, do not free the vport */
+ if (vf->pci_dev &&
+ vf->pci_dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
+ continue;
+
if (vf->vport_assigned) {
efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, i);
vf->vport_assigned = 0;
efx_ef10_vport_free(efx, nic_data->vport_id);
nic_data->vport_id = EVB_PORT_ID_ASSIGNED;
- efx_ef10_vswitch_free(efx, nic_data->vport_id);
+ /* Only free the vswitch if no VFs are assigned */
+ if (!pci_vfs_assigned(efx->pci_dev))
+ efx_ef10_vswitch_free(efx, nic_data->vport_id);
}
void efx_ef10_vswitching_remove_vf(struct efx_nic *efx)
return rc;
}
-static int efx_ef10_pci_sriov_disable(struct efx_nic *efx)
+static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force)
{
struct pci_dev *dev = efx->pci_dev;
+ unsigned int vfs_assigned = 0;
- if (!efx->vf_count)
- return 0;
+ vfs_assigned = pci_vfs_assigned(dev);
- if (pci_vfs_assigned(dev)) {
- netif_err(efx, drv, efx->net_dev, "VFs are assigned to guests; "
- "please detach them before disabling SR-IOV\n");
+ if (vfs_assigned && !force) {
+ netif_info(efx, drv, efx->net_dev, "VFs are assigned to guests; "
+ "please detach them before disabling SR-IOV\n");
return -EBUSY;
}
- pci_disable_sriov(dev);
+ if (!vfs_assigned)
+ pci_disable_sriov(dev);
+
efx_ef10_sriov_free_vf_vswitching(efx);
efx->vf_count = 0;
return 0;
int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs)
{
if (num_vfs == 0)
- return efx_ef10_pci_sriov_disable(efx);
+ return efx_ef10_pci_sriov_disable(efx, false);
else
return efx_ef10_pci_sriov_enable(efx, num_vfs);
}
unsigned int i;
int rc;
- if (!nic_data->vf)
+ if (!nic_data->vf) {
+ /* Remove any un-assigned orphaned VFs */
+ if (pci_num_vf(efx->pci_dev) && !pci_vfs_assigned(efx->pci_dev))
+ pci_disable_sriov(efx->pci_dev);
return;
+ }
/* Remove any VFs in the host */
for (i = 0; i < efx->vf_count; ++i) {
vf_efx->pci_dev->driver->remove(vf_efx->pci_dev);
}
- rc = efx_ef10_pci_sriov_disable(efx);
+ rc = efx_ef10_pci_sriov_disable(efx, true);
if (rc)
netif_dbg(efx, drv, efx->net_dev,
"Disabling SRIOV was not successful rc=%d\n", rc);