Merge tag 'f2fs-for-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
[platform/kernel/linux-rpi.git] / net / ethtool / rings.c
1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #include "netlink.h"
4 #include "common.h"
5
6 struct rings_req_info {
7         struct ethnl_req_info           base;
8 };
9
10 struct rings_reply_data {
11         struct ethnl_reply_data         base;
12         struct ethtool_ringparam        ringparam;
13 };
14
15 #define RINGS_REPDATA(__reply_base) \
16         container_of(__reply_base, struct rings_reply_data, base)
17
18 static const struct nla_policy
19 rings_get_policy[ETHTOOL_A_RINGS_MAX + 1] = {
20         [ETHTOOL_A_RINGS_UNSPEC]                = { .type = NLA_REJECT },
21         [ETHTOOL_A_RINGS_HEADER]                = { .type = NLA_NESTED },
22         [ETHTOOL_A_RINGS_RX_MAX]                = { .type = NLA_REJECT },
23         [ETHTOOL_A_RINGS_RX_MINI_MAX]           = { .type = NLA_REJECT },
24         [ETHTOOL_A_RINGS_RX_JUMBO_MAX]          = { .type = NLA_REJECT },
25         [ETHTOOL_A_RINGS_TX_MAX]                = { .type = NLA_REJECT },
26         [ETHTOOL_A_RINGS_RX]                    = { .type = NLA_REJECT },
27         [ETHTOOL_A_RINGS_RX_MINI]               = { .type = NLA_REJECT },
28         [ETHTOOL_A_RINGS_RX_JUMBO]              = { .type = NLA_REJECT },
29         [ETHTOOL_A_RINGS_TX]                    = { .type = NLA_REJECT },
30 };
31
32 static int rings_prepare_data(const struct ethnl_req_info *req_base,
33                               struct ethnl_reply_data *reply_base,
34                               struct genl_info *info)
35 {
36         struct rings_reply_data *data = RINGS_REPDATA(reply_base);
37         struct net_device *dev = reply_base->dev;
38         int ret;
39
40         if (!dev->ethtool_ops->get_ringparam)
41                 return -EOPNOTSUPP;
42         ret = ethnl_ops_begin(dev);
43         if (ret < 0)
44                 return ret;
45         dev->ethtool_ops->get_ringparam(dev, &data->ringparam);
46         ethnl_ops_complete(dev);
47
48         return 0;
49 }
50
51 static int rings_reply_size(const struct ethnl_req_info *req_base,
52                             const struct ethnl_reply_data *reply_base)
53 {
54         return nla_total_size(sizeof(u32)) +    /* _RINGS_RX_MAX */
55                nla_total_size(sizeof(u32)) +    /* _RINGS_RX_MINI_MAX */
56                nla_total_size(sizeof(u32)) +    /* _RINGS_RX_JUMBO_MAX */
57                nla_total_size(sizeof(u32)) +    /* _RINGS_TX_MAX */
58                nla_total_size(sizeof(u32)) +    /* _RINGS_RX */
59                nla_total_size(sizeof(u32)) +    /* _RINGS_RX_MINI */
60                nla_total_size(sizeof(u32)) +    /* _RINGS_RX_JUMBO */
61                nla_total_size(sizeof(u32));     /* _RINGS_TX */
62 }
63
64 static int rings_fill_reply(struct sk_buff *skb,
65                             const struct ethnl_req_info *req_base,
66                             const struct ethnl_reply_data *reply_base)
67 {
68         const struct rings_reply_data *data = RINGS_REPDATA(reply_base);
69         const struct ethtool_ringparam *ringparam = &data->ringparam;
70
71         if ((ringparam->rx_max_pending &&
72              (nla_put_u32(skb, ETHTOOL_A_RINGS_RX_MAX,
73                           ringparam->rx_max_pending) ||
74               nla_put_u32(skb, ETHTOOL_A_RINGS_RX,
75                           ringparam->rx_pending))) ||
76             (ringparam->rx_mini_max_pending &&
77              (nla_put_u32(skb, ETHTOOL_A_RINGS_RX_MINI_MAX,
78                           ringparam->rx_mini_max_pending) ||
79               nla_put_u32(skb, ETHTOOL_A_RINGS_RX_MINI,
80                           ringparam->rx_mini_pending))) ||
81             (ringparam->rx_jumbo_max_pending &&
82              (nla_put_u32(skb, ETHTOOL_A_RINGS_RX_JUMBO_MAX,
83                           ringparam->rx_jumbo_max_pending) ||
84               nla_put_u32(skb, ETHTOOL_A_RINGS_RX_JUMBO,
85                           ringparam->rx_jumbo_pending))) ||
86             (ringparam->tx_max_pending &&
87              (nla_put_u32(skb, ETHTOOL_A_RINGS_TX_MAX,
88                           ringparam->tx_max_pending) ||
89               nla_put_u32(skb, ETHTOOL_A_RINGS_TX,
90                           ringparam->tx_pending))))
91                 return -EMSGSIZE;
92
93         return 0;
94 }
95
96 const struct ethnl_request_ops ethnl_rings_request_ops = {
97         .request_cmd            = ETHTOOL_MSG_RINGS_GET,
98         .reply_cmd              = ETHTOOL_MSG_RINGS_GET_REPLY,
99         .hdr_attr               = ETHTOOL_A_RINGS_HEADER,
100         .max_attr               = ETHTOOL_A_RINGS_MAX,
101         .req_info_size          = sizeof(struct rings_req_info),
102         .reply_data_size        = sizeof(struct rings_reply_data),
103         .request_policy         = rings_get_policy,
104
105         .prepare_data           = rings_prepare_data,
106         .reply_size             = rings_reply_size,
107         .fill_reply             = rings_fill_reply,
108 };
109
110 /* RINGS_SET */
111
112 static const struct nla_policy
113 rings_set_policy[ETHTOOL_A_RINGS_MAX + 1] = {
114         [ETHTOOL_A_RINGS_UNSPEC]                = { .type = NLA_REJECT },
115         [ETHTOOL_A_RINGS_HEADER]                = { .type = NLA_NESTED },
116         [ETHTOOL_A_RINGS_RX_MAX]                = { .type = NLA_REJECT },
117         [ETHTOOL_A_RINGS_RX_MINI_MAX]           = { .type = NLA_REJECT },
118         [ETHTOOL_A_RINGS_RX_JUMBO_MAX]          = { .type = NLA_REJECT },
119         [ETHTOOL_A_RINGS_TX_MAX]                = { .type = NLA_REJECT },
120         [ETHTOOL_A_RINGS_RX]                    = { .type = NLA_U32 },
121         [ETHTOOL_A_RINGS_RX_MINI]               = { .type = NLA_U32 },
122         [ETHTOOL_A_RINGS_RX_JUMBO]              = { .type = NLA_U32 },
123         [ETHTOOL_A_RINGS_TX]                    = { .type = NLA_U32 },
124 };
125
126 int ethnl_set_rings(struct sk_buff *skb, struct genl_info *info)
127 {
128         struct nlattr *tb[ETHTOOL_A_RINGS_MAX + 1];
129         struct ethtool_ringparam ringparam = {};
130         struct ethnl_req_info req_info = {};
131         const struct nlattr *err_attr;
132         const struct ethtool_ops *ops;
133         struct net_device *dev;
134         bool mod = false;
135         int ret;
136
137         ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
138                           ETHTOOL_A_RINGS_MAX, rings_set_policy,
139                           info->extack);
140         if (ret < 0)
141                 return ret;
142         ret = ethnl_parse_header_dev_get(&req_info,
143                                          tb[ETHTOOL_A_RINGS_HEADER],
144                                          genl_info_net(info), info->extack,
145                                          true);
146         if (ret < 0)
147                 return ret;
148         dev = req_info.dev;
149         ops = dev->ethtool_ops;
150         ret = -EOPNOTSUPP;
151         if (!ops->get_ringparam || !ops->set_ringparam)
152                 goto out_dev;
153
154         rtnl_lock();
155         ret = ethnl_ops_begin(dev);
156         if (ret < 0)
157                 goto out_rtnl;
158         ops->get_ringparam(dev, &ringparam);
159
160         ethnl_update_u32(&ringparam.rx_pending, tb[ETHTOOL_A_RINGS_RX], &mod);
161         ethnl_update_u32(&ringparam.rx_mini_pending,
162                          tb[ETHTOOL_A_RINGS_RX_MINI], &mod);
163         ethnl_update_u32(&ringparam.rx_jumbo_pending,
164                          tb[ETHTOOL_A_RINGS_RX_JUMBO], &mod);
165         ethnl_update_u32(&ringparam.tx_pending, tb[ETHTOOL_A_RINGS_TX], &mod);
166         ret = 0;
167         if (!mod)
168                 goto out_ops;
169
170         /* ensure new ring parameters are within limits */
171         if (ringparam.rx_pending > ringparam.rx_max_pending)
172                 err_attr = tb[ETHTOOL_A_RINGS_RX];
173         else if (ringparam.rx_mini_pending > ringparam.rx_mini_max_pending)
174                 err_attr = tb[ETHTOOL_A_RINGS_RX_MINI];
175         else if (ringparam.rx_jumbo_pending > ringparam.rx_jumbo_max_pending)
176                 err_attr = tb[ETHTOOL_A_RINGS_RX_JUMBO];
177         else if (ringparam.tx_pending > ringparam.tx_max_pending)
178                 err_attr = tb[ETHTOOL_A_RINGS_TX];
179         else
180                 err_attr = NULL;
181         if (err_attr) {
182                 ret = -EINVAL;
183                 NL_SET_ERR_MSG_ATTR(info->extack, err_attr,
184                                     "requested ring size exceeds maximum");
185                 goto out_ops;
186         }
187
188         ret = dev->ethtool_ops->set_ringparam(dev, &ringparam);
189         if (ret < 0)
190                 goto out_ops;
191         ethtool_notify(dev, ETHTOOL_MSG_RINGS_NTF, NULL);
192
193 out_ops:
194         ethnl_ops_complete(dev);
195 out_rtnl:
196         rtnl_unlock();
197 out_dev:
198         dev_put(dev);
199         return ret;
200 }