summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc/ef10_sriov.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/sfc/ef10_sriov.c')
-rw-r--r--drivers/net/ethernet/sfc/ef10_sriov.c35
1 files changed, 24 insertions, 11 deletions
diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c
index 41ab18d4b107..6c9b6e45509a 100644
--- a/drivers/net/ethernet/sfc/ef10_sriov.c
+++ b/drivers/net/ethernet/sfc/ef10_sriov.c
@@ -165,6 +165,11 @@ static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx)
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;
@@ -380,7 +385,9 @@ void efx_ef10_vswitching_remove_pf(struct efx_nic *efx)
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)
@@ -413,20 +420,22 @@ fail1:
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;
@@ -435,7 +444,7 @@ static int efx_ef10_pci_sriov_disable(struct efx_nic *efx)
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);
}
@@ -451,8 +460,12 @@ void efx_ef10_sriov_fini(struct efx_nic *efx)
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) {
@@ -462,7 +475,7 @@ void efx_ef10_sriov_fini(struct efx_nic *efx)
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);
OpenPOWER on IntegriCloud