sfc: move table locking into filter_table_{probe,remove} methods
authorEdward Cree <ecree.xilinx@gmail.com>
Thu, 28 Jul 2022 18:57:50 +0000 (19:57 +0100)
committerJakub Kicinski <kuba@kernel.org>
Sat, 30 Jul 2022 04:22:06 +0000 (21:22 -0700)
We need to be able to drop the efx->filter_sem in ef100_filter_table_up()
 so that we can call functions that insert filters (and thus take that
 rwsem for read), which means the efx->type->filter_table_probe method
 needs to be responsible for taking the lock in the first place.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/ef100_nic.c
drivers/net/ethernet/sfc/ef10_sriov.c
drivers/net/ethernet/sfc/mcdi_filters.h
drivers/net/ethernet/sfc/rx_common.c

index ab979fd..ee734b6 100644 (file)
@@ -2538,23 +2538,33 @@ static int efx_ef10_filter_table_probe(struct efx_nic *efx)
 
        if (rc)
                return rc;
+       down_write(&efx->filter_sem);
        rc = efx_mcdi_filter_table_probe(efx, nic_data->workaround_26807);
 
        if (rc)
-               return rc;
+               goto out_unlock;
 
        list_for_each_entry(vlan, &nic_data->vlan_list, list) {
                rc = efx_mcdi_filter_add_vlan(efx, vlan->vid);
                if (rc)
                        goto fail_add_vlan;
        }
-       return 0;
+       goto out_unlock;
 
 fail_add_vlan:
        efx_mcdi_filter_table_remove(efx);
+out_unlock:
+       up_write(&efx->filter_sem);
        return rc;
 }
 
+static void efx_ef10_filter_table_remove(struct efx_nic *efx)
+{
+       down_write(&efx->filter_sem);
+       efx_mcdi_filter_table_remove(efx);
+       up_write(&efx->filter_sem);
+}
+
 /* This creates an entry in the RX descriptor queue */
 static inline void
 efx_ef10_build_rx_desc(struct efx_rx_queue *rx_queue, unsigned int index)
@@ -3211,9 +3221,7 @@ static int efx_ef10_vport_set_mac_address(struct efx_nic *efx)
 
        efx_device_detach_sync(efx);
        efx_net_stop(efx->net_dev);
-       down_write(&efx->filter_sem);
-       efx_mcdi_filter_table_remove(efx);
-       up_write(&efx->filter_sem);
+       efx_ef10_filter_table_remove(efx);
 
        rc = efx_ef10_vadaptor_free(efx, efx->vport_id);
        if (rc)
@@ -3243,9 +3251,7 @@ restore_vadaptor:
        if (rc2)
                goto reset_nic;
 restore_filters:
-       down_write(&efx->filter_sem);
        rc2 = efx_ef10_filter_table_probe(efx);
-       up_write(&efx->filter_sem);
        if (rc2)
                goto reset_nic;
 
@@ -3275,8 +3281,7 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx)
        efx_net_stop(efx->net_dev);
 
        mutex_lock(&efx->mac_lock);
-       down_write(&efx->filter_sem);
-       efx_mcdi_filter_table_remove(efx);
+       efx_ef10_filter_table_remove(efx);
 
        ether_addr_copy(MCDI_PTR(inbuf, VADAPTOR_SET_MAC_IN_MACADDR),
                        efx->net_dev->dev_addr);
@@ -3286,7 +3291,6 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx)
                                sizeof(inbuf), NULL, 0, NULL);
 
        efx_ef10_filter_table_probe(efx);
-       up_write(&efx->filter_sem);
        mutex_unlock(&efx->mac_lock);
 
        if (was_enabled)
@@ -4092,7 +4096,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
        .ev_test_generate = efx_ef10_ev_test_generate,
        .filter_table_probe = efx_ef10_filter_table_probe,
        .filter_table_restore = efx_mcdi_filter_table_restore,
-       .filter_table_remove = efx_mcdi_filter_table_remove,
+       .filter_table_remove = efx_ef10_filter_table_remove,
        .filter_update_rx_scatter = efx_mcdi_update_rx_scatter,
        .filter_insert = efx_mcdi_filter_insert,
        .filter_remove_safe = efx_mcdi_filter_remove_safe,
index 25cd43e..5fe18b3 100644 (file)
@@ -375,26 +375,32 @@ static int ef100_filter_table_up(struct efx_nic *efx)
 {
        int rc;
 
+       down_write(&efx->filter_sem);
        rc = efx_mcdi_filter_add_vlan(efx, EFX_FILTER_VID_UNSPEC);
-       if (rc) {
-               efx_mcdi_filter_table_down(efx);
-               return rc;
-       }
+       if (rc)
+               goto fail_unspec;
 
        rc = efx_mcdi_filter_add_vlan(efx, 0);
-       if (rc) {
-               efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC);
-               efx_mcdi_filter_table_down(efx);
-       }
+       if (rc)
+               goto fail_vlan0;
+       up_write(&efx->filter_sem);
+       return 0;
 
+fail_vlan0:
+       efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC);
+fail_unspec:
+       efx_mcdi_filter_table_down(efx);
+       up_write(&efx->filter_sem);
        return rc;
 }
 
 static void ef100_filter_table_down(struct efx_nic *efx)
 {
+       down_write(&efx->filter_sem);
        efx_mcdi_filter_del_vlan(efx, 0);
        efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC);
        efx_mcdi_filter_table_down(efx);
+       up_write(&efx->filter_sem);
 }
 
 /*     Other
index 92550c7..9aae0d8 100644 (file)
@@ -501,14 +501,11 @@ int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, const u8 *mac)
                efx_device_detach_sync(vf->efx);
                efx_net_stop(vf->efx->net_dev);
 
-               down_write(&vf->efx->filter_sem);
                vf->efx->type->filter_table_remove(vf->efx);
 
                rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED);
-               if (rc) {
-                       up_write(&vf->efx->filter_sem);
+               if (rc)
                        return rc;
-               }
        }
 
        rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_i);
@@ -539,12 +536,9 @@ int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, const u8 *mac)
        if (vf->efx) {
                /* VF cannot use the vport_id that the PF created */
                rc = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED);
-               if (rc) {
-                       up_write(&vf->efx->filter_sem);
+               if (rc)
                        return rc;
-               }
                vf->efx->type->filter_table_probe(vf->efx);
-               up_write(&vf->efx->filter_sem);
                efx_net_open(vf->efx->net_dev);
                efx_device_attach_if_not_resetting(vf->efx);
        }
@@ -580,7 +574,6 @@ int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan,
                efx_net_stop(vf->efx->net_dev);
 
                mutex_lock(&vf->efx->mac_lock);
-               down_write(&vf->efx->filter_sem);
                vf->efx->type->filter_table_remove(vf->efx);
 
                rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED);
@@ -654,7 +647,6 @@ restore_filters:
                if (rc2)
                        goto reset_nic_up_write;
 
-               up_write(&vf->efx->filter_sem);
                mutex_unlock(&vf->efx->mac_lock);
 
                rc2 = efx_net_open(vf->efx->net_dev);
@@ -666,10 +658,8 @@ restore_filters:
        return rc;
 
 reset_nic_up_write:
-       if (vf->efx) {
-               up_write(&vf->efx->filter_sem);
+       if (vf->efx)
                mutex_unlock(&vf->efx->mac_lock);
-       }
 reset_nic:
        if (vf->efx) {
                netif_err(efx, drv, efx->net_dev,
index 06426aa..c0d6558 100644 (file)
@@ -89,6 +89,7 @@ struct efx_mcdi_filter_table {
         */
        bool mc_chaining;
        bool vlan_filter;
+       /* Entries on the vlan_list are added/removed under filter_sem */
        struct list_head vlan_list;
 };
 
index bd21d6a..4826e6a 100644 (file)
@@ -793,7 +793,6 @@ int efx_probe_filters(struct efx_nic *efx)
        int rc;
 
        mutex_lock(&efx->mac_lock);
-       down_write(&efx->filter_sem);
        rc = efx->type->filter_table_probe(efx);
        if (rc)
                goto out_unlock;
@@ -830,7 +829,6 @@ int efx_probe_filters(struct efx_nic *efx)
        }
 #endif
 out_unlock:
-       up_write(&efx->filter_sem);
        mutex_unlock(&efx->mac_lock);
        return rc;
 }
@@ -846,9 +844,7 @@ void efx_remove_filters(struct efx_nic *efx)
                channel->rps_flow_id = NULL;
        }
 #endif
-       down_write(&efx->filter_sem);
        efx->type->filter_table_remove(efx);
-       up_write(&efx->filter_sem);
 }
 
 #ifdef CONFIG_RFS_ACCEL