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 .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
117static 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
130static 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
144static struct devlink_param_item *
145devlink_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
157static struct devlink_param_item *
158devlink_param_find_by_id(struct xarray *params, u32 param_id)
159{
160 return xa_load(params, param_id);
161}
162
163static bool
164devlink_param_cmode_is_supported(const struct devlink_param *param,
165 enum devlink_param_cmode cmode)
166{
167 return test_bit(cmode, ¶m->supported_cmodes);
168}
169
170static 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
179static 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
189static int
190devlink_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
238value_nest_cancel:
239 nla_nest_cancel(msg, param_value_attr);
240nla_put_failure:
241 return -EMSGSIZE;
242}
243
244static 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
323values_list_nest_cancel:
324 nla_nest_end(msg, param_values_list);
325param_nest_cancel:
326 nla_nest_cancel(msg, param_attr);
327genlmsg_cancel:
328 genlmsg_cancel(msg, hdr);
329 return -EMSGSIZE;
330}
331
332static 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
364static 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
374void devlink_params_notify_register(struct devlink *devlink)
375{
376 devlink_params_notify(devlink, DEVLINK_CMD_PARAM_NEW);
377}
378
379void devlink_params_notify_unregister(struct devlink *devlink)
380{
381 devlink_params_notify(devlink, DEVLINK_CMD_PARAM_DEL);
382}
383
384static 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
410int 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
416static int
417devlink_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
428static int
429devlink_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
478static struct devlink_param_item *
479devlink_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
490int 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
517static 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, ¶m_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
572int 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
580int 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
587int 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
594int 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
601static 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
611static 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
638err_xa_insert:
639 kfree(param_item);
640 return err;
641}
642
643static 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 */
665int 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
681rollback:
682 if (!i)
683 return err;
684
685 for (param--; i > 0; i--, param--)
686 devlink_param_unregister(devlink, param);
687 return err;
688}
689EXPORT_SYMBOL_GPL(devl_params_register);
690
691int 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}
702EXPORT_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 */
710void 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}
722EXPORT_SYMBOL_GPL(devl_params_unregister);
723
724void 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}
732EXPORT_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 */
757int 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}
780EXPORT_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 */
794void 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}
814EXPORT_SYMBOL_GPL(devl_param_driverinit_value_set);
815
816void 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 */
844void 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}
853EXPORT_SYMBOL_GPL(devl_param_value_changed);