summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/ethtool.h20
-rw-r--r--net/ethtool/ioctl.c46
2 files changed, 44 insertions, 22 deletions
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 89da0254ccd4..a1ee76936f53 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -181,6 +181,7 @@ struct ethtool_rxfh_context {
/* private: driver private data, indirection table, and hash key are
* stored sequentially in @data area. Use below helpers to access.
*/
+ u32 key_off;
u8 data[] __aligned(sizeof(void *));
};
@@ -196,18 +197,7 @@ static inline u32 *ethtool_rxfh_context_indir(struct ethtool_rxfh_context *ctx)
static inline u8 *ethtool_rxfh_context_key(struct ethtool_rxfh_context *ctx)
{
- return (u8 *)(ethtool_rxfh_context_indir(ctx) + ctx->indir_size);
-}
-
-static inline size_t ethtool_rxfh_context_size(u32 indir_size, u32 key_size,
- u16 priv_size)
-{
- size_t indir_bytes = array_size(indir_size, sizeof(u32));
- size_t flex_len;
-
- flex_len = size_add(size_add(indir_bytes, key_size),
- ALIGN(priv_size, sizeof(u32)));
- return struct_size_t(struct ethtool_rxfh_context, data, flex_len);
+ return &ctx->data[ctx->key_off];
}
void ethtool_rxfh_context_lost(struct net_device *dev, u32 context_id);
@@ -723,6 +713,10 @@ struct ethtool_rxfh_param {
* contexts.
* @cap_rss_sym_xor_supported: indicates if the driver supports symmetric-xor
* RSS.
+ * @rxfh_indir_space: max size of RSS indirection tables, if indirection table
+ * size as returned by @get_rxfh_indir_size may change during lifetime
+ * of the device. Leave as 0 if the table size is constant.
+ * @rxfh_key_space: same as @rxfh_indir_space, but for the key.
* @rxfh_priv_size: size of the driver private data area the core should
* allocate for an RSS context (in &struct ethtool_rxfh_context).
* @rxfh_max_context_id: maximum (exclusive) supported RSS context ID. If this
@@ -940,6 +934,8 @@ struct ethtool_ops {
u32 cap_link_lanes_supported:1;
u32 cap_rss_ctx_supported:1;
u32 cap_rss_sym_xor_supported:1;
+ u32 rxfh_indir_space;
+ u16 rxfh_key_space;
u16 rxfh_priv_size;
u32 rxfh_max_context_id;
u32 supported_coalesce_params;
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 615812ff8974..0732710a4836 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -1290,6 +1290,40 @@ out:
return ret;
}
+static struct ethtool_rxfh_context *
+ethtool_rxfh_ctx_alloc(const struct ethtool_ops *ops,
+ u32 indir_size, u32 key_size)
+{
+ size_t indir_bytes, flex_len, key_off, size;
+ struct ethtool_rxfh_context *ctx;
+ u32 priv_bytes, indir_max;
+ u16 key_max;
+
+ key_max = max(key_size, ops->rxfh_key_space);
+ indir_max = max(indir_size, ops->rxfh_indir_space);
+
+ priv_bytes = ALIGN(ops->rxfh_priv_size, sizeof(u32));
+ indir_bytes = array_size(indir_max, sizeof(u32));
+
+ key_off = size_add(priv_bytes, indir_bytes);
+ flex_len = size_add(key_off, key_max);
+ size = struct_size_t(struct ethtool_rxfh_context, data, flex_len);
+
+ ctx = kzalloc(size, GFP_KERNEL_ACCOUNT);
+ if (!ctx)
+ return NULL;
+
+ ctx->indir_size = indir_size;
+ ctx->key_size = key_size;
+ ctx->key_off = key_off;
+ ctx->priv_size = ops->rxfh_priv_size;
+
+ ctx->hfunc = ETH_RSS_HASH_NO_CHANGE;
+ ctx->input_xfrm = RXH_XFRM_NO_CHANGE;
+
+ return ctx;
+}
+
static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
void __user *useraddr)
{
@@ -1406,20 +1440,12 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
ret = -EINVAL;
goto out;
}
- ctx = kzalloc(ethtool_rxfh_context_size(dev_indir_size,
- dev_key_size,
- ops->rxfh_priv_size),
- GFP_KERNEL_ACCOUNT);
+ ctx = ethtool_rxfh_ctx_alloc(ops, dev_indir_size, dev_key_size);
if (!ctx) {
ret = -ENOMEM;
goto out;
}
- ctx->indir_size = dev_indir_size;
- ctx->key_size = dev_key_size;
- ctx->priv_size = ops->rxfh_priv_size;
- /* Initialise to an empty context */
- ctx->hfunc = ETH_RSS_HASH_NO_CHANGE;
- ctx->input_xfrm = RXH_XFRM_NO_CHANGE;
+
if (ops->create_rxfh_context) {
u32 limit = ops->rxfh_max_context_id ?: U32_MAX;
u32 ctx_id;