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