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