Linux Audio

Check our new training course

Loading...
v6.13.7
  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, &params, 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}
v6.8
  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};