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