diff options
Diffstat (limited to 'net/ethtool')
-rw-r--r-- | net/ethtool/ioctl.c | 46 |
1 files changed, 34 insertions, 12 deletions
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index e901a20e97f5..46b50ddde013 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1395,9 +1395,24 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, } ctx->indir_size = dev_indir_size; ctx->key_size = dev_key_size; - ctx->hfunc = rxfh.hfunc; - ctx->input_xfrm = rxfh.input_xfrm; 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; + + /* driver uses new API, core allocates ID */ + ret = xa_alloc(&dev->ethtool->rss_ctx, &ctx_id, ctx, + XA_LIMIT(1, limit), GFP_KERNEL_ACCOUNT); + if (ret < 0) { + kfree(ctx); + goto out; + } + WARN_ON(!ctx_id); /* can't happen */ + rxfh.rss_context = ctx_id; + } } else if (rxfh.rss_context) { ctx = xa_load(&dev->ethtool->rss_ctx, rxfh.rss_context); if (!ctx) { @@ -1409,11 +1424,24 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, rxfh_dev.rss_context = rxfh.rss_context; rxfh_dev.input_xfrm = rxfh.input_xfrm; - ret = ops->set_rxfh(dev, &rxfh_dev, extack); - if (ret) { + if (rxfh.rss_context && ops->create_rxfh_context) { if (create) + ret = ops->create_rxfh_context(dev, ctx, &rxfh_dev); + else if (rxfh_dev.rss_delete) + ret = ops->remove_rxfh_context(dev, ctx, + rxfh.rss_context); + else + ret = ops->modify_rxfh_context(dev, ctx, &rxfh_dev); + } else { + ret = ops->set_rxfh(dev, &rxfh_dev, extack); + } + if (ret) { + if (create) { /* failed to create, free our new tracking entry */ + if (ops->create_rxfh_context) + xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context); kfree(ctx); + } goto out; } @@ -1429,12 +1457,8 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, dev->priv_flags |= IFF_RXFH_CONFIGURED; } /* Update rss_ctx tracking */ - if (create) { - /* Ideally this should happen before calling the driver, - * so that we can fail more cleanly; but we don't have the - * context ID until the driver picks it, so we have to - * wait until after. - */ + if (create && !ops->create_rxfh_context) { + /* driver uses old API, it chose context ID */ if (WARN_ON(xa_load(&dev->ethtool->rss_ctx, rxfh.rss_context))) { /* context ID reused, our tracking is screwed */ kfree(ctx); @@ -1446,8 +1470,6 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, kfree(ctx); goto out; } - ctx->indir_configured = rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE; - ctx->key_configured = !!rxfh.key_size; } if (rxfh_dev.rss_delete) { WARN_ON(xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context) != ctx); |