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