^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <net/xdp_sock_drv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include "netlink.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) struct channels_req_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) struct ethnl_req_info base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) struct channels_reply_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) struct ethnl_reply_data base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) struct ethtool_channels channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define CHANNELS_REPDATA(__reply_base) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) container_of(__reply_base, struct channels_reply_data, base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) const struct nla_policy ethnl_channels_get_policy[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) [ETHTOOL_A_CHANNELS_HEADER] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) NLA_POLICY_NESTED(ethnl_header_policy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static int channels_prepare_data(const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct ethnl_reply_data *reply_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct channels_reply_data *data = CHANNELS_REPDATA(reply_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct net_device *dev = reply_base->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) if (!dev->ethtool_ops->get_channels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) ret = ethnl_ops_begin(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) dev->ethtool_ops->get_channels(dev, &data->channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) ethnl_ops_complete(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static int channels_reply_size(const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) const struct ethnl_reply_data *reply_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return nla_total_size(sizeof(u32)) + /* _CHANNELS_RX_MAX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) nla_total_size(sizeof(u32)) + /* _CHANNELS_TX_MAX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) nla_total_size(sizeof(u32)) + /* _CHANNELS_OTHER_MAX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) nla_total_size(sizeof(u32)) + /* _CHANNELS_COMBINED_MAX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) nla_total_size(sizeof(u32)) + /* _CHANNELS_RX_COUNT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) nla_total_size(sizeof(u32)) + /* _CHANNELS_TX_COUNT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) nla_total_size(sizeof(u32)) + /* _CHANNELS_OTHER_COUNT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) nla_total_size(sizeof(u32)); /* _CHANNELS_COMBINED_COUNT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static int channels_fill_reply(struct sk_buff *skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) const struct ethnl_reply_data *reply_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) const struct channels_reply_data *data = CHANNELS_REPDATA(reply_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) const struct ethtool_channels *channels = &data->channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if ((channels->max_rx &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) (nla_put_u32(skb, ETHTOOL_A_CHANNELS_RX_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) channels->max_rx) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) nla_put_u32(skb, ETHTOOL_A_CHANNELS_RX_COUNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) channels->rx_count))) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) (channels->max_tx &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) (nla_put_u32(skb, ETHTOOL_A_CHANNELS_TX_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) channels->max_tx) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) nla_put_u32(skb, ETHTOOL_A_CHANNELS_TX_COUNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) channels->tx_count))) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) (channels->max_other &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) (nla_put_u32(skb, ETHTOOL_A_CHANNELS_OTHER_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) channels->max_other) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) nla_put_u32(skb, ETHTOOL_A_CHANNELS_OTHER_COUNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) channels->other_count))) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) (channels->max_combined &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) (nla_put_u32(skb, ETHTOOL_A_CHANNELS_COMBINED_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) channels->max_combined) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) nla_put_u32(skb, ETHTOOL_A_CHANNELS_COMBINED_COUNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) channels->combined_count))))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) const struct ethnl_request_ops ethnl_channels_request_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) .request_cmd = ETHTOOL_MSG_CHANNELS_GET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) .reply_cmd = ETHTOOL_MSG_CHANNELS_GET_REPLY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) .hdr_attr = ETHTOOL_A_CHANNELS_HEADER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) .req_info_size = sizeof(struct channels_req_info),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .reply_data_size = sizeof(struct channels_reply_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) .prepare_data = channels_prepare_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .reply_size = channels_reply_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .fill_reply = channels_fill_reply,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* CHANNELS_SET */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) const struct nla_policy ethnl_channels_set_policy[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) [ETHTOOL_A_CHANNELS_HEADER] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) NLA_POLICY_NESTED(ethnl_header_policy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) [ETHTOOL_A_CHANNELS_RX_COUNT] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) [ETHTOOL_A_CHANNELS_TX_COUNT] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) [ETHTOOL_A_CHANNELS_OTHER_COUNT] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) [ETHTOOL_A_CHANNELS_COMBINED_COUNT] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) unsigned int from_channel, old_total, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) bool mod = false, mod_combined = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) struct ethtool_channels channels = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct ethnl_req_info req_info = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct nlattr **tb = info->attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) u32 err_attr, max_rx_in_use = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) const struct ethtool_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) ret = ethnl_parse_header_dev_get(&req_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) tb[ETHTOOL_A_CHANNELS_HEADER],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) genl_info_net(info), info->extack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) dev = req_info.dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) ret = -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (!ops->get_channels || !ops->set_channels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) goto out_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) rtnl_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) ret = ethnl_ops_begin(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) goto out_rtnl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ops->get_channels(dev, &channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) old_total = channels.combined_count +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) max(channels.rx_count, channels.tx_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ethnl_update_u32(&channels.rx_count, tb[ETHTOOL_A_CHANNELS_RX_COUNT],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) &mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) ethnl_update_u32(&channels.tx_count, tb[ETHTOOL_A_CHANNELS_TX_COUNT],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) &mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) ethnl_update_u32(&channels.other_count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) tb[ETHTOOL_A_CHANNELS_OTHER_COUNT], &mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) ethnl_update_u32(&channels.combined_count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) tb[ETHTOOL_A_CHANNELS_COMBINED_COUNT], &mod_combined);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) mod |= mod_combined;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (!mod)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /* ensure new channel counts are within limits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (channels.rx_count > channels.max_rx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) err_attr = ETHTOOL_A_CHANNELS_RX_COUNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) else if (channels.tx_count > channels.max_tx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) err_attr = ETHTOOL_A_CHANNELS_TX_COUNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) else if (channels.other_count > channels.max_other)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) err_attr = ETHTOOL_A_CHANNELS_OTHER_COUNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) else if (channels.combined_count > channels.max_combined)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) err_attr = ETHTOOL_A_CHANNELS_COMBINED_COUNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) err_attr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (err_attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) NL_SET_ERR_MSG_ATTR(info->extack, tb[err_attr],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) "requested channel count exceeds maximum");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /* ensure there is at least one RX and one TX channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (!channels.combined_count && !channels.rx_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) err_attr = ETHTOOL_A_CHANNELS_RX_COUNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) else if (!channels.combined_count && !channels.tx_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) err_attr = ETHTOOL_A_CHANNELS_TX_COUNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) err_attr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (err_attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if (mod_combined)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) err_attr = ETHTOOL_A_CHANNELS_COMBINED_COUNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) NL_SET_ERR_MSG_ATTR(info->extack, tb[err_attr],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) "requested channel counts would result in no RX or TX channel being configured");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) /* ensure the new Rx count fits within the configured Rx flow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * indirection table settings
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (netif_is_rxfh_configured(dev) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) !ethtool_get_max_rxfh_channel(dev, &max_rx_in_use) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) (channels.combined_count + channels.rx_count) <= max_rx_in_use) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) GENL_SET_ERR_MSG(info, "requested channel counts are too low for existing indirection table settings");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) /* Disabling channels, query zero-copy AF_XDP sockets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) from_channel = channels.combined_count +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) min(channels.rx_count, channels.tx_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) for (i = from_channel; i < old_total; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (xsk_get_pool_from_qid(dev, i)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) GENL_SET_ERR_MSG(info, "requested channel counts are too low for existing zerocopy AF_XDP sockets");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) ret = dev->ethtool_ops->set_channels(dev, &channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) ethtool_notify(dev, ETHTOOL_MSG_CHANNELS_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) out_ops:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) ethnl_ops_complete(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) out_rtnl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) out_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) dev_put(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }