Loading...
1// SPDX-License-Identifier: GPL-2.0-only
2
3#include <linux/ethtool.h>
4#include <linux/firmware.h>
5#include <linux/sfp.h>
6#include <net/devlink.h>
7
8#include "netlink.h"
9#include "common.h"
10#include "bitset.h"
11#include "module_fw.h"
12
13struct module_req_info {
14 struct ethnl_req_info base;
15};
16
17struct module_reply_data {
18 struct ethnl_reply_data base;
19 struct ethtool_module_power_mode_params power;
20};
21
22#define MODULE_REPDATA(__reply_base) \
23 container_of(__reply_base, struct module_reply_data, base)
24
25/* MODULE_GET */
26
27const struct nla_policy ethnl_module_get_policy[ETHTOOL_A_MODULE_HEADER + 1] = {
28 [ETHTOOL_A_MODULE_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
29};
30
31static int module_get_power_mode(struct net_device *dev,
32 struct module_reply_data *data,
33 struct netlink_ext_ack *extack)
34{
35 const struct ethtool_ops *ops = dev->ethtool_ops;
36
37 if (!ops->get_module_power_mode)
38 return 0;
39
40 if (dev->ethtool->module_fw_flash_in_progress) {
41 NL_SET_ERR_MSG(extack,
42 "Module firmware flashing is in progress");
43 return -EBUSY;
44 }
45
46 return ops->get_module_power_mode(dev, &data->power, extack);
47}
48
49static int module_prepare_data(const struct ethnl_req_info *req_base,
50 struct ethnl_reply_data *reply_base,
51 const struct genl_info *info)
52{
53 struct module_reply_data *data = MODULE_REPDATA(reply_base);
54 struct net_device *dev = reply_base->dev;
55 int ret;
56
57 ret = ethnl_ops_begin(dev);
58 if (ret < 0)
59 return ret;
60
61 ret = module_get_power_mode(dev, data, info->extack);
62 if (ret < 0)
63 goto out_complete;
64
65out_complete:
66 ethnl_ops_complete(dev);
67 return ret;
68}
69
70static int module_reply_size(const struct ethnl_req_info *req_base,
71 const struct ethnl_reply_data *reply_base)
72{
73 struct module_reply_data *data = MODULE_REPDATA(reply_base);
74 int len = 0;
75
76 if (data->power.policy)
77 len += nla_total_size(sizeof(u8)); /* _MODULE_POWER_MODE_POLICY */
78
79 if (data->power.mode)
80 len += nla_total_size(sizeof(u8)); /* _MODULE_POWER_MODE */
81
82 return len;
83}
84
85static int module_fill_reply(struct sk_buff *skb,
86 const struct ethnl_req_info *req_base,
87 const struct ethnl_reply_data *reply_base)
88{
89 const struct module_reply_data *data = MODULE_REPDATA(reply_base);
90
91 if (data->power.policy &&
92 nla_put_u8(skb, ETHTOOL_A_MODULE_POWER_MODE_POLICY,
93 data->power.policy))
94 return -EMSGSIZE;
95
96 if (data->power.mode &&
97 nla_put_u8(skb, ETHTOOL_A_MODULE_POWER_MODE, data->power.mode))
98 return -EMSGSIZE;
99
100 return 0;
101}
102
103/* MODULE_SET */
104
105const struct nla_policy ethnl_module_set_policy[ETHTOOL_A_MODULE_POWER_MODE_POLICY + 1] = {
106 [ETHTOOL_A_MODULE_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
107 [ETHTOOL_A_MODULE_POWER_MODE_POLICY] =
108 NLA_POLICY_RANGE(NLA_U8, ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH,
109 ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO),
110};
111
112static int
113ethnl_set_module_validate(struct ethnl_req_info *req_info,
114 struct genl_info *info)
115{
116 const struct ethtool_ops *ops = req_info->dev->ethtool_ops;
117 struct nlattr **tb = info->attrs;
118
119 if (!tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY])
120 return 0;
121
122 if (req_info->dev->ethtool->module_fw_flash_in_progress) {
123 NL_SET_ERR_MSG(info->extack,
124 "Module firmware flashing is in progress");
125 return -EBUSY;
126 }
127
128 if (!ops->get_module_power_mode || !ops->set_module_power_mode) {
129 NL_SET_ERR_MSG_ATTR(info->extack,
130 tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY],
131 "Setting power mode policy is not supported by this device");
132 return -EOPNOTSUPP;
133 }
134
135 return 1;
136}
137
138static int
139ethnl_set_module(struct ethnl_req_info *req_info, struct genl_info *info)
140{
141 struct ethtool_module_power_mode_params power = {};
142 struct ethtool_module_power_mode_params power_new;
143 const struct ethtool_ops *ops;
144 struct net_device *dev = req_info->dev;
145 struct nlattr **tb = info->attrs;
146 int ret;
147
148 ops = dev->ethtool_ops;
149
150 power_new.policy = nla_get_u8(tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]);
151 ret = ops->get_module_power_mode(dev, &power, info->extack);
152 if (ret < 0)
153 return ret;
154
155 if (power_new.policy == power.policy)
156 return 0;
157
158 ret = ops->set_module_power_mode(dev, &power_new, info->extack);
159 return ret < 0 ? ret : 1;
160}
161
162const struct ethnl_request_ops ethnl_module_request_ops = {
163 .request_cmd = ETHTOOL_MSG_MODULE_GET,
164 .reply_cmd = ETHTOOL_MSG_MODULE_GET_REPLY,
165 .hdr_attr = ETHTOOL_A_MODULE_HEADER,
166 .req_info_size = sizeof(struct module_req_info),
167 .reply_data_size = sizeof(struct module_reply_data),
168
169 .prepare_data = module_prepare_data,
170 .reply_size = module_reply_size,
171 .fill_reply = module_fill_reply,
172
173 .set_validate = ethnl_set_module_validate,
174 .set = ethnl_set_module,
175 .set_ntf_cmd = ETHTOOL_MSG_MODULE_NTF,
176};
177
178/* MODULE_FW_FLASH_ACT */
179
180const struct nla_policy
181ethnl_module_fw_flash_act_policy[ETHTOOL_A_MODULE_FW_FLASH_PASSWORD + 1] = {
182 [ETHTOOL_A_MODULE_FW_FLASH_HEADER] =
183 NLA_POLICY_NESTED(ethnl_header_policy),
184 [ETHTOOL_A_MODULE_FW_FLASH_FILE_NAME] = { .type = NLA_NUL_STRING },
185 [ETHTOOL_A_MODULE_FW_FLASH_PASSWORD] = { .type = NLA_U32 },
186};
187
188static LIST_HEAD(module_fw_flash_work_list);
189static DEFINE_SPINLOCK(module_fw_flash_work_list_lock);
190
191static int
192module_flash_fw_work_list_add(struct ethtool_module_fw_flash *module_fw,
193 struct genl_info *info)
194{
195 struct ethtool_module_fw_flash *work;
196
197 /* First, check if already registered. */
198 spin_lock(&module_fw_flash_work_list_lock);
199 list_for_each_entry(work, &module_fw_flash_work_list, list) {
200 if (work->fw_update.ntf_params.portid == info->snd_portid &&
201 work->fw_update.dev == module_fw->fw_update.dev) {
202 spin_unlock(&module_fw_flash_work_list_lock);
203 return -EALREADY;
204 }
205 }
206
207 list_add_tail(&module_fw->list, &module_fw_flash_work_list);
208 spin_unlock(&module_fw_flash_work_list_lock);
209
210 return 0;
211}
212
213static void module_flash_fw_work_list_del(struct list_head *list)
214{
215 spin_lock(&module_fw_flash_work_list_lock);
216 list_del(list);
217 spin_unlock(&module_fw_flash_work_list_lock);
218}
219
220static void module_flash_fw_work(struct work_struct *work)
221{
222 struct ethtool_module_fw_flash *module_fw;
223
224 module_fw = container_of(work, struct ethtool_module_fw_flash, work);
225
226 ethtool_cmis_fw_update(&module_fw->fw_update);
227
228 module_flash_fw_work_list_del(&module_fw->list);
229 module_fw->fw_update.dev->ethtool->module_fw_flash_in_progress = false;
230 netdev_put(module_fw->fw_update.dev, &module_fw->dev_tracker);
231 release_firmware(module_fw->fw_update.fw);
232 kfree(module_fw);
233}
234
235#define MODULE_EEPROM_PHYS_ID_PAGE 0
236#define MODULE_EEPROM_PHYS_ID_I2C_ADDR 0x50
237
238static int module_flash_fw_work_init(struct ethtool_module_fw_flash *module_fw,
239 struct net_device *dev,
240 struct netlink_ext_ack *extack)
241{
242 const struct ethtool_ops *ops = dev->ethtool_ops;
243 struct ethtool_module_eeprom page_data = {};
244 u8 phys_id;
245 int err;
246
247 /* Fetch the SFF-8024 Identifier Value. For all supported standards, it
248 * is located at I2C address 0x50, byte 0. See section 4.1 in SFF-8024,
249 * revision 4.9.
250 */
251 page_data.page = MODULE_EEPROM_PHYS_ID_PAGE;
252 page_data.offset = SFP_PHYS_ID;
253 page_data.length = sizeof(phys_id);
254 page_data.i2c_address = MODULE_EEPROM_PHYS_ID_I2C_ADDR;
255 page_data.data = &phys_id;
256
257 err = ops->get_module_eeprom_by_page(dev, &page_data, extack);
258 if (err < 0)
259 return err;
260
261 switch (phys_id) {
262 case SFF8024_ID_QSFP_DD:
263 case SFF8024_ID_OSFP:
264 case SFF8024_ID_DSFP:
265 case SFF8024_ID_QSFP_PLUS_CMIS:
266 case SFF8024_ID_SFP_DD_CMIS:
267 case SFF8024_ID_SFP_PLUS_CMIS:
268 INIT_WORK(&module_fw->work, module_flash_fw_work);
269 break;
270 default:
271 NL_SET_ERR_MSG(extack,
272 "Module type does not support firmware flashing");
273 return -EOPNOTSUPP;
274 }
275
276 return 0;
277}
278
279void ethnl_module_fw_flash_sock_destroy(struct ethnl_sock_priv *sk_priv)
280{
281 struct ethtool_module_fw_flash *work;
282
283 spin_lock(&module_fw_flash_work_list_lock);
284 list_for_each_entry(work, &module_fw_flash_work_list, list) {
285 if (work->fw_update.dev == sk_priv->dev &&
286 work->fw_update.ntf_params.portid == sk_priv->portid) {
287 work->fw_update.ntf_params.closed_sock = true;
288 break;
289 }
290 }
291 spin_unlock(&module_fw_flash_work_list_lock);
292}
293
294static int
295module_flash_fw_schedule(struct net_device *dev, const char *file_name,
296 struct ethtool_module_fw_flash_params *params,
297 struct sk_buff *skb, struct genl_info *info)
298{
299 struct ethtool_cmis_fw_update_params *fw_update;
300 struct ethtool_module_fw_flash *module_fw;
301 int err;
302
303 module_fw = kzalloc(sizeof(*module_fw), GFP_KERNEL);
304 if (!module_fw)
305 return -ENOMEM;
306
307 fw_update = &module_fw->fw_update;
308 fw_update->params = *params;
309 err = request_firmware_direct(&fw_update->fw,
310 file_name, &dev->dev);
311 if (err) {
312 NL_SET_ERR_MSG(info->extack,
313 "Failed to request module firmware image");
314 goto err_free;
315 }
316
317 err = module_flash_fw_work_init(module_fw, dev, info->extack);
318 if (err < 0)
319 goto err_release_firmware;
320
321 dev->ethtool->module_fw_flash_in_progress = true;
322 netdev_hold(dev, &module_fw->dev_tracker, GFP_KERNEL);
323 fw_update->dev = dev;
324 fw_update->ntf_params.portid = info->snd_portid;
325 fw_update->ntf_params.seq = info->snd_seq;
326 fw_update->ntf_params.closed_sock = false;
327
328 err = ethnl_sock_priv_set(skb, dev, fw_update->ntf_params.portid,
329 ETHTOOL_SOCK_TYPE_MODULE_FW_FLASH);
330 if (err < 0)
331 goto err_release_firmware;
332
333 err = module_flash_fw_work_list_add(module_fw, info);
334 if (err < 0)
335 goto err_release_firmware;
336
337 schedule_work(&module_fw->work);
338
339 return 0;
340
341err_release_firmware:
342 release_firmware(fw_update->fw);
343err_free:
344 kfree(module_fw);
345 return err;
346}
347
348static int module_flash_fw(struct net_device *dev, struct nlattr **tb,
349 struct sk_buff *skb, struct genl_info *info)
350{
351 struct ethtool_module_fw_flash_params params = {};
352 const char *file_name;
353 struct nlattr *attr;
354
355 if (GENL_REQ_ATTR_CHECK(info, ETHTOOL_A_MODULE_FW_FLASH_FILE_NAME))
356 return -EINVAL;
357
358 file_name = nla_data(tb[ETHTOOL_A_MODULE_FW_FLASH_FILE_NAME]);
359
360 attr = tb[ETHTOOL_A_MODULE_FW_FLASH_PASSWORD];
361 if (attr) {
362 params.password = cpu_to_be32(nla_get_u32(attr));
363 params.password_valid = true;
364 }
365
366 return module_flash_fw_schedule(dev, file_name, ¶ms, skb, info);
367}
368
369static int ethnl_module_fw_flash_validate(struct net_device *dev,
370 struct netlink_ext_ack *extack)
371{
372 struct devlink_port *devlink_port = dev->devlink_port;
373 const struct ethtool_ops *ops = dev->ethtool_ops;
374
375 if (!ops->set_module_eeprom_by_page ||
376 !ops->get_module_eeprom_by_page) {
377 NL_SET_ERR_MSG(extack,
378 "Flashing module firmware is not supported by this device");
379 return -EOPNOTSUPP;
380 }
381
382 if (!ops->reset) {
383 NL_SET_ERR_MSG(extack,
384 "Reset module is not supported by this device, so flashing is not permitted");
385 return -EOPNOTSUPP;
386 }
387
388 if (dev->ethtool->module_fw_flash_in_progress) {
389 NL_SET_ERR_MSG(extack, "Module firmware flashing already in progress");
390 return -EBUSY;
391 }
392
393 if (dev->flags & IFF_UP) {
394 NL_SET_ERR_MSG(extack, "Netdevice is up, so flashing is not permitted");
395 return -EBUSY;
396 }
397
398 if (devlink_port && devlink_port->attrs.split) {
399 NL_SET_ERR_MSG(extack, "Can't perform firmware flashing on a split port");
400 return -EOPNOTSUPP;
401 }
402
403 return 0;
404}
405
406int ethnl_act_module_fw_flash(struct sk_buff *skb, struct genl_info *info)
407{
408 struct ethnl_req_info req_info = {};
409 struct nlattr **tb = info->attrs;
410 struct net_device *dev;
411 int ret;
412
413 ret = ethnl_parse_header_dev_get(&req_info,
414 tb[ETHTOOL_A_MODULE_FW_FLASH_HEADER],
415 genl_info_net(info), info->extack,
416 true);
417 if (ret < 0)
418 return ret;
419 dev = req_info.dev;
420
421 rtnl_lock();
422 ret = ethnl_ops_begin(dev);
423 if (ret < 0)
424 goto out_rtnl;
425
426 ret = ethnl_module_fw_flash_validate(dev, info->extack);
427 if (ret < 0)
428 goto out_rtnl;
429
430 ret = module_flash_fw(dev, tb, skb, info);
431
432 ethnl_ops_complete(dev);
433
434out_rtnl:
435 rtnl_unlock();
436 ethnl_parse_header_dev_put(&req_info);
437 return ret;
438}
439
440/* MODULE_FW_FLASH_NTF */
441
442static int
443ethnl_module_fw_flash_ntf_put_err(struct sk_buff *skb, char *err_msg,
444 char *sub_err_msg)
445{
446 int err_msg_len, sub_err_msg_len, total_len;
447 struct nlattr *attr;
448
449 if (!err_msg)
450 return 0;
451
452 err_msg_len = strlen(err_msg);
453 total_len = err_msg_len + 2; /* For period and NUL. */
454
455 if (sub_err_msg) {
456 sub_err_msg_len = strlen(sub_err_msg);
457 total_len += sub_err_msg_len + 2; /* For ", ". */
458 }
459
460 attr = nla_reserve(skb, ETHTOOL_A_MODULE_FW_FLASH_STATUS_MSG,
461 total_len);
462 if (!attr)
463 return -ENOMEM;
464
465 if (sub_err_msg)
466 sprintf(nla_data(attr), "%s, %s.", err_msg, sub_err_msg);
467 else
468 sprintf(nla_data(attr), "%s.", err_msg);
469
470 return 0;
471}
472
473static void
474ethnl_module_fw_flash_ntf(struct net_device *dev,
475 enum ethtool_module_fw_flash_status status,
476 struct ethnl_module_fw_flash_ntf_params *ntf_params,
477 char *err_msg, char *sub_err_msg,
478 u64 done, u64 total)
479{
480 struct sk_buff *skb;
481 void *hdr;
482 int ret;
483
484 if (ntf_params->closed_sock)
485 return;
486
487 skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
488 if (!skb)
489 return;
490
491 hdr = ethnl_unicast_put(skb, ntf_params->portid, ++ntf_params->seq,
492 ETHTOOL_MSG_MODULE_FW_FLASH_NTF);
493 if (!hdr)
494 goto err_skb;
495
496 ret = ethnl_fill_reply_header(skb, dev,
497 ETHTOOL_A_MODULE_FW_FLASH_HEADER);
498 if (ret < 0)
499 goto err_skb;
500
501 if (nla_put_u32(skb, ETHTOOL_A_MODULE_FW_FLASH_STATUS, status))
502 goto err_skb;
503
504 ret = ethnl_module_fw_flash_ntf_put_err(skb, err_msg, sub_err_msg);
505 if (ret < 0)
506 goto err_skb;
507
508 if (nla_put_uint(skb, ETHTOOL_A_MODULE_FW_FLASH_DONE, done))
509 goto err_skb;
510
511 if (nla_put_uint(skb, ETHTOOL_A_MODULE_FW_FLASH_TOTAL, total))
512 goto err_skb;
513
514 genlmsg_end(skb, hdr);
515 genlmsg_unicast(dev_net(dev), skb, ntf_params->portid);
516 return;
517
518err_skb:
519 nlmsg_free(skb);
520}
521
522void ethnl_module_fw_flash_ntf_err(struct net_device *dev,
523 struct ethnl_module_fw_flash_ntf_params *params,
524 char *err_msg, char *sub_err_msg)
525{
526 ethnl_module_fw_flash_ntf(dev, ETHTOOL_MODULE_FW_FLASH_STATUS_ERROR,
527 params, err_msg, sub_err_msg, 0, 0);
528}
529
530void
531ethnl_module_fw_flash_ntf_start(struct net_device *dev,
532 struct ethnl_module_fw_flash_ntf_params *params)
533{
534 ethnl_module_fw_flash_ntf(dev, ETHTOOL_MODULE_FW_FLASH_STATUS_STARTED,
535 params, NULL, NULL, 0, 0);
536}
537
538void
539ethnl_module_fw_flash_ntf_complete(struct net_device *dev,
540 struct ethnl_module_fw_flash_ntf_params *params)
541{
542 ethnl_module_fw_flash_ntf(dev, ETHTOOL_MODULE_FW_FLASH_STATUS_COMPLETED,
543 params, NULL, NULL, 0, 0);
544}
545
546void
547ethnl_module_fw_flash_ntf_in_progress(struct net_device *dev,
548 struct ethnl_module_fw_flash_ntf_params *params,
549 u64 done, u64 total)
550{
551 ethnl_module_fw_flash_ntf(dev,
552 ETHTOOL_MODULE_FW_FLASH_STATUS_IN_PROGRESS,
553 params, NULL, NULL, done, total);
554}
1// SPDX-License-Identifier: GPL-2.0-only
2
3#include <linux/ethtool.h>
4
5#include "netlink.h"
6#include "common.h"
7#include "bitset.h"
8
9struct module_req_info {
10 struct ethnl_req_info base;
11};
12
13struct module_reply_data {
14 struct ethnl_reply_data base;
15 struct ethtool_module_power_mode_params power;
16};
17
18#define MODULE_REPDATA(__reply_base) \
19 container_of(__reply_base, struct module_reply_data, base)
20
21/* MODULE_GET */
22
23const struct nla_policy ethnl_module_get_policy[ETHTOOL_A_MODULE_HEADER + 1] = {
24 [ETHTOOL_A_MODULE_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
25};
26
27static int module_get_power_mode(struct net_device *dev,
28 struct module_reply_data *data,
29 struct netlink_ext_ack *extack)
30{
31 const struct ethtool_ops *ops = dev->ethtool_ops;
32
33 if (!ops->get_module_power_mode)
34 return 0;
35
36 return ops->get_module_power_mode(dev, &data->power, extack);
37}
38
39static int module_prepare_data(const struct ethnl_req_info *req_base,
40 struct ethnl_reply_data *reply_base,
41 const struct genl_info *info)
42{
43 struct module_reply_data *data = MODULE_REPDATA(reply_base);
44 struct net_device *dev = reply_base->dev;
45 int ret;
46
47 ret = ethnl_ops_begin(dev);
48 if (ret < 0)
49 return ret;
50
51 ret = module_get_power_mode(dev, data, info->extack);
52 if (ret < 0)
53 goto out_complete;
54
55out_complete:
56 ethnl_ops_complete(dev);
57 return ret;
58}
59
60static int module_reply_size(const struct ethnl_req_info *req_base,
61 const struct ethnl_reply_data *reply_base)
62{
63 struct module_reply_data *data = MODULE_REPDATA(reply_base);
64 int len = 0;
65
66 if (data->power.policy)
67 len += nla_total_size(sizeof(u8)); /* _MODULE_POWER_MODE_POLICY */
68
69 if (data->power.mode)
70 len += nla_total_size(sizeof(u8)); /* _MODULE_POWER_MODE */
71
72 return len;
73}
74
75static int module_fill_reply(struct sk_buff *skb,
76 const struct ethnl_req_info *req_base,
77 const struct ethnl_reply_data *reply_base)
78{
79 const struct module_reply_data *data = MODULE_REPDATA(reply_base);
80
81 if (data->power.policy &&
82 nla_put_u8(skb, ETHTOOL_A_MODULE_POWER_MODE_POLICY,
83 data->power.policy))
84 return -EMSGSIZE;
85
86 if (data->power.mode &&
87 nla_put_u8(skb, ETHTOOL_A_MODULE_POWER_MODE, data->power.mode))
88 return -EMSGSIZE;
89
90 return 0;
91}
92
93/* MODULE_SET */
94
95const struct nla_policy ethnl_module_set_policy[ETHTOOL_A_MODULE_POWER_MODE_POLICY + 1] = {
96 [ETHTOOL_A_MODULE_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
97 [ETHTOOL_A_MODULE_POWER_MODE_POLICY] =
98 NLA_POLICY_RANGE(NLA_U8, ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH,
99 ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO),
100};
101
102static int
103ethnl_set_module_validate(struct ethnl_req_info *req_info,
104 struct genl_info *info)
105{
106 const struct ethtool_ops *ops = req_info->dev->ethtool_ops;
107 struct nlattr **tb = info->attrs;
108
109 if (!tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY])
110 return 0;
111
112 if (!ops->get_module_power_mode || !ops->set_module_power_mode) {
113 NL_SET_ERR_MSG_ATTR(info->extack,
114 tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY],
115 "Setting power mode policy is not supported by this device");
116 return -EOPNOTSUPP;
117 }
118
119 return 1;
120}
121
122static int
123ethnl_set_module(struct ethnl_req_info *req_info, struct genl_info *info)
124{
125 struct ethtool_module_power_mode_params power = {};
126 struct ethtool_module_power_mode_params power_new;
127 const struct ethtool_ops *ops;
128 struct net_device *dev = req_info->dev;
129 struct nlattr **tb = info->attrs;
130 int ret;
131
132 ops = dev->ethtool_ops;
133
134 power_new.policy = nla_get_u8(tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]);
135 ret = ops->get_module_power_mode(dev, &power, info->extack);
136 if (ret < 0)
137 return ret;
138
139 if (power_new.policy == power.policy)
140 return 0;
141
142 ret = ops->set_module_power_mode(dev, &power_new, info->extack);
143 return ret < 0 ? ret : 1;
144}
145
146const struct ethnl_request_ops ethnl_module_request_ops = {
147 .request_cmd = ETHTOOL_MSG_MODULE_GET,
148 .reply_cmd = ETHTOOL_MSG_MODULE_GET_REPLY,
149 .hdr_attr = ETHTOOL_A_MODULE_HEADER,
150 .req_info_size = sizeof(struct module_req_info),
151 .reply_data_size = sizeof(struct module_reply_data),
152
153 .prepare_data = module_prepare_data,
154 .reply_size = module_reply_size,
155 .fill_reply = module_fill_reply,
156
157 .set_validate = ethnl_set_module_validate,
158 .set = ethnl_set_module,
159 .set_ntf_cmd = ETHTOOL_MSG_MODULE_NTF,
160};