Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/devlink/param.c
29267 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
117
static int devlink_param_generic_verify(const struct devlink_param *param)
118
{
119
/* verify it match generic parameter by id and name */
120
if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
121
return -EINVAL;
122
if (strcmp(param->name, devlink_param_generic[param->id].name))
123
return -ENOENT;
124
125
WARN_ON(param->type != devlink_param_generic[param->id].type);
126
127
return 0;
128
}
129
130
static int devlink_param_driver_verify(const struct devlink_param *param)
131
{
132
int i;
133
134
if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
135
return -EINVAL;
136
/* verify no such name in generic params */
137
for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
138
if (!strcmp(param->name, devlink_param_generic[i].name))
139
return -EEXIST;
140
141
return 0;
142
}
143
144
static struct devlink_param_item *
145
devlink_param_find_by_name(struct xarray *params, const char *param_name)
146
{
147
struct devlink_param_item *param_item;
148
unsigned long param_id;
149
150
xa_for_each(params, param_id, param_item) {
151
if (!strcmp(param_item->param->name, param_name))
152
return param_item;
153
}
154
return NULL;
155
}
156
157
static struct devlink_param_item *
158
devlink_param_find_by_id(struct xarray *params, u32 param_id)
159
{
160
return xa_load(params, param_id);
161
}
162
163
static bool
164
devlink_param_cmode_is_supported(const struct devlink_param *param,
165
enum devlink_param_cmode cmode)
166
{
167
return test_bit(cmode, &param->supported_cmodes);
168
}
169
170
static int devlink_param_get(struct devlink *devlink,
171
const struct devlink_param *param,
172
struct devlink_param_gset_ctx *ctx)
173
{
174
if (!param->get)
175
return -EOPNOTSUPP;
176
return param->get(devlink, param->id, ctx);
177
}
178
179
static int devlink_param_set(struct devlink *devlink,
180
const struct devlink_param *param,
181
struct devlink_param_gset_ctx *ctx,
182
struct netlink_ext_ack *extack)
183
{
184
if (!param->set)
185
return -EOPNOTSUPP;
186
return param->set(devlink, param->id, ctx, extack);
187
}
188
189
static int
190
devlink_nl_param_value_fill_one(struct sk_buff *msg,
191
enum devlink_param_type type,
192
enum devlink_param_cmode cmode,
193
union devlink_param_value val)
194
{
195
struct nlattr *param_value_attr;
196
197
param_value_attr = nla_nest_start_noflag(msg,
198
DEVLINK_ATTR_PARAM_VALUE);
199
if (!param_value_attr)
200
goto nla_put_failure;
201
202
if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
203
goto value_nest_cancel;
204
205
switch (type) {
206
case DEVLINK_PARAM_TYPE_U8:
207
if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
208
goto value_nest_cancel;
209
break;
210
case DEVLINK_PARAM_TYPE_U16:
211
if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
212
goto value_nest_cancel;
213
break;
214
case DEVLINK_PARAM_TYPE_U32:
215
if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
216
goto value_nest_cancel;
217
break;
218
case DEVLINK_PARAM_TYPE_U64:
219
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
220
val.vu64))
221
goto value_nest_cancel;
222
break;
223
case DEVLINK_PARAM_TYPE_STRING:
224
if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
225
val.vstr))
226
goto value_nest_cancel;
227
break;
228
case DEVLINK_PARAM_TYPE_BOOL:
229
if (val.vbool &&
230
nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
231
goto value_nest_cancel;
232
break;
233
}
234
235
nla_nest_end(msg, param_value_attr);
236
return 0;
237
238
value_nest_cancel:
239
nla_nest_cancel(msg, param_value_attr);
240
nla_put_failure:
241
return -EMSGSIZE;
242
}
243
244
static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
245
unsigned int port_index,
246
struct devlink_param_item *param_item,
247
enum devlink_command cmd,
248
u32 portid, u32 seq, int flags)
249
{
250
union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
251
bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
252
const struct devlink_param *param = param_item->param;
253
struct devlink_param_gset_ctx ctx;
254
struct nlattr *param_values_list;
255
struct nlattr *param_attr;
256
void *hdr;
257
int err;
258
int i;
259
260
/* Get value from driver part to driverinit configuration mode */
261
for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
262
if (!devlink_param_cmode_is_supported(param, i))
263
continue;
264
if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
265
if (param_item->driverinit_value_new_valid)
266
param_value[i] = param_item->driverinit_value_new;
267
else if (param_item->driverinit_value_valid)
268
param_value[i] = param_item->driverinit_value;
269
else
270
return -EOPNOTSUPP;
271
} else {
272
ctx.cmode = i;
273
err = devlink_param_get(devlink, param, &ctx);
274
if (err)
275
return err;
276
param_value[i] = ctx.val;
277
}
278
param_value_set[i] = true;
279
}
280
281
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
282
if (!hdr)
283
return -EMSGSIZE;
284
285
if (devlink_nl_put_handle(msg, devlink))
286
goto genlmsg_cancel;
287
288
if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
289
cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
290
cmd == DEVLINK_CMD_PORT_PARAM_DEL)
291
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
292
goto genlmsg_cancel;
293
294
param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
295
if (!param_attr)
296
goto genlmsg_cancel;
297
if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
298
goto param_nest_cancel;
299
if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
300
goto param_nest_cancel;
301
if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, param->type))
302
goto param_nest_cancel;
303
304
param_values_list = nla_nest_start_noflag(msg,
305
DEVLINK_ATTR_PARAM_VALUES_LIST);
306
if (!param_values_list)
307
goto param_nest_cancel;
308
309
for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
310
if (!param_value_set[i])
311
continue;
312
err = devlink_nl_param_value_fill_one(msg, param->type,
313
i, param_value[i]);
314
if (err)
315
goto values_list_nest_cancel;
316
}
317
318
nla_nest_end(msg, param_values_list);
319
nla_nest_end(msg, param_attr);
320
genlmsg_end(msg, hdr);
321
return 0;
322
323
values_list_nest_cancel:
324
nla_nest_end(msg, param_values_list);
325
param_nest_cancel:
326
nla_nest_cancel(msg, param_attr);
327
genlmsg_cancel:
328
genlmsg_cancel(msg, hdr);
329
return -EMSGSIZE;
330
}
331
332
static void devlink_param_notify(struct devlink *devlink,
333
unsigned int port_index,
334
struct devlink_param_item *param_item,
335
enum devlink_command cmd)
336
{
337
struct sk_buff *msg;
338
int err;
339
340
WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
341
cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
342
cmd != DEVLINK_CMD_PORT_PARAM_DEL);
343
344
/* devlink_notify_register() / devlink_notify_unregister()
345
* will replay the notifications if the params are added/removed
346
* outside of the lifetime of the instance.
347
*/
348
if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
349
return;
350
351
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
352
if (!msg)
353
return;
354
err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
355
0, 0, 0);
356
if (err) {
357
nlmsg_free(msg);
358
return;
359
}
360
361
devlink_nl_notify_send(devlink, msg);
362
}
363
364
static void devlink_params_notify(struct devlink *devlink,
365
enum devlink_command cmd)
366
{
367
struct devlink_param_item *param_item;
368
unsigned long param_id;
369
370
xa_for_each(&devlink->params, param_id, param_item)
371
devlink_param_notify(devlink, 0, param_item, cmd);
372
}
373
374
void devlink_params_notify_register(struct devlink *devlink)
375
{
376
devlink_params_notify(devlink, DEVLINK_CMD_PARAM_NEW);
377
}
378
379
void devlink_params_notify_unregister(struct devlink *devlink)
380
{
381
devlink_params_notify(devlink, DEVLINK_CMD_PARAM_DEL);
382
}
383
384
static int devlink_nl_param_get_dump_one(struct sk_buff *msg,
385
struct devlink *devlink,
386
struct netlink_callback *cb,
387
int flags)
388
{
389
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
390
struct devlink_param_item *param_item;
391
unsigned long param_id;
392
int err = 0;
393
394
xa_for_each_start(&devlink->params, param_id, param_item, state->idx) {
395
err = devlink_nl_param_fill(msg, devlink, 0, param_item,
396
DEVLINK_CMD_PARAM_GET,
397
NETLINK_CB(cb->skb).portid,
398
cb->nlh->nlmsg_seq, flags);
399
if (err == -EOPNOTSUPP) {
400
err = 0;
401
} else if (err) {
402
state->idx = param_id;
403
break;
404
}
405
}
406
407
return err;
408
}
409
410
int devlink_nl_param_get_dumpit(struct sk_buff *skb,
411
struct netlink_callback *cb)
412
{
413
return devlink_nl_dumpit(skb, cb, devlink_nl_param_get_dump_one);
414
}
415
416
static int
417
devlink_param_type_get_from_info(struct genl_info *info,
418
enum devlink_param_type *param_type)
419
{
420
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_TYPE))
421
return -EINVAL;
422
423
*param_type = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE]);
424
425
return 0;
426
}
427
428
static int
429
devlink_param_value_get_from_info(const struct devlink_param *param,
430
struct genl_info *info,
431
union devlink_param_value *value)
432
{
433
struct nlattr *param_data;
434
int len;
435
436
param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
437
438
if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
439
return -EINVAL;
440
441
switch (param->type) {
442
case DEVLINK_PARAM_TYPE_U8:
443
if (nla_len(param_data) != sizeof(u8))
444
return -EINVAL;
445
value->vu8 = nla_get_u8(param_data);
446
break;
447
case DEVLINK_PARAM_TYPE_U16:
448
if (nla_len(param_data) != sizeof(u16))
449
return -EINVAL;
450
value->vu16 = nla_get_u16(param_data);
451
break;
452
case DEVLINK_PARAM_TYPE_U32:
453
if (nla_len(param_data) != sizeof(u32))
454
return -EINVAL;
455
value->vu32 = nla_get_u32(param_data);
456
break;
457
case DEVLINK_PARAM_TYPE_U64:
458
if (nla_len(param_data) != sizeof(u64))
459
return -EINVAL;
460
value->vu64 = nla_get_u64(param_data);
461
break;
462
case DEVLINK_PARAM_TYPE_STRING:
463
len = strnlen(nla_data(param_data), nla_len(param_data));
464
if (len == nla_len(param_data) ||
465
len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
466
return -EINVAL;
467
strcpy(value->vstr, nla_data(param_data));
468
break;
469
case DEVLINK_PARAM_TYPE_BOOL:
470
if (param_data && nla_len(param_data))
471
return -EINVAL;
472
value->vbool = nla_get_flag(param_data);
473
break;
474
}
475
return 0;
476
}
477
478
static struct devlink_param_item *
479
devlink_param_get_from_info(struct xarray *params, struct genl_info *info)
480
{
481
char *param_name;
482
483
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_NAME))
484
return NULL;
485
486
param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
487
return devlink_param_find_by_name(params, param_name);
488
}
489
490
int devlink_nl_param_get_doit(struct sk_buff *skb,
491
struct genl_info *info)
492
{
493
struct devlink *devlink = info->user_ptr[0];
494
struct devlink_param_item *param_item;
495
struct sk_buff *msg;
496
int err;
497
498
param_item = devlink_param_get_from_info(&devlink->params, info);
499
if (!param_item)
500
return -EINVAL;
501
502
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
503
if (!msg)
504
return -ENOMEM;
505
506
err = devlink_nl_param_fill(msg, devlink, 0, param_item,
507
DEVLINK_CMD_PARAM_GET,
508
info->snd_portid, info->snd_seq, 0);
509
if (err) {
510
nlmsg_free(msg);
511
return err;
512
}
513
514
return genlmsg_reply(msg, info);
515
}
516
517
static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
518
unsigned int port_index,
519
struct xarray *params,
520
struct genl_info *info,
521
enum devlink_command cmd)
522
{
523
enum devlink_param_type param_type;
524
struct devlink_param_gset_ctx ctx;
525
enum devlink_param_cmode cmode;
526
struct devlink_param_item *param_item;
527
const struct devlink_param *param;
528
union devlink_param_value value;
529
int err = 0;
530
531
param_item = devlink_param_get_from_info(params, info);
532
if (!param_item)
533
return -EINVAL;
534
param = param_item->param;
535
err = devlink_param_type_get_from_info(info, &param_type);
536
if (err)
537
return err;
538
if (param_type != param->type)
539
return -EINVAL;
540
err = devlink_param_value_get_from_info(param, info, &value);
541
if (err)
542
return err;
543
if (param->validate) {
544
err = param->validate(devlink, param->id, value, info->extack);
545
if (err)
546
return err;
547
}
548
549
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_VALUE_CMODE))
550
return -EINVAL;
551
cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
552
if (!devlink_param_cmode_is_supported(param, cmode))
553
return -EOPNOTSUPP;
554
555
if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
556
param_item->driverinit_value_new = value;
557
param_item->driverinit_value_new_valid = true;
558
} else {
559
if (!param->set)
560
return -EOPNOTSUPP;
561
ctx.val = value;
562
ctx.cmode = cmode;
563
err = devlink_param_set(devlink, param, &ctx, info->extack);
564
if (err)
565
return err;
566
}
567
568
devlink_param_notify(devlink, port_index, param_item, cmd);
569
return 0;
570
}
571
572
int devlink_nl_param_set_doit(struct sk_buff *skb, struct genl_info *info)
573
{
574
struct devlink *devlink = info->user_ptr[0];
575
576
return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->params,
577
info, DEVLINK_CMD_PARAM_NEW);
578
}
579
580
int devlink_nl_port_param_get_dumpit(struct sk_buff *msg,
581
struct netlink_callback *cb)
582
{
583
NL_SET_ERR_MSG(cb->extack, "Port params are not supported");
584
return msg->len;
585
}
586
587
int devlink_nl_port_param_get_doit(struct sk_buff *skb,
588
struct genl_info *info)
589
{
590
NL_SET_ERR_MSG(info->extack, "Port params are not supported");
591
return -EINVAL;
592
}
593
594
int devlink_nl_port_param_set_doit(struct sk_buff *skb,
595
struct genl_info *info)
596
{
597
NL_SET_ERR_MSG(info->extack, "Port params are not supported");
598
return -EINVAL;
599
}
600
601
static int devlink_param_verify(const struct devlink_param *param)
602
{
603
if (!param || !param->name || !param->supported_cmodes)
604
return -EINVAL;
605
if (param->generic)
606
return devlink_param_generic_verify(param);
607
else
608
return devlink_param_driver_verify(param);
609
}
610
611
static int devlink_param_register(struct devlink *devlink,
612
const struct devlink_param *param)
613
{
614
struct devlink_param_item *param_item;
615
int err;
616
617
WARN_ON(devlink_param_verify(param));
618
WARN_ON(devlink_param_find_by_name(&devlink->params, param->name));
619
620
if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
621
WARN_ON(param->get || param->set);
622
else
623
WARN_ON(!param->get || !param->set);
624
625
param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
626
if (!param_item)
627
return -ENOMEM;
628
629
param_item->param = param;
630
631
err = xa_insert(&devlink->params, param->id, param_item, GFP_KERNEL);
632
if (err)
633
goto err_xa_insert;
634
635
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
636
return 0;
637
638
err_xa_insert:
639
kfree(param_item);
640
return err;
641
}
642
643
static void devlink_param_unregister(struct devlink *devlink,
644
const struct devlink_param *param)
645
{
646
struct devlink_param_item *param_item;
647
648
param_item = devlink_param_find_by_id(&devlink->params, param->id);
649
if (WARN_ON(!param_item))
650
return;
651
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_DEL);
652
xa_erase(&devlink->params, param->id);
653
kfree(param_item);
654
}
655
656
/**
657
* devl_params_register - register configuration parameters
658
*
659
* @devlink: devlink
660
* @params: configuration parameters array
661
* @params_count: number of parameters provided
662
*
663
* Register the configuration parameters supported by the driver.
664
*/
665
int devl_params_register(struct devlink *devlink,
666
const struct devlink_param *params,
667
size_t params_count)
668
{
669
const struct devlink_param *param = params;
670
int i, err;
671
672
lockdep_assert_held(&devlink->lock);
673
674
for (i = 0; i < params_count; i++, param++) {
675
err = devlink_param_register(devlink, param);
676
if (err)
677
goto rollback;
678
}
679
return 0;
680
681
rollback:
682
if (!i)
683
return err;
684
685
for (param--; i > 0; i--, param--)
686
devlink_param_unregister(devlink, param);
687
return err;
688
}
689
EXPORT_SYMBOL_GPL(devl_params_register);
690
691
int devlink_params_register(struct devlink *devlink,
692
const struct devlink_param *params,
693
size_t params_count)
694
{
695
int err;
696
697
devl_lock(devlink);
698
err = devl_params_register(devlink, params, params_count);
699
devl_unlock(devlink);
700
return err;
701
}
702
EXPORT_SYMBOL_GPL(devlink_params_register);
703
704
/**
705
* devl_params_unregister - unregister configuration parameters
706
* @devlink: devlink
707
* @params: configuration parameters to unregister
708
* @params_count: number of parameters provided
709
*/
710
void devl_params_unregister(struct devlink *devlink,
711
const struct devlink_param *params,
712
size_t params_count)
713
{
714
const struct devlink_param *param = params;
715
int i;
716
717
lockdep_assert_held(&devlink->lock);
718
719
for (i = 0; i < params_count; i++, param++)
720
devlink_param_unregister(devlink, param);
721
}
722
EXPORT_SYMBOL_GPL(devl_params_unregister);
723
724
void devlink_params_unregister(struct devlink *devlink,
725
const struct devlink_param *params,
726
size_t params_count)
727
{
728
devl_lock(devlink);
729
devl_params_unregister(devlink, params, params_count);
730
devl_unlock(devlink);
731
}
732
EXPORT_SYMBOL_GPL(devlink_params_unregister);
733
734
/**
735
* devl_param_driverinit_value_get - get configuration parameter
736
* value for driver initializing
737
*
738
* @devlink: devlink
739
* @param_id: parameter ID
740
* @val: pointer to store the value of parameter in driverinit
741
* configuration mode
742
*
743
* This function should be used by the driver to get driverinit
744
* configuration for initialization after reload command.
745
*
746
* Note that lockless call of this function relies on the
747
* driver to maintain following basic sane behavior:
748
* 1) Driver ensures a call to this function cannot race with
749
* registering/unregistering the parameter with the same parameter ID.
750
* 2) Driver ensures a call to this function cannot race with
751
* devl_param_driverinit_value_set() call with the same parameter ID.
752
* 3) Driver ensures a call to this function cannot race with
753
* reload operation.
754
* If the driver is not able to comply, it has to take the devlink->lock
755
* while calling this.
756
*/
757
int devl_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
758
union devlink_param_value *val)
759
{
760
struct devlink_param_item *param_item;
761
762
if (WARN_ON(!devlink_reload_supported(devlink->ops)))
763
return -EOPNOTSUPP;
764
765
param_item = devlink_param_find_by_id(&devlink->params, param_id);
766
if (!param_item)
767
return -EINVAL;
768
769
if (!param_item->driverinit_value_valid)
770
return -EOPNOTSUPP;
771
772
if (WARN_ON(!devlink_param_cmode_is_supported(param_item->param,
773
DEVLINK_PARAM_CMODE_DRIVERINIT)))
774
return -EOPNOTSUPP;
775
776
*val = param_item->driverinit_value;
777
778
return 0;
779
}
780
EXPORT_SYMBOL_GPL(devl_param_driverinit_value_get);
781
782
/**
783
* devl_param_driverinit_value_set - set value of configuration
784
* parameter for driverinit
785
* configuration mode
786
*
787
* @devlink: devlink
788
* @param_id: parameter ID
789
* @init_val: value of parameter to set for driverinit configuration mode
790
*
791
* This function should be used by the driver to set driverinit
792
* configuration mode default value.
793
*/
794
void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
795
union devlink_param_value init_val)
796
{
797
struct devlink_param_item *param_item;
798
799
devl_assert_locked(devlink);
800
801
param_item = devlink_param_find_by_id(&devlink->params, param_id);
802
if (WARN_ON(!param_item))
803
return;
804
805
if (WARN_ON(!devlink_param_cmode_is_supported(param_item->param,
806
DEVLINK_PARAM_CMODE_DRIVERINIT)))
807
return;
808
809
param_item->driverinit_value = init_val;
810
param_item->driverinit_value_valid = true;
811
812
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
813
}
814
EXPORT_SYMBOL_GPL(devl_param_driverinit_value_set);
815
816
void devlink_params_driverinit_load_new(struct devlink *devlink)
817
{
818
struct devlink_param_item *param_item;
819
unsigned long param_id;
820
821
xa_for_each(&devlink->params, param_id, param_item) {
822
if (!devlink_param_cmode_is_supported(param_item->param,
823
DEVLINK_PARAM_CMODE_DRIVERINIT) ||
824
!param_item->driverinit_value_new_valid)
825
continue;
826
param_item->driverinit_value = param_item->driverinit_value_new;
827
param_item->driverinit_value_valid = true;
828
param_item->driverinit_value_new_valid = false;
829
}
830
}
831
832
/**
833
* devl_param_value_changed - notify devlink on a parameter's value
834
* change. Should be called by the driver
835
* right after the change.
836
*
837
* @devlink: devlink
838
* @param_id: parameter ID
839
*
840
* This function should be used by the driver to notify devlink on value
841
* change, excluding driverinit configuration mode.
842
* For driverinit configuration mode driver should use the function
843
*/
844
void devl_param_value_changed(struct devlink *devlink, u32 param_id)
845
{
846
struct devlink_param_item *param_item;
847
848
param_item = devlink_param_find_by_id(&devlink->params, param_id);
849
WARN_ON(!param_item);
850
851
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
852
}
853
EXPORT_SYMBOL_GPL(devl_param_value_changed);
854
855