]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
sfc: use new rxfh_context API
authorEdward Cree <ecree.xilinx@gmail.com>
Thu, 27 Jun 2024 15:33:52 +0000 (16:33 +0100)
committerJakub Kicinski <kuba@kernel.org>
Sat, 29 Jun 2024 01:53:21 +0000 (18:53 -0700)
The core is now responsible for allocating IDs and a memory region for
 us to store our state (struct efx_rss_context_priv), so we no longer
 need efx_alloc_rss_context_entry() and friends.
Since the contexts are now maintained by the core, use the core's lock
 (net_dev->ethtool->rss_lock), rather than our own mutex (efx->rss_lock),
 to serialise access against changes; and remove the now-unused
 efx->rss_lock from struct efx_nic.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Link: https://patch.msgid.link/150274740ea8cc137fef5502541ce573d32fb319.1719502240.git.ecree.xilinx@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
13 files changed:
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/ef100_ethtool.c
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/efx.h
drivers/net/ethernet/sfc/efx_common.c
drivers/net/ethernet/sfc/ethtool.c
drivers/net/ethernet/sfc/ethtool_common.c
drivers/net/ethernet/sfc/ethtool_common.h
drivers/net/ethernet/sfc/mcdi_filters.c
drivers/net/ethernet/sfc/mcdi_filters.h
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sfc/rx_common.c
drivers/net/ethernet/sfc/rx_common.h

index 8fa6c0e9195b09486f57eef6cdc1aa227e74d172..7d69302ffa0af06ab6180ba2a18c4a19858c33d3 100644 (file)
@@ -1396,7 +1396,7 @@ static void efx_ef10_table_reset_mc_allocations(struct efx_nic *efx)
        efx_mcdi_filter_table_reset_mc_allocations(efx);
        nic_data->must_restore_piobufs = true;
        efx_ef10_forget_old_piobufs(efx);
-       efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
+       efx->rss_context.priv.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
 
        /* Driver-created vswitches and vports must be re-created */
        nic_data->must_probe_vswitching = true;
index cf55202b3a7bc7a652f43ceab8be0cb4179ec98b..896ffca4aee2b30e7d3ec739a35ba85a86f507b3 100644 (file)
@@ -59,8 +59,12 @@ const struct ethtool_ops ef100_ethtool_ops = {
 
        .get_rxfh_indir_size    = efx_ethtool_get_rxfh_indir_size,
        .get_rxfh_key_size      = efx_ethtool_get_rxfh_key_size,
+       .rxfh_priv_size         = sizeof(struct efx_rss_context_priv),
        .get_rxfh               = efx_ethtool_get_rxfh,
        .set_rxfh               = efx_ethtool_set_rxfh,
+       .create_rxfh_context    = efx_ethtool_create_rxfh_context,
+       .modify_rxfh_context    = efx_ethtool_modify_rxfh_context,
+       .remove_rxfh_context    = efx_ethtool_remove_rxfh_context,
 
        .get_module_info        = efx_ethtool_get_module_info,
        .get_module_eeprom      = efx_ethtool_get_module_eeprom,
index e9d9de8e648ac82f3bbe0b8fe22de047d61fab65..6f1a01ded7d4ce197705ed1bab81a26fc996d525 100644 (file)
@@ -299,7 +299,7 @@ static int efx_probe_nic(struct efx_nic *efx)
        if (efx->n_channels > 1)
                netdev_rss_key_fill(efx->rss_context.rx_hash_key,
                                    sizeof(efx->rss_context.rx_hash_key));
-       efx_set_default_rx_indir_table(efx, &efx->rss_context);
+       efx_set_default_rx_indir_table(efx, efx->rss_context.rx_indir_table);
 
        /* Initialise the interrupt moderation settings */
        efx->irq_mod_step_us = DIV_ROUND_UP(efx->timer_quantum_ns, 1000);
index 48d3623735ba6bdba2b9278d0c82ed6a595f9e6a..7a6cab883d66dc4c76bfa6cbc610b0899c62192d 100644 (file)
@@ -158,7 +158,7 @@ static inline s32 efx_filter_get_rx_ids(struct efx_nic *efx,
 }
 
 /* RSS contexts */
-static inline bool efx_rss_active(struct efx_rss_context *ctx)
+static inline bool efx_rss_active(struct efx_rss_context_priv *ctx)
 {
        return ctx->context_id != EFX_MCDI_RSS_CONTEXT_INVALID;
 }
index 4ebd5ae23ecaeca55a4d51de2896aac0e6f3d55e..13cf647051af0543289a98b03ab4af6cff6394b6 100644 (file)
@@ -714,7 +714,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method)
 
        mutex_lock(&efx->mac_lock);
        down_write(&efx->filter_sem);
-       mutex_lock(&efx->rss_lock);
+       mutex_lock(&efx->net_dev->ethtool->rss_lock);
        efx->type->fini(efx);
 }
 
@@ -777,7 +777,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
 
        if (efx->type->rx_restore_rss_contexts)
                efx->type->rx_restore_rss_contexts(efx);
-       mutex_unlock(&efx->rss_lock);
+       mutex_unlock(&efx->net_dev->ethtool->rss_lock);
        efx->type->filter_table_restore(efx);
        up_write(&efx->filter_sem);
 
@@ -793,7 +793,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
 fail:
        efx->port_initialized = false;
 
-       mutex_unlock(&efx->rss_lock);
+       mutex_unlock(&efx->net_dev->ethtool->rss_lock);
        up_write(&efx->filter_sem);
        mutex_unlock(&efx->mac_lock);
 
@@ -1000,9 +1000,7 @@ int efx_init_struct(struct efx_nic *efx, struct pci_dev *pci_dev)
                efx->type->rx_hash_offset - efx->type->rx_prefix_size;
        efx->rx_packet_ts_offset =
                efx->type->rx_ts_offset - efx->type->rx_prefix_size;
-       INIT_LIST_HEAD(&efx->rss_context.list);
-       efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
-       mutex_init(&efx->rss_lock);
+       efx->rss_context.priv.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
        efx->vport_id = EVB_PORT_ID_ASSIGNED;
        spin_lock_init(&efx->stats_lock);
        efx->vi_stride = EFX_DEFAULT_VI_STRIDE;
index 37c69c8d90b1166a44c006a4cd38b7a055873df5..0f5c68b8bab7411400bea05a73a53db85e142480 100644 (file)
@@ -268,8 +268,12 @@ const struct ethtool_ops efx_ethtool_ops = {
        .set_rxnfc              = efx_ethtool_set_rxnfc,
        .get_rxfh_indir_size    = efx_ethtool_get_rxfh_indir_size,
        .get_rxfh_key_size      = efx_ethtool_get_rxfh_key_size,
+       .rxfh_priv_size         = sizeof(struct efx_rss_context_priv),
        .get_rxfh               = efx_ethtool_get_rxfh,
        .set_rxfh               = efx_ethtool_set_rxfh,
+       .create_rxfh_context    = efx_ethtool_create_rxfh_context,
+       .modify_rxfh_context    = efx_ethtool_modify_rxfh_context,
+       .remove_rxfh_context    = efx_ethtool_remove_rxfh_context,
        .get_ts_info            = efx_ethtool_get_ts_info,
        .get_module_info        = efx_ethtool_get_module_info,
        .get_module_eeprom      = efx_ethtool_get_module_eeprom,
index 7d5e5db4eac5d5bc6e6f27a20b0df71bf9fc8760..0a8d2c9ffce6b11e8d5694fa2e85a0139959afc9 100644 (file)
@@ -820,10 +820,10 @@ int efx_ethtool_get_rxnfc(struct net_device *net_dev,
                return 0;
 
        case ETHTOOL_GRXFH: {
-               struct efx_rss_context *ctx = &efx->rss_context;
+               struct efx_rss_context_priv *ctx = &efx->rss_context.priv;
                __u64 data;
 
-               mutex_lock(&efx->rss_lock);
+               mutex_lock(&net_dev->ethtool->rss_lock);
                if (info->flow_type & FLOW_RSS && info->rss_context) {
                        ctx = efx_find_rss_context_entry(efx, info->rss_context);
                        if (!ctx) {
@@ -864,7 +864,7 @@ int efx_ethtool_get_rxnfc(struct net_device *net_dev,
 out_setdata_unlock:
                info->data = data;
 out_unlock:
-               mutex_unlock(&efx->rss_lock);
+               mutex_unlock(&net_dev->ethtool->rss_lock);
                return rc;
        }
 
@@ -1167,31 +1167,33 @@ static int efx_ethtool_get_rxfh_context(struct net_device *net_dev,
                                        struct ethtool_rxfh_param *rxfh)
 {
        struct efx_nic *efx = efx_netdev_priv(net_dev);
-       struct efx_rss_context *ctx;
+       struct efx_rss_context_priv *ctx_priv;
+       struct efx_rss_context ctx;
        int rc = 0;
 
        if (!efx->type->rx_pull_rss_context_config)
                return -EOPNOTSUPP;
 
-       mutex_lock(&efx->rss_lock);
-       ctx = efx_find_rss_context_entry(efx, rxfh->rss_context);
-       if (!ctx) {
+       mutex_lock(&net_dev->ethtool->rss_lock);
+       ctx_priv = efx_find_rss_context_entry(efx, rxfh->rss_context);
+       if (!ctx_priv) {
                rc = -ENOENT;
                goto out_unlock;
        }
-       rc = efx->type->rx_pull_rss_context_config(efx, ctx);
+       ctx.priv = *ctx_priv;
+       rc = efx->type->rx_pull_rss_context_config(efx, &ctx);
        if (rc)
                goto out_unlock;
 
        rxfh->hfunc = ETH_RSS_HASH_TOP;
        if (rxfh->indir)
-               memcpy(rxfh->indir, ctx->rx_indir_table,
-                      sizeof(ctx->rx_indir_table));
+               memcpy(rxfh->indir, ctx.rx_indir_table,
+                      sizeof(ctx.rx_indir_table));
        if (rxfh->key)
-               memcpy(rxfh->key, ctx->rx_hash_key,
+               memcpy(rxfh->key, ctx.rx_hash_key,
                       efx->type->rx_hash_key_size);
 out_unlock:
-       mutex_unlock(&efx->rss_lock);
+       mutex_unlock(&net_dev->ethtool->rss_lock);
        return rc;
 }
 
@@ -1218,68 +1220,85 @@ int efx_ethtool_get_rxfh(struct net_device *net_dev,
        return 0;
 }
 
-static int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
-                                       struct ethtool_rxfh_param *rxfh,
-                                       struct netlink_ext_ack *extack)
+int efx_ethtool_modify_rxfh_context(struct net_device *net_dev,
+                                   struct ethtool_rxfh_context *ctx,
+                                   const struct ethtool_rxfh_param *rxfh,
+                                   struct netlink_ext_ack *extack)
 {
        struct efx_nic *efx = efx_netdev_priv(net_dev);
-       u32 *rss_context = &rxfh->rss_context;
-       struct efx_rss_context *ctx;
-       u32 *indir = rxfh->indir;
-       bool allocated = false;
-       u8 *key = rxfh->key;
-       int rc;
+       struct efx_rss_context_priv *priv;
+       const u32 *indir = rxfh->indir;
+       const u8 *key = rxfh->key;
 
-       if (!efx->type->rx_push_rss_context_config)
+       if (!efx->type->rx_push_rss_context_config) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "NIC type does not support custom contexts");
                return -EOPNOTSUPP;
-
-       mutex_lock(&efx->rss_lock);
-
-       if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
-               if (rxfh->rss_delete) {
-                       /* alloc + delete == Nothing to do */
-                       rc = -EINVAL;
-                       goto out_unlock;
-               }
-               ctx = efx_alloc_rss_context_entry(efx);
-               if (!ctx) {
-                       rc = -ENOMEM;
-                       goto out_unlock;
-               }
-               ctx->context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
-               /* Initialise indir table and key to defaults */
-               efx_set_default_rx_indir_table(efx, ctx);
-               netdev_rss_key_fill(ctx->rx_hash_key, sizeof(ctx->rx_hash_key));
-               allocated = true;
-       } else {
-               ctx = efx_find_rss_context_entry(efx, *rss_context);
-               if (!ctx) {
-                       rc = -ENOENT;
-                       goto out_unlock;
-               }
        }
-
-       if (rxfh->rss_delete) {
-               /* delete this context */
-               rc = efx->type->rx_push_rss_context_config(efx, ctx, NULL, NULL);
-               if (!rc)
-                       efx_free_rss_context_entry(ctx);
-               goto out_unlock;
+       /* Hash function is Toeplitz, cannot be changed */
+       if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+           rxfh->hfunc != ETH_RSS_HASH_TOP) {
+               NL_SET_ERR_MSG_MOD(extack, "Only Toeplitz hash is supported");
+               return -EOPNOTSUPP;
        }
 
+       priv = ethtool_rxfh_context_priv(ctx);
+
        if (!key)
-               key = ctx->rx_hash_key;
+               key = ethtool_rxfh_context_key(ctx);
        if (!indir)
-               indir = ctx->rx_indir_table;
+               indir = ethtool_rxfh_context_indir(ctx);
 
-       rc = efx->type->rx_push_rss_context_config(efx, ctx, indir, key);
-       if (rc && allocated)
-               efx_free_rss_context_entry(ctx);
-       else
-               *rss_context = ctx->user_id;
-out_unlock:
-       mutex_unlock(&efx->rss_lock);
-       return rc;
+       return efx->type->rx_push_rss_context_config(efx, priv, indir, key,
+                                                    false);
+}
+
+int efx_ethtool_create_rxfh_context(struct net_device *net_dev,
+                                   struct ethtool_rxfh_context *ctx,
+                                   const struct ethtool_rxfh_param *rxfh,
+                                   struct netlink_ext_ack *extack)
+{
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
+       struct efx_rss_context_priv *priv;
+
+       priv = ethtool_rxfh_context_priv(ctx);
+
+       priv->context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
+       priv->rx_hash_udp_4tuple = false;
+       /* Generate default indir table and/or key if not specified.
+        * We use ctx as a place to store these; this is fine because
+        * we're doing a create, so if we fail then the ctx will just
+        * be deleted.
+        */
+       if (!rxfh->indir)
+               efx_set_default_rx_indir_table(efx, ethtool_rxfh_context_indir(ctx));
+       if (!rxfh->key)
+               netdev_rss_key_fill(ethtool_rxfh_context_key(ctx),
+                                   ctx->key_size);
+       if (rxfh->hfunc == ETH_RSS_HASH_NO_CHANGE)
+               ctx->hfunc = ETH_RSS_HASH_TOP;
+       if (rxfh->input_xfrm == RXH_XFRM_NO_CHANGE)
+               ctx->input_xfrm = 0;
+       return efx_ethtool_modify_rxfh_context(net_dev, ctx, rxfh, extack);
+}
+
+int efx_ethtool_remove_rxfh_context(struct net_device *net_dev,
+                                   struct ethtool_rxfh_context *ctx,
+                                   u32 rss_context,
+                                   struct netlink_ext_ack *extack)
+{
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
+       struct efx_rss_context_priv *priv;
+
+       if (!efx->type->rx_push_rss_context_config) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "NIC type does not support custom contexts");
+               return -EOPNOTSUPP;
+       }
+
+       priv = ethtool_rxfh_context_priv(ctx);
+       return efx->type->rx_push_rss_context_config(efx, priv, NULL, NULL,
+                                                    true);
 }
 
 int efx_ethtool_set_rxfh(struct net_device *net_dev,
@@ -1295,8 +1314,9 @@ int efx_ethtool_set_rxfh(struct net_device *net_dev,
            rxfh->hfunc != ETH_RSS_HASH_TOP)
                return -EOPNOTSUPP;
 
-       if (rxfh->rss_context)
-               return efx_ethtool_set_rxfh_context(net_dev, rxfh, extack);
+       /* Custom contexts should use new API */
+       if (WARN_ON_ONCE(rxfh->rss_context))
+               return -EIO;
 
        if (!indir && !key)
                return 0;
index a680e59802138c7f0c9ea87c89bc79500eb0af08..fc52e891637d30cd6a05f86ef5a08dd3b5341867 100644 (file)
@@ -49,6 +49,18 @@ int efx_ethtool_get_rxfh(struct net_device *net_dev,
 int efx_ethtool_set_rxfh(struct net_device *net_dev,
                         struct ethtool_rxfh_param *rxfh,
                         struct netlink_ext_ack *extack);
+int efx_ethtool_create_rxfh_context(struct net_device *net_dev,
+                                   struct ethtool_rxfh_context *ctx,
+                                   const struct ethtool_rxfh_param *rxfh,
+                                   struct netlink_ext_ack *extack);
+int efx_ethtool_modify_rxfh_context(struct net_device *net_dev,
+                                   struct ethtool_rxfh_context *ctx,
+                                   const struct ethtool_rxfh_param *rxfh,
+                                   struct netlink_ext_ack *extack);
+int efx_ethtool_remove_rxfh_context(struct net_device *net_dev,
+                                   struct ethtool_rxfh_context *ctx,
+                                   u32 rss_context,
+                                   struct netlink_ext_ack *extack);
 int efx_ethtool_reset(struct net_device *net_dev, u32 *flags);
 int efx_ethtool_get_module_eeprom(struct net_device *net_dev,
                                  struct ethtool_eeprom *ee,
index 4ff6586116ee134d423e98b25b22c78cd3ca234e..6ef96292909a2f08e454ff3f8492d042652eef74 100644 (file)
@@ -194,7 +194,7 @@ efx_mcdi_filter_push_prep_set_match_fields(struct efx_nic *efx,
 static void efx_mcdi_filter_push_prep(struct efx_nic *efx,
                                      const struct efx_filter_spec *spec,
                                      efx_dword_t *inbuf, u64 handle,
-                                     struct efx_rss_context *ctx,
+                                     struct efx_rss_context_priv *ctx,
                                      bool replacing)
 {
        u32 flags = spec->flags;
@@ -245,7 +245,7 @@ static void efx_mcdi_filter_push_prep(struct efx_nic *efx,
 
 static int efx_mcdi_filter_push(struct efx_nic *efx,
                                const struct efx_filter_spec *spec, u64 *handle,
-                               struct efx_rss_context *ctx, bool replacing)
+                               struct efx_rss_context_priv *ctx, bool replacing)
 {
        MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_EXT_IN_LEN);
        MCDI_DECLARE_BUF(outbuf, MC_CMD_FILTER_OP_EXT_OUT_LEN);
@@ -345,9 +345,9 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx,
                                         bool replace_equal)
 {
        DECLARE_BITMAP(mc_rem_map, EFX_EF10_FILTER_SEARCH_LIMIT);
+       struct efx_rss_context_priv *ctx = NULL;
        struct efx_mcdi_filter_table *table;
        struct efx_filter_spec *saved_spec;
-       struct efx_rss_context *ctx = NULL;
        unsigned int match_pri, hash;
        unsigned int priv_flags;
        bool rss_locked = false;
@@ -380,12 +380,12 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx,
                bitmap_zero(mc_rem_map, EFX_EF10_FILTER_SEARCH_LIMIT);
 
        if (spec->flags & EFX_FILTER_FLAG_RX_RSS) {
-               mutex_lock(&efx->rss_lock);
+               mutex_lock(&efx->net_dev->ethtool->rss_lock);
                rss_locked = true;
                if (spec->rss_context)
                        ctx = efx_find_rss_context_entry(efx, spec->rss_context);
                else
-                       ctx = &efx->rss_context;
+                       ctx = &efx->rss_context.priv;
                if (!ctx) {
                        rc = -ENOENT;
                        goto out_unlock;
@@ -548,7 +548,7 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx,
 
 out_unlock:
        if (rss_locked)
-               mutex_unlock(&efx->rss_lock);
+               mutex_unlock(&efx->net_dev->ethtool->rss_lock);
        up_write(&table->lock);
        return rc;
 }
@@ -611,13 +611,13 @@ static int efx_mcdi_filter_remove_internal(struct efx_nic *efx,
 
                new_spec.priority = EFX_FILTER_PRI_AUTO;
                new_spec.flags = (EFX_FILTER_FLAG_RX |
-                                 (efx_rss_active(&efx->rss_context) ?
+                                 (efx_rss_active(&efx->rss_context.priv) ?
                                   EFX_FILTER_FLAG_RX_RSS : 0));
                new_spec.dmaq_id = 0;
                new_spec.rss_context = 0;
                rc = efx_mcdi_filter_push(efx, &new_spec,
                                          &table->entry[filter_idx].handle,
-                                         &efx->rss_context,
+                                         &efx->rss_context.priv,
                                          true);
 
                if (rc == 0)
@@ -764,7 +764,7 @@ static int efx_mcdi_filter_insert_addr_list(struct efx_nic *efx,
                ids = vlan->uc;
        }
 
-       filter_flags = efx_rss_active(&efx->rss_context) ? EFX_FILTER_FLAG_RX_RSS : 0;
+       filter_flags = efx_rss_active(&efx->rss_context.priv) ? EFX_FILTER_FLAG_RX_RSS : 0;
 
        /* Insert/renew filters */
        for (i = 0; i < addr_count; i++) {
@@ -833,7 +833,7 @@ static int efx_mcdi_filter_insert_def(struct efx_nic *efx,
        int rc;
        u16 *id;
 
-       filter_flags = efx_rss_active(&efx->rss_context) ? EFX_FILTER_FLAG_RX_RSS : 0;
+       filter_flags = efx_rss_active(&efx->rss_context.priv) ? EFX_FILTER_FLAG_RX_RSS : 0;
 
        efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0);
 
@@ -1375,8 +1375,8 @@ void efx_mcdi_filter_table_restore(struct efx_nic *efx)
        struct efx_mcdi_filter_table *table = efx->filter_state;
        unsigned int invalid_filters = 0, failed = 0;
        struct efx_mcdi_filter_vlan *vlan;
+       struct efx_rss_context_priv *ctx;
        struct efx_filter_spec *spec;
-       struct efx_rss_context *ctx;
        unsigned int filter_idx;
        u32 mcdi_flags;
        int match_pri;
@@ -1388,7 +1388,7 @@ void efx_mcdi_filter_table_restore(struct efx_nic *efx)
                return;
 
        down_write(&table->lock);
-       mutex_lock(&efx->rss_lock);
+       mutex_lock(&efx->net_dev->ethtool->rss_lock);
 
        for (filter_idx = 0; filter_idx < EFX_MCDI_FILTER_TBL_ROWS; filter_idx++) {
                spec = efx_mcdi_filter_entry_spec(table, filter_idx);
@@ -1407,7 +1407,7 @@ void efx_mcdi_filter_table_restore(struct efx_nic *efx)
                if (spec->rss_context)
                        ctx = efx_find_rss_context_entry(efx, spec->rss_context);
                else
-                       ctx = &efx->rss_context;
+                       ctx = &efx->rss_context.priv;
                if (spec->flags & EFX_FILTER_FLAG_RX_RSS) {
                        if (!ctx) {
                                netif_warn(efx, drv, efx->net_dev,
@@ -1444,7 +1444,7 @@ not_restored:
                }
        }
 
-       mutex_unlock(&efx->rss_lock);
+       mutex_unlock(&efx->net_dev->ethtool->rss_lock);
        up_write(&table->lock);
 
        /*
@@ -1861,7 +1861,8 @@ out_unlock:
                                         RSS_MODE_HASH_ADDRS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV6_RSS_MODE_LBN |\
                                         RSS_MODE_HASH_ADDRS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV6_RSS_MODE_LBN)
 
-int efx_mcdi_get_rss_context_flags(struct efx_nic *efx, u32 context, u32 *flags)
+static int efx_mcdi_get_rss_context_flags(struct efx_nic *efx, u32 context,
+                                         u32 *flags)
 {
        /*
         * Firmware had a bug (sfc bug 61952) where it would not actually
@@ -1909,8 +1910,8 @@ int efx_mcdi_get_rss_context_flags(struct efx_nic *efx, u32 context, u32 *flags)
  * Defaults are 4-tuple for TCP and 2-tuple for UDP and other-IP, so we
  * just need to set the UDP ports flags (for both IP versions).
  */
-void efx_mcdi_set_rss_context_flags(struct efx_nic *efx,
-                                   struct efx_rss_context *ctx)
+static void efx_mcdi_set_rss_context_flags(struct efx_nic *efx,
+                                          struct efx_rss_context_priv *ctx)
 {
        MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN);
        u32 flags;
@@ -1931,7 +1932,7 @@ void efx_mcdi_set_rss_context_flags(struct efx_nic *efx,
 }
 
 static int efx_mcdi_filter_alloc_rss_context(struct efx_nic *efx, bool exclusive,
-                                            struct efx_rss_context *ctx,
+                                            struct efx_rss_context_priv *ctx,
                                             unsigned *context_size)
 {
        MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN);
@@ -2032,25 +2033,26 @@ void efx_mcdi_rx_free_indir_table(struct efx_nic *efx)
 {
        int rc;
 
-       if (efx->rss_context.context_id != EFX_MCDI_RSS_CONTEXT_INVALID) {
-               rc = efx_mcdi_filter_free_rss_context(efx, efx->rss_context.context_id);
+       if (efx->rss_context.priv.context_id != EFX_MCDI_RSS_CONTEXT_INVALID) {
+               rc = efx_mcdi_filter_free_rss_context(efx, efx->rss_context.priv.context_id);
                WARN_ON(rc != 0);
        }
-       efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
+       efx->rss_context.priv.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
 }
 
 static int efx_mcdi_filter_rx_push_shared_rss_config(struct efx_nic *efx,
                                              unsigned *context_size)
 {
        struct efx_mcdi_filter_table *table = efx->filter_state;
-       int rc = efx_mcdi_filter_alloc_rss_context(efx, false, &efx->rss_context,
-                                           context_size);
+       int rc = efx_mcdi_filter_alloc_rss_context(efx, false,
+                                                  &efx->rss_context.priv,
+                                                  context_size);
 
        if (rc != 0)
                return rc;
 
        table->rx_rss_context_exclusive = false;
-       efx_set_default_rx_indir_table(efx, &efx->rss_context);
+       efx_set_default_rx_indir_table(efx, efx->rss_context.rx_indir_table);
        return 0;
 }
 
@@ -2058,26 +2060,27 @@ static int efx_mcdi_filter_rx_push_exclusive_rss_config(struct efx_nic *efx,
                                                 const u32 *rx_indir_table,
                                                 const u8 *key)
 {
+       u32 old_rx_rss_context = efx->rss_context.priv.context_id;
        struct efx_mcdi_filter_table *table = efx->filter_state;
-       u32 old_rx_rss_context = efx->rss_context.context_id;
        int rc;
 
-       if (efx->rss_context.context_id == EFX_MCDI_RSS_CONTEXT_INVALID ||
+       if (efx->rss_context.priv.context_id == EFX_MCDI_RSS_CONTEXT_INVALID ||
            !table->rx_rss_context_exclusive) {
-               rc = efx_mcdi_filter_alloc_rss_context(efx, true, &efx->rss_context,
-                                               NULL);
+               rc = efx_mcdi_filter_alloc_rss_context(efx, true,
+                                                      &efx->rss_context.priv,
+                                                      NULL);
                if (rc == -EOPNOTSUPP)
                        return rc;
                else if (rc != 0)
                        goto fail1;
        }
 
-       rc = efx_mcdi_filter_populate_rss_table(efx, efx->rss_context.context_id,
-                                        rx_indir_table, key);
+       rc = efx_mcdi_filter_populate_rss_table(efx, efx->rss_context.priv.context_id,
+                                               rx_indir_table, key);
        if (rc != 0)
                goto fail2;
 
-       if (efx->rss_context.context_id != old_rx_rss_context &&
+       if (efx->rss_context.priv.context_id != old_rx_rss_context &&
            old_rx_rss_context != EFX_MCDI_RSS_CONTEXT_INVALID)
                WARN_ON(efx_mcdi_filter_free_rss_context(efx, old_rx_rss_context) != 0);
        table->rx_rss_context_exclusive = true;
@@ -2091,9 +2094,9 @@ static int efx_mcdi_filter_rx_push_exclusive_rss_config(struct efx_nic *efx,
        return 0;
 
 fail2:
-       if (old_rx_rss_context != efx->rss_context.context_id) {
-               WARN_ON(efx_mcdi_filter_free_rss_context(efx, efx->rss_context.context_id) != 0);
-               efx->rss_context.context_id = old_rx_rss_context;
+       if (old_rx_rss_context != efx->rss_context.priv.context_id) {
+               WARN_ON(efx_mcdi_filter_free_rss_context(efx, efx->rss_context.priv.context_id) != 0);
+               efx->rss_context.priv.context_id = old_rx_rss_context;
        }
 fail1:
        netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
@@ -2101,33 +2104,28 @@ fail1:
 }
 
 int efx_mcdi_rx_push_rss_context_config(struct efx_nic *efx,
-                                       struct efx_rss_context *ctx,
+                                       struct efx_rss_context_priv *ctx,
                                        const u32 *rx_indir_table,
-                                       const u8 *key)
+                                       const u8 *key, bool delete)
 {
        int rc;
 
-       WARN_ON(!mutex_is_locked(&efx->rss_lock));
+       WARN_ON(!mutex_is_locked(&efx->net_dev->ethtool->rss_lock));
 
        if (ctx->context_id == EFX_MCDI_RSS_CONTEXT_INVALID) {
+               if (delete)
+                       /* already wasn't in HW, nothing to do */
+                       return 0;
                rc = efx_mcdi_filter_alloc_rss_context(efx, true, ctx, NULL);
                if (rc)
                        return rc;
        }
 
-       if (!rx_indir_table) /* Delete this context */
+       if (delete) /* Delete this context */
                return efx_mcdi_filter_free_rss_context(efx, ctx->context_id);
 
-       rc = efx_mcdi_filter_populate_rss_table(efx, ctx->context_id,
-                                        rx_indir_table, key);
-       if (rc)
-               return rc;
-
-       memcpy(ctx->rx_indir_table, rx_indir_table,
-              sizeof(efx->rss_context.rx_indir_table));
-       memcpy(ctx->rx_hash_key, key, efx->type->rx_hash_key_size);
-
-       return 0;
+       return efx_mcdi_filter_populate_rss_table(efx, ctx->context_id,
+                                                 rx_indir_table, key);
 }
 
 int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx,
@@ -2139,16 +2137,16 @@ int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx,
        size_t outlen;
        int rc, i;
 
-       WARN_ON(!mutex_is_locked(&efx->rss_lock));
+       WARN_ON(!mutex_is_locked(&efx->net_dev->ethtool->rss_lock));
 
        BUILD_BUG_ON(MC_CMD_RSS_CONTEXT_GET_TABLE_IN_LEN !=
                     MC_CMD_RSS_CONTEXT_GET_KEY_IN_LEN);
 
-       if (ctx->context_id == EFX_MCDI_RSS_CONTEXT_INVALID)
+       if (ctx->priv.context_id == EFX_MCDI_RSS_CONTEXT_INVALID)
                return -ENOENT;
 
        MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_TABLE_IN_RSS_CONTEXT_ID,
-                      ctx->context_id);
+                      ctx->priv.context_id);
        BUILD_BUG_ON(ARRAY_SIZE(ctx->rx_indir_table) !=
                     MC_CMD_RSS_CONTEXT_GET_TABLE_OUT_INDIRECTION_TABLE_LEN);
        rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_TABLE, inbuf, sizeof(inbuf),
@@ -2164,7 +2162,7 @@ int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx,
                                RSS_CONTEXT_GET_TABLE_OUT_INDIRECTION_TABLE)[i];
 
        MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_KEY_IN_RSS_CONTEXT_ID,
-                      ctx->context_id);
+                      ctx->priv.context_id);
        BUILD_BUG_ON(ARRAY_SIZE(ctx->rx_hash_key) !=
                     MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
        rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_KEY, inbuf, sizeof(inbuf),
@@ -2186,35 +2184,42 @@ int efx_mcdi_rx_pull_rss_config(struct efx_nic *efx)
 {
        int rc;
 
-       mutex_lock(&efx->rss_lock);
+       mutex_lock(&efx->net_dev->ethtool->rss_lock);
        rc = efx_mcdi_rx_pull_rss_context_config(efx, &efx->rss_context);
-       mutex_unlock(&efx->rss_lock);
+       mutex_unlock(&efx->net_dev->ethtool->rss_lock);
        return rc;
 }
 
 void efx_mcdi_rx_restore_rss_contexts(struct efx_nic *efx)
 {
        struct efx_mcdi_filter_table *table = efx->filter_state;
-       struct efx_rss_context *ctx;
+       struct ethtool_rxfh_context *ctx;
+       unsigned long context;
        int rc;
 
-       WARN_ON(!mutex_is_locked(&efx->rss_lock));
+       WARN_ON(!mutex_is_locked(&efx->net_dev->ethtool->rss_lock));
 
        if (!table->must_restore_rss_contexts)
                return;
 
-       list_for_each_entry(ctx, &efx->rss_context.list, list) {
+       xa_for_each(&efx->net_dev->ethtool->rss_ctx, context, ctx) {
+               struct efx_rss_context_priv *priv;
+               u32 *indir;
+               u8 *key;
+
+               priv = ethtool_rxfh_context_priv(ctx);
                /* previous NIC RSS context is gone */
-               ctx->context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
+               priv->context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
                /* so try to allocate a new one */
-               rc = efx_mcdi_rx_push_rss_context_config(efx, ctx,
-                                                        ctx->rx_indir_table,
-                                                        ctx->rx_hash_key);
+               indir = ethtool_rxfh_context_indir(ctx);
+               key = ethtool_rxfh_context_key(ctx);
+               rc = efx_mcdi_rx_push_rss_context_config(efx, priv, indir, key,
+                                                        false);
                if (rc)
                        netif_warn(efx, probe, efx->net_dev,
-                                  "failed to restore RSS context %u, rc=%d"
+                                  "failed to restore RSS context %lu, rc=%d"
                                   "; RSS filters may fail to be applied\n",
-                                  ctx->user_id, rc);
+                                  context, rc);
        }
        table->must_restore_rss_contexts = false;
 }
@@ -2276,7 +2281,7 @@ int efx_mcdi_vf_rx_push_rss_config(struct efx_nic *efx, bool user,
 {
        if (user)
                return -EOPNOTSUPP;
-       if (efx->rss_context.context_id != EFX_MCDI_RSS_CONTEXT_INVALID)
+       if (efx->rss_context.priv.context_id != EFX_MCDI_RSS_CONTEXT_INVALID)
                return 0;
        return efx_mcdi_filter_rx_push_shared_rss_config(efx, NULL);
 }
@@ -2295,7 +2300,7 @@ int efx_mcdi_push_default_indir_table(struct efx_nic *efx,
 
        efx_mcdi_rx_free_indir_table(efx);
        if (rss_spread > 1) {
-               efx_set_default_rx_indir_table(efx, &efx->rss_context);
+               efx_set_default_rx_indir_table(efx, efx->rss_context.rx_indir_table);
                rc = efx->type->rx_push_rss_config(efx, false,
                                   efx->rss_context.rx_indir_table, NULL);
        }
index c0d6558b9fd2465209eab6c4af441c8671fad307..11b9f87ed9e1f184f041f8e94b3181887bb4e285 100644 (file)
@@ -145,9 +145,9 @@ void efx_mcdi_filter_del_vlan(struct efx_nic *efx, u16 vid);
 
 void efx_mcdi_rx_free_indir_table(struct efx_nic *efx);
 int efx_mcdi_rx_push_rss_context_config(struct efx_nic *efx,
-                                       struct efx_rss_context *ctx,
+                                       struct efx_rss_context_priv *ctx,
                                        const u32 *rx_indir_table,
-                                       const u8 *key);
+                                       const u8 *key, bool delete);
 int efx_mcdi_pf_rx_push_rss_config(struct efx_nic *efx, bool user,
                                   const u32 *rx_indir_table,
                                   const u8 *key);
@@ -161,10 +161,6 @@ int efx_mcdi_push_default_indir_table(struct efx_nic *efx,
 int efx_mcdi_rx_pull_rss_config(struct efx_nic *efx);
 int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx,
                                        struct efx_rss_context *ctx);
-int efx_mcdi_get_rss_context_flags(struct efx_nic *efx, u32 context,
-                                  u32 *flags);
-void efx_mcdi_set_rss_context_flags(struct efx_nic *efx,
-                                   struct efx_rss_context *ctx);
 void efx_mcdi_rx_restore_rss_contexts(struct efx_nic *efx);
 
 static inline void efx_mcdi_update_rx_scatter(struct efx_nic *efx)
index f2dd7feb0e0cd019414f35eebc462889f8a159f2..b85c51cbe7f977bae9ce6ad17312ede93e8c2272 100644 (file)
@@ -737,21 +737,24 @@ struct vfdi_status;
 /* The reserved RSS context value */
 #define EFX_MCDI_RSS_CONTEXT_INVALID   0xffffffff
 /**
- * struct efx_rss_context - A user-defined RSS context for filtering
- * @list: node of linked list on which this struct is stored
+ * struct efx_rss_context_priv - driver private data for an RSS context
  * @context_id: the RSS_CONTEXT_ID returned by MC firmware, or
  *     %EFX_MCDI_RSS_CONTEXT_INVALID if this context is not present on the NIC.
- *     For Siena, 0 if RSS is active, else %EFX_MCDI_RSS_CONTEXT_INVALID.
- * @user_id: the rss_context ID exposed to userspace over ethtool.
  * @rx_hash_udp_4tuple: UDP 4-tuple hashing enabled
+ */
+struct efx_rss_context_priv {
+       u32 context_id;
+       bool rx_hash_udp_4tuple;
+};
+
+/**
+ * struct efx_rss_context - an RSS context
+ * @priv: hardware-specific state
  * @rx_hash_key: Toeplitz hash key for this RSS context
  * @indir_table: Indirection table for this RSS context
  */
 struct efx_rss_context {
-       struct list_head list;
-       u32 context_id;
-       u32 user_id;
-       bool rx_hash_udp_4tuple;
+       struct efx_rss_context_priv priv;
        u8 rx_hash_key[40];
        u32 rx_indir_table[128];
 };
@@ -883,9 +886,7 @@ struct efx_mae;
  * @rx_packet_ts_offset: Offset of timestamp from start of packet data
  *     (valid only if channel->sync_timestamps_enabled; always negative)
  * @rx_scatter: Scatter mode enabled for receives
- * @rss_context: Main RSS context.  Its @list member is the head of the list of
- *     RSS contexts created by user requests
- * @rss_lock: Protects custom RSS context software state in @rss_context.list
+ * @rss_context: Main RSS context.
  * @vport_id: The function's vport ID, only relevant for PFs
  * @int_error_count: Number of internal errors seen recently
  * @int_error_expire: Time at which error count will be expired
@@ -1052,7 +1053,6 @@ struct efx_nic {
        int rx_packet_ts_offset;
        bool rx_scatter;
        struct efx_rss_context rss_context;
-       struct mutex rss_lock;
        u32 vport_id;
 
        unsigned int_error_count;
@@ -1416,9 +1416,9 @@ struct efx_nic_type {
                                  const u32 *rx_indir_table, const u8 *key);
        int (*rx_pull_rss_config)(struct efx_nic *efx);
        int (*rx_push_rss_context_config)(struct efx_nic *efx,
-                                         struct efx_rss_context *ctx,
+                                         struct efx_rss_context_priv *ctx,
                                          const u32 *rx_indir_table,
-                                         const u8 *key);
+                                         const u8 *key, bool delete);
        int (*rx_pull_rss_context_config)(struct efx_nic *efx,
                                          struct efx_rss_context *ctx);
        void (*rx_restore_rss_contexts)(struct efx_nic *efx);
index dcd901eccfc8f1f9c68ee391de548a2c1602ab94..0b7dc75c40f9275d6b9fc9e620c4c5ad31bf78a2 100644 (file)
@@ -557,69 +557,25 @@ efx_rx_packet_gro(struct efx_channel *channel, struct efx_rx_buffer *rx_buf,
        napi_gro_frags(napi);
 }
 
-/* RSS contexts.  We're using linked lists and crappy O(n) algorithms, because
- * (a) this is an infrequent control-plane operation and (b) n is small (max 64)
- */
-struct efx_rss_context *efx_alloc_rss_context_entry(struct efx_nic *efx)
+struct efx_rss_context_priv *efx_find_rss_context_entry(struct efx_nic *efx,
+                                                       u32 id)
 {
-       struct list_head *head = &efx->rss_context.list;
-       struct efx_rss_context *ctx, *new;
-       u32 id = 1; /* Don't use zero, that refers to the master RSS context */
-
-       WARN_ON(!mutex_is_locked(&efx->rss_lock));
+       struct ethtool_rxfh_context *ctx;
 
-       /* Search for first gap in the numbering */
-       list_for_each_entry(ctx, head, list) {
-               if (ctx->user_id != id)
-                       break;
-               id++;
-               /* Check for wrap.  If this happens, we have nearly 2^32
-                * allocated RSS contexts, which seems unlikely.
-                */
-               if (WARN_ON_ONCE(!id))
-                       return NULL;
-       }
+       WARN_ON(!mutex_is_locked(&efx->net_dev->ethtool->rss_lock));
 
-       /* Create the new entry */
-       new = kmalloc(sizeof(*new), GFP_KERNEL);
-       if (!new)
+       ctx = xa_load(&efx->net_dev->ethtool->rss_ctx, id);
+       if (!ctx)
                return NULL;
-       new->context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
-       new->rx_hash_udp_4tuple = false;
-
-       /* Insert the new entry into the gap */
-       new->user_id = id;
-       list_add_tail(&new->list, &ctx->list);
-       return new;
-}
-
-struct efx_rss_context *efx_find_rss_context_entry(struct efx_nic *efx, u32 id)
-{
-       struct list_head *head = &efx->rss_context.list;
-       struct efx_rss_context *ctx;
-
-       WARN_ON(!mutex_is_locked(&efx->rss_lock));
-
-       list_for_each_entry(ctx, head, list)
-               if (ctx->user_id == id)
-                       return ctx;
-       return NULL;
-}
-
-void efx_free_rss_context_entry(struct efx_rss_context *ctx)
-{
-       list_del(&ctx->list);
-       kfree(ctx);
+       return ethtool_rxfh_context_priv(ctx);
 }
 
-void efx_set_default_rx_indir_table(struct efx_nic *efx,
-                                   struct efx_rss_context *ctx)
+void efx_set_default_rx_indir_table(struct efx_nic *efx, u32 *indir)
 {
        size_t i;
 
-       for (i = 0; i < ARRAY_SIZE(ctx->rx_indir_table); i++)
-               ctx->rx_indir_table[i] =
-                       ethtool_rxfh_indir_default(i, efx->rss_spread);
+       for (i = 0; i < ARRAY_SIZE(efx->rss_context.rx_indir_table); i++)
+               indir[i] = ethtool_rxfh_indir_default(i, efx->rss_spread);
 }
 
 /**
index fbd2769307f915d08cf3c4a7fd53953f5dbffce3..75fa841923627bbfb744ac07c015c06ddcfbb2a6 100644 (file)
@@ -84,11 +84,9 @@ void
 efx_rx_packet_gro(struct efx_channel *channel, struct efx_rx_buffer *rx_buf,
                  unsigned int n_frags, u8 *eh, __wsum csum);
 
-struct efx_rss_context *efx_alloc_rss_context_entry(struct efx_nic *efx);
-struct efx_rss_context *efx_find_rss_context_entry(struct efx_nic *efx, u32 id);
-void efx_free_rss_context_entry(struct efx_rss_context *ctx);
-void efx_set_default_rx_indir_table(struct efx_nic *efx,
-                                   struct efx_rss_context *ctx);
+struct efx_rss_context_priv *efx_find_rss_context_entry(struct efx_nic *efx,
+                                                       u32 id);
+void efx_set_default_rx_indir_table(struct efx_nic *efx, u32 *indir);
 
 bool efx_filter_is_mc_recipient(const struct efx_filter_spec *spec);
 bool efx_filter_spec_equal(const struct efx_filter_spec *left,