Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/devlink/param.c
48999 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4
* Copyright (c) 2016 Jiri Pirko <[email protected]>
5
*/
6
7
#include "devl_internal.h"
8
9
static const struct devlink_param devlink_param_generic[] = {
10
{
11
.id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
12
.name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
13
.type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
14
},
15
{
16
.id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
17
.name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
18
.type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
19
},
20
{
21
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
22
.name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
23
.type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
24
},
25
{
26
.id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
27
.name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
28
.type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
29
},
30
{
31
.id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
32
.name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
33
.type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
34
},
35
{
36
.id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
37
.name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
38
.type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
39
},
40
{
41
.id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
42
.name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
43
.type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
44
},
45
{
46
.id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
47
.name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
48
.type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
49
},
50
{
51
.id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE,
52
.name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME,
53
.type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE,
54
},
55
{
56
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
57
.name = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_NAME,
58
.type = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_TYPE,
59
},
60
{
61
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_REMOTE_DEV_RESET,
62
.name = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_NAME,
63
.type = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_TYPE,
64
},
65
{
66
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ETH,
67
.name = DEVLINK_PARAM_GENERIC_ENABLE_ETH_NAME,
68
.type = DEVLINK_PARAM_GENERIC_ENABLE_ETH_TYPE,
69
},
70
{
71
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA,
72
.name = DEVLINK_PARAM_GENERIC_ENABLE_RDMA_NAME,
73
.type = DEVLINK_PARAM_GENERIC_ENABLE_RDMA_TYPE,
74
},
75
{
76
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET,
77
.name = DEVLINK_PARAM_GENERIC_ENABLE_VNET_NAME,
78
.type = DEVLINK_PARAM_GENERIC_ENABLE_VNET_TYPE,
79
},
80
{
81
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_IWARP,
82
.name = DEVLINK_PARAM_GENERIC_ENABLE_IWARP_NAME,
83
.type = DEVLINK_PARAM_GENERIC_ENABLE_IWARP_TYPE,
84
},
85
{
86
.id = DEVLINK_PARAM_GENERIC_ID_IO_EQ_SIZE,
87
.name = DEVLINK_PARAM_GENERIC_IO_EQ_SIZE_NAME,
88
.type = DEVLINK_PARAM_GENERIC_IO_EQ_SIZE_TYPE,
89
},
90
{
91
.id = DEVLINK_PARAM_GENERIC_ID_EVENT_EQ_SIZE,
92
.name = DEVLINK_PARAM_GENERIC_EVENT_EQ_SIZE_NAME,
93
.type = DEVLINK_PARAM_GENERIC_EVENT_EQ_SIZE_TYPE,
94
},
95
{
96
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_PHC,
97
.name = DEVLINK_PARAM_GENERIC_ENABLE_PHC_NAME,
98
.type = DEVLINK_PARAM_GENERIC_ENABLE_PHC_TYPE,
99
},
100
{
101
.id = DEVLINK_PARAM_GENERIC_ID_CLOCK_ID,
102
.name = DEVLINK_PARAM_GENERIC_CLOCK_ID_NAME,
103
.type = DEVLINK_PARAM_GENERIC_CLOCK_ID_TYPE,
104
},
105
{
106
.id = DEVLINK_PARAM_GENERIC_ID_TOTAL_VFS,
107
.name = DEVLINK_PARAM_GENERIC_TOTAL_VFS_NAME,
108
.type = DEVLINK_PARAM_GENERIC_TOTAL_VFS_TYPE,
109
},
110
{
111
.id = DEVLINK_PARAM_GENERIC_ID_NUM_DOORBELLS,
112
.name = DEVLINK_PARAM_GENERIC_NUM_DOORBELLS_NAME,
113
.type = DEVLINK_PARAM_GENERIC_NUM_DOORBELLS_TYPE,
114
},
115
{
116
.id = DEVLINK_PARAM_GENERIC_ID_MAX_MAC_PER_VF,
117
.name = DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_NAME,
118
.type = DEVLINK_PARAM_GENERIC_MAX_MAC_PER_VF_TYPE,
119
},
120
};
121
122
static int devlink_param_generic_verify(const struct devlink_param *param)
123
{
124
/* verify it match generic parameter by id and name */
125
if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
126
return -EINVAL;
127
if (strcmp(param->name, devlink_param_generic[param->id].name))
128
return -ENOENT;
129
130
WARN_ON(param->type != devlink_param_generic[param->id].type);
131
132
return 0;
133
}
134
135
static int devlink_param_driver_verify(const struct devlink_param *param)
136
{
137
int i;
138
139
if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
140
return -EINVAL;
141
/* verify no such name in generic params */
142
for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
143
if (!strcmp(param->name, devlink_param_generic[i].name))
144
return -EEXIST;
145
146
return 0;
147
}
148
149
static struct devlink_param_item *
150
devlink_param_find_by_name(struct xarray *params, const char *param_name)
151
{
152
struct devlink_param_item *param_item;
153
unsigned long param_id;
154
155
xa_for_each(params, param_id, param_item) {
156
if (!strcmp(param_item->param->name, param_name))
157
return param_item;
158
}
159
return NULL;
160
}
161
162
static struct devlink_param_item *
163
devlink_param_find_by_id(struct xarray *params, u32 param_id)
164
{
165
return xa_load(params, param_id);
166
}
167
168
static bool
169
devlink_param_cmode_is_supported(const struct devlink_param *param,
170
enum devlink_param_cmode cmode)
171
{
172
return test_bit(cmode, &param->supported_cmodes);
173
}
174
175
static int devlink_param_get(struct devlink *devlink,
176
const struct devlink_param *param,
177
struct devlink_param_gset_ctx *ctx,
178
struct netlink_ext_ack *extack)
179
{
180
if (!param->get)
181
return -EOPNOTSUPP;
182
return param->get(devlink, param->id, ctx, extack);
183
}
184
185
static int devlink_param_set(struct devlink *devlink,
186
const struct devlink_param *param,
187
struct devlink_param_gset_ctx *ctx,
188
struct netlink_ext_ack *extack)
189
{
190
if (!param->set)
191
return -EOPNOTSUPP;
192
return param->set(devlink, param->id, ctx, extack);
193
}
194
195
static int devlink_param_get_default(struct devlink *devlink,
196
const struct devlink_param *param,
197
struct devlink_param_gset_ctx *ctx,
198
struct netlink_ext_ack *extack)
199
{
200
if (!param->get_default)
201
return -EOPNOTSUPP;
202
203
return param->get_default(devlink, param->id, ctx, extack);
204
}
205
206
static int devlink_param_reset_default(struct devlink *devlink,
207
const struct devlink_param *param,
208
enum devlink_param_cmode cmode,
209
struct netlink_ext_ack *extack)
210
{
211
if (!param->reset_default)
212
return -EOPNOTSUPP;
213
214
return param->reset_default(devlink, param->id, cmode, extack);
215
}
216
217
static int
218
devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type,
219
int nla_type, union devlink_param_value val,
220
bool flag_as_u8)
221
{
222
switch (type) {
223
case DEVLINK_PARAM_TYPE_U8:
224
if (nla_put_u8(msg, nla_type, val.vu8))
225
return -EMSGSIZE;
226
break;
227
case DEVLINK_PARAM_TYPE_U16:
228
if (nla_put_u16(msg, nla_type, val.vu16))
229
return -EMSGSIZE;
230
break;
231
case DEVLINK_PARAM_TYPE_U32:
232
if (nla_put_u32(msg, nla_type, val.vu32))
233
return -EMSGSIZE;
234
break;
235
case DEVLINK_PARAM_TYPE_U64:
236
if (devlink_nl_put_u64(msg, nla_type, val.vu64))
237
return -EMSGSIZE;
238
break;
239
case DEVLINK_PARAM_TYPE_STRING:
240
if (nla_put_string(msg, nla_type, val.vstr))
241
return -EMSGSIZE;
242
break;
243
case DEVLINK_PARAM_TYPE_BOOL:
244
/* default values of type bool are encoded with u8, so that
245
* false can be distinguished from not present
246
*/
247
if (flag_as_u8) {
248
if (nla_put_u8(msg, nla_type, val.vbool))
249
return -EMSGSIZE;
250
} else {
251
if (val.vbool && nla_put_flag(msg, nla_type))
252
return -EMSGSIZE;
253
}
254
break;
255
}
256
return 0;
257
}
258
259
static int
260
devlink_nl_param_value_fill_one(struct sk_buff *msg,
261
enum devlink_param_type type,
262
enum devlink_param_cmode cmode,
263
union devlink_param_value val,
264
union devlink_param_value default_val,
265
bool has_default)
266
{
267
struct nlattr *param_value_attr;
268
int err = -EMSGSIZE;
269
270
param_value_attr = nla_nest_start_noflag(msg,
271
DEVLINK_ATTR_PARAM_VALUE);
272
if (!param_value_attr)
273
return -EMSGSIZE;
274
275
if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
276
goto value_nest_cancel;
277
278
err = devlink_nl_param_value_put(msg, type,
279
DEVLINK_ATTR_PARAM_VALUE_DATA,
280
val, false);
281
if (err)
282
goto value_nest_cancel;
283
284
if (has_default) {
285
err = devlink_nl_param_value_put(msg, type,
286
DEVLINK_ATTR_PARAM_VALUE_DEFAULT,
287
default_val, true);
288
if (err)
289
goto value_nest_cancel;
290
}
291
292
nla_nest_end(msg, param_value_attr);
293
return 0;
294
295
value_nest_cancel:
296
nla_nest_cancel(msg, param_value_attr);
297
return err;
298
}
299
300
static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
301
unsigned int port_index,
302
struct devlink_param_item *param_item,
303
enum devlink_command cmd,
304
u32 portid, u32 seq, int flags,
305
struct netlink_ext_ack *extack)
306
{
307
union devlink_param_value default_value[DEVLINK_PARAM_CMODE_MAX + 1];
308
union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
309
bool default_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
310
bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
311
const struct devlink_param *param = param_item->param;
312
struct devlink_param_gset_ctx ctx;
313
struct nlattr *param_values_list;
314
struct nlattr *param_attr;
315
void *hdr;
316
int err;
317
int i;
318
319
/* Get value from driver part to driverinit configuration mode */
320
for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
321
if (!devlink_param_cmode_is_supported(param, i))
322
continue;
323
if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
324
if (param_item->driverinit_value_new_valid)
325
param_value[i] = param_item->driverinit_value_new;
326
else if (param_item->driverinit_value_valid)
327
param_value[i] = param_item->driverinit_value;
328
else
329
return -EOPNOTSUPP;
330
331
if (param_item->driverinit_value_valid) {
332
default_value[i] = param_item->driverinit_default;
333
default_value_set[i] = true;
334
}
335
} else {
336
ctx.cmode = i;
337
err = devlink_param_get(devlink, param, &ctx, extack);
338
if (err)
339
return err;
340
param_value[i] = ctx.val;
341
342
err = devlink_param_get_default(devlink, param, &ctx,
343
extack);
344
if (!err) {
345
default_value[i] = ctx.val;
346
default_value_set[i] = true;
347
} else if (err != -EOPNOTSUPP) {
348
return err;
349
}
350
}
351
param_value_set[i] = true;
352
}
353
354
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
355
if (!hdr)
356
return -EMSGSIZE;
357
358
if (devlink_nl_put_handle(msg, devlink))
359
goto genlmsg_cancel;
360
361
if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
362
cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
363
cmd == DEVLINK_CMD_PORT_PARAM_DEL)
364
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
365
goto genlmsg_cancel;
366
367
param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
368
if (!param_attr)
369
goto genlmsg_cancel;
370
if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
371
goto param_nest_cancel;
372
if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
373
goto param_nest_cancel;
374
if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, param->type))
375
goto param_nest_cancel;
376
377
param_values_list = nla_nest_start_noflag(msg,
378
DEVLINK_ATTR_PARAM_VALUES_LIST);
379
if (!param_values_list)
380
goto param_nest_cancel;
381
382
for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
383
if (!param_value_set[i])
384
continue;
385
err = devlink_nl_param_value_fill_one(msg, param->type,
386
i, param_value[i],
387
default_value[i],
388
default_value_set[i]);
389
if (err)
390
goto values_list_nest_cancel;
391
}
392
393
nla_nest_end(msg, param_values_list);
394
nla_nest_end(msg, param_attr);
395
genlmsg_end(msg, hdr);
396
return 0;
397
398
values_list_nest_cancel:
399
nla_nest_end(msg, param_values_list);
400
param_nest_cancel:
401
nla_nest_cancel(msg, param_attr);
402
genlmsg_cancel:
403
genlmsg_cancel(msg, hdr);
404
return -EMSGSIZE;
405
}
406
407
static void devlink_param_notify(struct devlink *devlink,
408
unsigned int port_index,
409
struct devlink_param_item *param_item,
410
enum devlink_command cmd)
411
{
412
struct sk_buff *msg;
413
int err;
414
415
WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
416
cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
417
cmd != DEVLINK_CMD_PORT_PARAM_DEL);
418
419
/* devlink_notify_register() / devlink_notify_unregister()
420
* will replay the notifications if the params are added/removed
421
* outside of the lifetime of the instance.
422
*/
423
if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
424
return;
425
426
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
427
if (!msg)
428
return;
429
err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
430
0, 0, 0, NULL);
431
if (err) {
432
nlmsg_free(msg);
433
return;
434
}
435
436
devlink_nl_notify_send(devlink, msg);
437
}
438
439
static void devlink_params_notify(struct devlink *devlink,
440
enum devlink_command cmd)
441
{
442
struct devlink_param_item *param_item;
443
unsigned long param_id;
444
445
xa_for_each(&devlink->params, param_id, param_item)
446
devlink_param_notify(devlink, 0, param_item, cmd);
447
}
448
449
void devlink_params_notify_register(struct devlink *devlink)
450
{
451
devlink_params_notify(devlink, DEVLINK_CMD_PARAM_NEW);
452
}
453
454
void devlink_params_notify_unregister(struct devlink *devlink)
455
{
456
devlink_params_notify(devlink, DEVLINK_CMD_PARAM_DEL);
457
}
458
459
static int devlink_nl_param_get_dump_one(struct sk_buff *msg,
460
struct devlink *devlink,
461
struct netlink_callback *cb,
462
int flags)
463
{
464
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
465
struct devlink_param_item *param_item;
466
unsigned long param_id;
467
int err = 0;
468
469
xa_for_each_start(&devlink->params, param_id, param_item, state->idx) {
470
err = devlink_nl_param_fill(msg, devlink, 0, param_item,
471
DEVLINK_CMD_PARAM_GET,
472
NETLINK_CB(cb->skb).portid,
473
cb->nlh->nlmsg_seq, flags,
474
cb->extack);
475
if (err == -EOPNOTSUPP) {
476
err = 0;
477
} else if (err) {
478
state->idx = param_id;
479
break;
480
}
481
}
482
483
return err;
484
}
485
486
int devlink_nl_param_get_dumpit(struct sk_buff *skb,
487
struct netlink_callback *cb)
488
{
489
return devlink_nl_dumpit(skb, cb, devlink_nl_param_get_dump_one);
490
}
491
492
static int
493
devlink_param_type_get_from_info(struct genl_info *info,
494
enum devlink_param_type *param_type)
495
{
496
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_TYPE))
497
return -EINVAL;
498
499
*param_type = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE]);
500
501
return 0;
502
}
503
504
static int
505
devlink_param_value_get_from_info(const struct devlink_param *param,
506
struct genl_info *info,
507
union devlink_param_value *value)
508
{
509
struct nlattr *param_data;
510
int len;
511
512
param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
513
514
if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
515
return -EINVAL;
516
517
switch (param->type) {
518
case DEVLINK_PARAM_TYPE_U8:
519
if (nla_len(param_data) != sizeof(u8))
520
return -EINVAL;
521
value->vu8 = nla_get_u8(param_data);
522
break;
523
case DEVLINK_PARAM_TYPE_U16:
524
if (nla_len(param_data) != sizeof(u16))
525
return -EINVAL;
526
value->vu16 = nla_get_u16(param_data);
527
break;
528
case DEVLINK_PARAM_TYPE_U32:
529
if (nla_len(param_data) != sizeof(u32))
530
return -EINVAL;
531
value->vu32 = nla_get_u32(param_data);
532
break;
533
case DEVLINK_PARAM_TYPE_U64:
534
if (nla_len(param_data) != sizeof(u64))
535
return -EINVAL;
536
value->vu64 = nla_get_u64(param_data);
537
break;
538
case DEVLINK_PARAM_TYPE_STRING:
539
len = strnlen(nla_data(param_data), nla_len(param_data));
540
if (len == nla_len(param_data) ||
541
len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
542
return -EINVAL;
543
strcpy(value->vstr, nla_data(param_data));
544
break;
545
case DEVLINK_PARAM_TYPE_BOOL:
546
if (param_data && nla_len(param_data))
547
return -EINVAL;
548
value->vbool = nla_get_flag(param_data);
549
break;
550
}
551
return 0;
552
}
553
554
static struct devlink_param_item *
555
devlink_param_get_from_info(struct xarray *params, struct genl_info *info)
556
{
557
char *param_name;
558
559
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_NAME))
560
return NULL;
561
562
param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
563
return devlink_param_find_by_name(params, param_name);
564
}
565
566
int devlink_nl_param_get_doit(struct sk_buff *skb,
567
struct genl_info *info)
568
{
569
struct devlink *devlink = info->user_ptr[0];
570
struct devlink_param_item *param_item;
571
struct sk_buff *msg;
572
int err;
573
574
param_item = devlink_param_get_from_info(&devlink->params, info);
575
if (!param_item)
576
return -EINVAL;
577
578
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
579
if (!msg)
580
return -ENOMEM;
581
582
err = devlink_nl_param_fill(msg, devlink, 0, param_item,
583
DEVLINK_CMD_PARAM_GET, info->snd_portid,
584
info->snd_seq, 0, info->extack);
585
if (err) {
586
nlmsg_free(msg);
587
return err;
588
}
589
590
return genlmsg_reply(msg, info);
591
}
592
593
static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
594
unsigned int port_index,
595
struct xarray *params,
596
struct genl_info *info,
597
enum devlink_command cmd)
598
{
599
enum devlink_param_type param_type;
600
struct devlink_param_gset_ctx ctx;
601
enum devlink_param_cmode cmode;
602
struct devlink_param_item *param_item;
603
const struct devlink_param *param;
604
union devlink_param_value value;
605
bool reset_default;
606
int err = 0;
607
608
param_item = devlink_param_get_from_info(params, info);
609
if (!param_item)
610
return -EINVAL;
611
param = param_item->param;
612
err = devlink_param_type_get_from_info(info, &param_type);
613
if (err)
614
return err;
615
if (param_type != param->type)
616
return -EINVAL;
617
618
reset_default = info->attrs[DEVLINK_ATTR_PARAM_RESET_DEFAULT];
619
if (!reset_default) {
620
err = devlink_param_value_get_from_info(param, info, &value);
621
if (err)
622
return err;
623
if (param->validate) {
624
err = param->validate(devlink, param->id, value,
625
info->extack);
626
if (err)
627
return err;
628
}
629
}
630
631
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_VALUE_CMODE))
632
return -EINVAL;
633
cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
634
if (!devlink_param_cmode_is_supported(param, cmode))
635
return -EOPNOTSUPP;
636
637
if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
638
if (reset_default) {
639
if (!param_item->driverinit_value_valid) {
640
NL_SET_ERR_MSG(info->extack,
641
"Default value not available");
642
return -EOPNOTSUPP;
643
}
644
value = param_item->driverinit_default;
645
}
646
647
param_item->driverinit_value_new = value;
648
param_item->driverinit_value_new_valid = true;
649
} else {
650
if (!param->set)
651
return -EOPNOTSUPP;
652
ctx.val = value;
653
ctx.cmode = cmode;
654
if (reset_default)
655
err = devlink_param_reset_default(devlink, param, cmode,
656
info->extack);
657
else
658
err = devlink_param_set(devlink, param, &ctx,
659
info->extack);
660
if (err)
661
return err;
662
}
663
664
devlink_param_notify(devlink, port_index, param_item, cmd);
665
return 0;
666
}
667
668
int devlink_nl_param_set_doit(struct sk_buff *skb, struct genl_info *info)
669
{
670
struct devlink *devlink = info->user_ptr[0];
671
672
return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->params,
673
info, DEVLINK_CMD_PARAM_NEW);
674
}
675
676
int devlink_nl_port_param_get_dumpit(struct sk_buff *msg,
677
struct netlink_callback *cb)
678
{
679
NL_SET_ERR_MSG(cb->extack, "Port params are not supported");
680
return msg->len;
681
}
682
683
int devlink_nl_port_param_get_doit(struct sk_buff *skb,
684
struct genl_info *info)
685
{
686
NL_SET_ERR_MSG(info->extack, "Port params are not supported");
687
return -EINVAL;
688
}
689
690
int devlink_nl_port_param_set_doit(struct sk_buff *skb,
691
struct genl_info *info)
692
{
693
NL_SET_ERR_MSG(info->extack, "Port params are not supported");
694
return -EINVAL;
695
}
696
697
static int devlink_param_verify(const struct devlink_param *param)
698
{
699
if (!param || !param->name || !param->supported_cmodes)
700
return -EINVAL;
701
if (param->generic)
702
return devlink_param_generic_verify(param);
703
else
704
return devlink_param_driver_verify(param);
705
}
706
707
static int devlink_param_register(struct devlink *devlink,
708
const struct devlink_param *param)
709
{
710
struct devlink_param_item *param_item;
711
int err;
712
713
WARN_ON(devlink_param_verify(param));
714
WARN_ON(devlink_param_find_by_name(&devlink->params, param->name));
715
716
if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
717
WARN_ON(param->get || param->set);
718
else
719
WARN_ON(!param->get || !param->set);
720
721
param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
722
if (!param_item)
723
return -ENOMEM;
724
725
param_item->param = param;
726
727
err = xa_insert(&devlink->params, param->id, param_item, GFP_KERNEL);
728
if (err)
729
goto err_xa_insert;
730
731
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
732
return 0;
733
734
err_xa_insert:
735
kfree(param_item);
736
return err;
737
}
738
739
static void devlink_param_unregister(struct devlink *devlink,
740
const struct devlink_param *param)
741
{
742
struct devlink_param_item *param_item;
743
744
param_item = devlink_param_find_by_id(&devlink->params, param->id);
745
if (WARN_ON(!param_item))
746
return;
747
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_DEL);
748
xa_erase(&devlink->params, param->id);
749
kfree(param_item);
750
}
751
752
/**
753
* devl_params_register - register configuration parameters
754
*
755
* @devlink: devlink
756
* @params: configuration parameters array
757
* @params_count: number of parameters provided
758
*
759
* Register the configuration parameters supported by the driver.
760
*/
761
int devl_params_register(struct devlink *devlink,
762
const struct devlink_param *params,
763
size_t params_count)
764
{
765
const struct devlink_param *param = params;
766
int i, err;
767
768
lockdep_assert_held(&devlink->lock);
769
770
for (i = 0; i < params_count; i++, param++) {
771
err = devlink_param_register(devlink, param);
772
if (err)
773
goto rollback;
774
}
775
return 0;
776
777
rollback:
778
if (!i)
779
return err;
780
781
for (param--; i > 0; i--, param--)
782
devlink_param_unregister(devlink, param);
783
return err;
784
}
785
EXPORT_SYMBOL_GPL(devl_params_register);
786
787
int devlink_params_register(struct devlink *devlink,
788
const struct devlink_param *params,
789
size_t params_count)
790
{
791
int err;
792
793
devl_lock(devlink);
794
err = devl_params_register(devlink, params, params_count);
795
devl_unlock(devlink);
796
return err;
797
}
798
EXPORT_SYMBOL_GPL(devlink_params_register);
799
800
/**
801
* devl_params_unregister - unregister configuration parameters
802
* @devlink: devlink
803
* @params: configuration parameters to unregister
804
* @params_count: number of parameters provided
805
*/
806
void devl_params_unregister(struct devlink *devlink,
807
const struct devlink_param *params,
808
size_t params_count)
809
{
810
const struct devlink_param *param = params;
811
int i;
812
813
lockdep_assert_held(&devlink->lock);
814
815
for (i = 0; i < params_count; i++, param++)
816
devlink_param_unregister(devlink, param);
817
}
818
EXPORT_SYMBOL_GPL(devl_params_unregister);
819
820
void devlink_params_unregister(struct devlink *devlink,
821
const struct devlink_param *params,
822
size_t params_count)
823
{
824
devl_lock(devlink);
825
devl_params_unregister(devlink, params, params_count);
826
devl_unlock(devlink);
827
}
828
EXPORT_SYMBOL_GPL(devlink_params_unregister);
829
830
/**
831
* devl_param_driverinit_value_get - get configuration parameter
832
* value for driver initializing
833
*
834
* @devlink: devlink
835
* @param_id: parameter ID
836
* @val: pointer to store the value of parameter in driverinit
837
* configuration mode
838
*
839
* This function should be used by the driver to get driverinit
840
* configuration for initialization after reload command.
841
*
842
* Note that lockless call of this function relies on the
843
* driver to maintain following basic sane behavior:
844
* 1) Driver ensures a call to this function cannot race with
845
* registering/unregistering the parameter with the same parameter ID.
846
* 2) Driver ensures a call to this function cannot race with
847
* devl_param_driverinit_value_set() call with the same parameter ID.
848
* 3) Driver ensures a call to this function cannot race with
849
* reload operation.
850
* If the driver is not able to comply, it has to take the devlink->lock
851
* while calling this.
852
*/
853
int devl_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
854
union devlink_param_value *val)
855
{
856
struct devlink_param_item *param_item;
857
858
if (WARN_ON(!devlink_reload_supported(devlink->ops)))
859
return -EOPNOTSUPP;
860
861
param_item = devlink_param_find_by_id(&devlink->params, param_id);
862
if (!param_item)
863
return -EINVAL;
864
865
if (!param_item->driverinit_value_valid)
866
return -EOPNOTSUPP;
867
868
if (WARN_ON(!devlink_param_cmode_is_supported(param_item->param,
869
DEVLINK_PARAM_CMODE_DRIVERINIT)))
870
return -EOPNOTSUPP;
871
872
*val = param_item->driverinit_value;
873
874
return 0;
875
}
876
EXPORT_SYMBOL_GPL(devl_param_driverinit_value_get);
877
878
/**
879
* devl_param_driverinit_value_set - set value of configuration
880
* parameter for driverinit
881
* configuration mode
882
*
883
* @devlink: devlink
884
* @param_id: parameter ID
885
* @init_val: value of parameter to set for driverinit configuration mode
886
*
887
* This function should be used by the driver to set driverinit
888
* configuration mode default value.
889
*/
890
void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
891
union devlink_param_value init_val)
892
{
893
struct devlink_param_item *param_item;
894
895
devl_assert_locked(devlink);
896
897
param_item = devlink_param_find_by_id(&devlink->params, param_id);
898
if (WARN_ON(!param_item))
899
return;
900
901
if (WARN_ON(!devlink_param_cmode_is_supported(param_item->param,
902
DEVLINK_PARAM_CMODE_DRIVERINIT)))
903
return;
904
905
param_item->driverinit_value = init_val;
906
param_item->driverinit_value_valid = true;
907
param_item->driverinit_default = init_val;
908
909
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
910
}
911
EXPORT_SYMBOL_GPL(devl_param_driverinit_value_set);
912
913
void devlink_params_driverinit_load_new(struct devlink *devlink)
914
{
915
struct devlink_param_item *param_item;
916
unsigned long param_id;
917
918
xa_for_each(&devlink->params, param_id, param_item) {
919
if (!devlink_param_cmode_is_supported(param_item->param,
920
DEVLINK_PARAM_CMODE_DRIVERINIT) ||
921
!param_item->driverinit_value_new_valid)
922
continue;
923
param_item->driverinit_value = param_item->driverinit_value_new;
924
param_item->driverinit_value_valid = true;
925
param_item->driverinit_value_new_valid = false;
926
}
927
}
928
929
/**
930
* devl_param_value_changed - notify devlink on a parameter's value
931
* change. Should be called by the driver
932
* right after the change.
933
*
934
* @devlink: devlink
935
* @param_id: parameter ID
936
*
937
* This function should be used by the driver to notify devlink on value
938
* change, excluding driverinit configuration mode.
939
* For driverinit configuration mode driver should use the function
940
*/
941
void devl_param_value_changed(struct devlink *devlink, u32 param_id)
942
{
943
struct devlink_param_item *param_item;
944
945
param_item = devlink_param_find_by_id(&devlink->params, param_id);
946
WARN_ON(!param_item);
947
948
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
949
}
950
EXPORT_SYMBOL_GPL(devl_param_value_changed);
951
952