xref: /linux/net/devlink/resource.c (revision 333f7de560e1196034b67db16916b10a0c529e1d)
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 /**
10  * struct devlink_resource - devlink resource
11  * @name: name of the resource
12  * @id: id, per devlink instance
13  * @size: size of the resource
14  * @size_new: updated size of the resource, reload is needed
15  * @size_valid: valid in case the total size of the resource is valid
16  *              including its children
17  * @parent: parent resource
18  * @size_params: size parameters
19  * @list: parent list
20  * @resource_list: list of child resources
21  * @occ_get: occupancy getter callback
22  * @occ_get_priv: occupancy getter callback priv
23  */
24 struct devlink_resource {
25 	const char *name;
26 	u64 id;
27 	u64 size;
28 	u64 size_new;
29 	bool size_valid;
30 	struct devlink_resource *parent;
31 	struct devlink_resource_size_params size_params;
32 	struct list_head list;
33 	struct list_head resource_list;
34 	devlink_resource_occ_get_t *occ_get;
35 	void *occ_get_priv;
36 };
37 
38 static struct devlink_resource *
39 __devlink_resource_find(struct list_head *resource_list_head,
40 			struct devlink_resource *resource,
41 			u64 resource_id)
42 {
43 	struct list_head *resource_list;
44 
45 	if (resource)
46 		resource_list = &resource->resource_list;
47 	else
48 		resource_list = resource_list_head;
49 
50 	list_for_each_entry(resource, resource_list, list) {
51 		struct devlink_resource *child_resource;
52 
53 		if (resource->id == resource_id)
54 			return resource;
55 
56 		child_resource = __devlink_resource_find(resource_list_head,
57 							 resource,
58 							 resource_id);
59 		if (child_resource)
60 			return child_resource;
61 	}
62 	return NULL;
63 }
64 
65 static struct devlink_resource *
66 devlink_resource_find(struct devlink *devlink,
67 		      struct devlink_resource *resource, u64 resource_id)
68 {
69 	return __devlink_resource_find(&devlink->resource_list,
70 				       resource, resource_id);
71 }
72 
73 static void
74 devlink_resource_validate_children(struct devlink_resource *resource)
75 {
76 	struct devlink_resource *child_resource;
77 	bool size_valid = true;
78 	u64 parts_size = 0;
79 
80 	if (list_empty(&resource->resource_list))
81 		goto out;
82 
83 	list_for_each_entry(child_resource, &resource->resource_list, list)
84 		parts_size += child_resource->size_new;
85 
86 	if (parts_size > resource->size_new)
87 		size_valid = false;
88 out:
89 	resource->size_valid = size_valid;
90 }
91 
92 static int
93 devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
94 			       struct netlink_ext_ack *extack)
95 {
96 	u64 reminder;
97 	int err = 0;
98 
99 	if (size > resource->size_params.size_max) {
100 		NL_SET_ERR_MSG(extack, "Size larger than maximum");
101 		err = -EINVAL;
102 	}
103 
104 	if (size < resource->size_params.size_min) {
105 		NL_SET_ERR_MSG(extack, "Size smaller than minimum");
106 		err = -EINVAL;
107 	}
108 
109 	div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
110 	if (reminder) {
111 		NL_SET_ERR_MSG(extack, "Wrong granularity");
112 		err = -EINVAL;
113 	}
114 
115 	return err;
116 }
117 
118 int devlink_nl_resource_set_doit(struct sk_buff *skb, struct genl_info *info)
119 {
120 	struct devlink *devlink = devlink_nl_ctx(info)->devlink;
121 	struct devlink_resource *resource;
122 	u64 resource_id;
123 	u64 size;
124 	int err;
125 
126 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_RESOURCE_ID) ||
127 	    GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_RESOURCE_SIZE))
128 		return -EINVAL;
129 	resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
130 
131 	resource = devlink_resource_find(devlink, NULL, resource_id);
132 	if (!resource)
133 		return -EINVAL;
134 
135 	size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
136 	err = devlink_resource_validate_size(resource, size, info->extack);
137 	if (err)
138 		return err;
139 
140 	resource->size_new = size;
141 	devlink_resource_validate_children(resource);
142 	if (resource->parent)
143 		devlink_resource_validate_children(resource->parent);
144 	return 0;
145 }
146 
147 static int
148 devlink_resource_size_params_put(struct devlink_resource *resource,
149 				 struct sk_buff *skb)
150 {
151 	struct devlink_resource_size_params *size_params;
152 
153 	size_params = &resource->size_params;
154 	if (devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
155 			       size_params->size_granularity) ||
156 	    devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
157 			       size_params->size_max) ||
158 	    devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
159 			       size_params->size_min) ||
160 	    nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
161 		return -EMSGSIZE;
162 	return 0;
163 }
164 
165 static int devlink_resource_occ_put(struct devlink_resource *resource,
166 				    struct sk_buff *skb)
167 {
168 	if (!resource->occ_get)
169 		return 0;
170 	return devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_OCC,
171 				  resource->occ_get(resource->occ_get_priv));
172 }
173 
174 static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
175 				struct devlink_resource *resource)
176 {
177 	struct devlink_resource *child_resource;
178 	struct nlattr *child_resource_attr;
179 	struct nlattr *resource_attr;
180 
181 	resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
182 	if (!resource_attr)
183 		return -EMSGSIZE;
184 
185 	if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
186 	    devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size) ||
187 	    devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id))
188 		goto nla_put_failure;
189 	if (resource->size != resource->size_new &&
190 	    devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
191 			       resource->size_new))
192 		goto nla_put_failure;
193 	if (devlink_resource_occ_put(resource, skb))
194 		goto nla_put_failure;
195 	if (devlink_resource_size_params_put(resource, skb))
196 		goto nla_put_failure;
197 	if (list_empty(&resource->resource_list))
198 		goto out;
199 
200 	if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
201 		       resource->size_valid))
202 		goto nla_put_failure;
203 
204 	child_resource_attr = nla_nest_start_noflag(skb,
205 						    DEVLINK_ATTR_RESOURCE_LIST);
206 	if (!child_resource_attr)
207 		goto nla_put_failure;
208 
209 	list_for_each_entry(child_resource, &resource->resource_list, list) {
210 		if (devlink_resource_put(devlink, skb, child_resource))
211 			goto resource_put_failure;
212 	}
213 
214 	nla_nest_end(skb, child_resource_attr);
215 out:
216 	nla_nest_end(skb, resource_attr);
217 	return 0;
218 
219 resource_put_failure:
220 	nla_nest_cancel(skb, child_resource_attr);
221 nla_put_failure:
222 	nla_nest_cancel(skb, resource_attr);
223 	return -EMSGSIZE;
224 }
225 
226 static int devlink_resource_list_fill(struct sk_buff *skb,
227 				      struct devlink *devlink,
228 				      struct list_head *resource_list_head,
229 				      int *idx)
230 {
231 	struct devlink_resource *resource;
232 	int i = 0;
233 	int err;
234 
235 	list_for_each_entry(resource, resource_list_head, list) {
236 		if (i < *idx) {
237 			i++;
238 			continue;
239 		}
240 		err = devlink_resource_put(devlink, skb, resource);
241 		if (err) {
242 			*idx = i;
243 			return err;
244 		}
245 		i++;
246 	}
247 	*idx = 0;
248 	return 0;
249 }
250 
251 static int devlink_resource_fill(struct genl_info *info,
252 				 enum devlink_command cmd, int flags)
253 {
254 	struct devlink_nl_ctx *ctx = devlink_nl_ctx(info);
255 	struct devlink *devlink = ctx->devlink;
256 	struct devlink_port *devlink_port;
257 	struct devlink_resource *resource;
258 	struct list_head *resource_list;
259 	struct nlattr *resources_attr;
260 	struct sk_buff *skb = NULL;
261 	struct nlmsghdr *nlh;
262 	bool incomplete;
263 	void *hdr;
264 	int i;
265 	int err;
266 
267 	devlink_port = ctx->devlink_port;
268 	resource_list = devlink_port ?
269 		&devlink_port->resource_list : &devlink->resource_list;
270 	resource = list_first_entry(resource_list,
271 				    struct devlink_resource, list);
272 start_again:
273 	err = devlink_nl_msg_reply_and_new(&skb, info);
274 	if (err)
275 		return err;
276 
277 	hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
278 			  &devlink_nl_family, NLM_F_MULTI, cmd);
279 	if (!hdr) {
280 		nlmsg_free(skb);
281 		return -EMSGSIZE;
282 	}
283 
284 	if (devlink_nl_put_handle(skb, devlink))
285 		goto nla_put_failure;
286 	if (devlink_port &&
287 	    nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
288 		goto nla_put_failure;
289 
290 	resources_attr = nla_nest_start_noflag(skb,
291 					       DEVLINK_ATTR_RESOURCE_LIST);
292 	if (!resources_attr)
293 		goto nla_put_failure;
294 
295 	incomplete = false;
296 	i = 0;
297 	list_for_each_entry_from(resource, resource_list, list) {
298 		err = devlink_resource_put(devlink, skb, resource);
299 		if (err) {
300 			if (!i)
301 				goto err_resource_put;
302 			incomplete = true;
303 			break;
304 		}
305 		i++;
306 	}
307 	nla_nest_end(skb, resources_attr);
308 	genlmsg_end(skb, hdr);
309 	if (incomplete)
310 		goto start_again;
311 send_done:
312 	nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
313 			NLMSG_DONE, 0, flags | NLM_F_MULTI);
314 	if (!nlh) {
315 		err = devlink_nl_msg_reply_and_new(&skb, info);
316 		if (err)
317 			return err;
318 		goto send_done;
319 	}
320 	return genlmsg_reply(skb, info);
321 
322 nla_put_failure:
323 	err = -EMSGSIZE;
324 err_resource_put:
325 	nlmsg_free(skb);
326 	return err;
327 }
328 
329 int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info)
330 {
331 	struct devlink_nl_ctx *ctx = devlink_nl_ctx(info);
332 	struct devlink *devlink = ctx->devlink;
333 	struct devlink_port *devlink_port;
334 	struct list_head *resource_list;
335 
336 	devlink_port = ctx->devlink_port;
337 	if (info->attrs[DEVLINK_ATTR_PORT_INDEX] && !devlink_port)
338 		return -ENODEV;
339 
340 	resource_list = devlink_port ?
341 		&devlink_port->resource_list : &devlink->resource_list;
342 	if (list_empty(resource_list))
343 		return -EOPNOTSUPP;
344 
345 	return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
346 }
347 
348 static int
349 devlink_resource_dump_fill_one(struct sk_buff *skb, struct devlink *devlink,
350 			       struct devlink_port *devlink_port,
351 			       struct netlink_callback *cb, int flags, int *idx)
352 {
353 	struct list_head *resource_list;
354 	struct nlattr *resources_attr;
355 	int start_idx = *idx;
356 	void *hdr;
357 	int err;
358 
359 	resource_list = devlink_port ?
360 		&devlink_port->resource_list : &devlink->resource_list;
361 
362 	if (list_empty(resource_list))
363 		return 0;
364 
365 	err = -EMSGSIZE;
366 	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
367 			  &devlink_nl_family, flags, DEVLINK_CMD_RESOURCE_DUMP);
368 	if (!hdr)
369 		return err;
370 
371 	if (devlink_nl_put_handle(skb, devlink))
372 		goto nla_put_failure;
373 	if (devlink_port &&
374 	    nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
375 		goto nla_put_failure;
376 
377 	resources_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE_LIST);
378 	if (!resources_attr)
379 		goto nla_put_failure;
380 
381 	err = devlink_resource_list_fill(skb, devlink, resource_list, idx);
382 	if (err) {
383 		if (*idx == start_idx)
384 			goto resource_list_cancel;
385 		nla_nest_end(skb, resources_attr);
386 		genlmsg_end(skb, hdr);
387 		return err;
388 	}
389 	nla_nest_end(skb, resources_attr);
390 	genlmsg_end(skb, hdr);
391 	return 0;
392 
393 resource_list_cancel:
394 	nla_nest_cancel(skb, resources_attr);
395 nla_put_failure:
396 	genlmsg_cancel(skb, hdr);
397 	return err;
398 }
399 
400 static int
401 devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
402 			     struct netlink_callback *cb, int flags)
403 {
404 	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
405 	const struct genl_info *info = genl_info_dump(cb);
406 	struct devlink_port *devlink_port;
407 	struct nlattr *scope_attr = NULL;
408 	unsigned long port_idx;
409 	u32 scope = 0;
410 	int err;
411 
412 	if (info->attrs && info->attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK]) {
413 		scope_attr = info->attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK];
414 		scope = nla_get_u32(scope_attr);
415 		if (!scope) {
416 			NL_SET_ERR_MSG_ATTR(info->extack, scope_attr,
417 					    "empty resource scope selection");
418 			return -EINVAL;
419 		}
420 	}
421 
422 	if (!state->port_ctx.index_valid &&
423 	    (!scope || (scope & DEVLINK_RESOURCE_SCOPE_DEV))) {
424 		err = devlink_resource_dump_fill_one(skb, devlink, NULL,
425 						     cb, flags, &state->idx);
426 		if (err)
427 			return err;
428 		state->idx = 0;
429 	}
430 
431 	if (scope && !(scope & DEVLINK_RESOURCE_SCOPE_PORT))
432 		goto out;
433 	/* Check in case port was removed between dump callbacks. */
434 	if (state->port_ctx.index_valid &&
435 	    !xa_load(&devlink->ports, state->port_ctx.index))
436 		state->idx = 0;
437 	state->port_ctx.index_valid = true;
438 	xa_for_each_start(&devlink->ports, port_idx, devlink_port,
439 			  state->port_ctx.index) {
440 		err = devlink_resource_dump_fill_one(skb, devlink, devlink_port,
441 						     cb, flags, &state->idx);
442 		if (err) {
443 			state->port_ctx.index = port_idx;
444 			return err;
445 		}
446 		state->idx = 0;
447 	}
448 out:
449 	state->port_ctx.index_valid = false;
450 	state->port_ctx.index = 0;
451 	return 0;
452 }
453 
454 int devlink_nl_resource_dump_dumpit(struct sk_buff *skb,
455 				    struct netlink_callback *cb)
456 {
457 	return devlink_nl_dumpit(skb, cb, devlink_nl_resource_dump_one);
458 }
459 
460 int devlink_resources_validate(struct devlink *devlink,
461 			       struct devlink_resource *resource,
462 			       struct genl_info *info)
463 {
464 	struct list_head *resource_list;
465 	int err = 0;
466 
467 	if (resource)
468 		resource_list = &resource->resource_list;
469 	else
470 		resource_list = &devlink->resource_list;
471 
472 	list_for_each_entry(resource, resource_list, list) {
473 		if (!resource->size_valid)
474 			return -EINVAL;
475 		err = devlink_resources_validate(devlink, resource, info);
476 		if (err)
477 			return err;
478 	}
479 	return err;
480 }
481 
482 static int
483 __devl_resource_register(struct devlink *devlink,
484 			 struct list_head *resource_list_head,
485 			 const char *resource_name, u64 resource_size,
486 			 u64 resource_id, u64 parent_resource_id,
487 			 const struct devlink_resource_size_params *params)
488 {
489 	struct devlink_resource *resource;
490 	struct list_head *resource_list;
491 	bool top_hierarchy;
492 
493 	WARN_ON(resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP);
494 
495 	lockdep_assert_held(&devlink->lock);
496 
497 	top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
498 
499 	resource = __devlink_resource_find(resource_list_head, NULL,
500 					   resource_id);
501 	if (resource)
502 		return -EEXIST;
503 
504 	resource = kzalloc_obj(*resource);
505 	if (!resource)
506 		return -ENOMEM;
507 
508 	if (top_hierarchy) {
509 		resource_list = resource_list_head;
510 	} else {
511 		struct devlink_resource *parent_resource;
512 
513 		parent_resource = __devlink_resource_find(resource_list_head,
514 							  NULL,
515 							  parent_resource_id);
516 		if (parent_resource) {
517 			resource_list = &parent_resource->resource_list;
518 			resource->parent = parent_resource;
519 		} else {
520 			kfree(resource);
521 			return -EINVAL;
522 		}
523 	}
524 
525 	resource->name = resource_name;
526 	resource->size = resource_size;
527 	resource->size_new = resource_size;
528 	resource->id = resource_id;
529 	resource->size_valid = true;
530 	memcpy(&resource->size_params, params, sizeof(resource->size_params));
531 	INIT_LIST_HEAD(&resource->resource_list);
532 	list_add_tail(&resource->list, resource_list);
533 
534 	return 0;
535 }
536 
537 /**
538  * devl_resource_register - devlink resource register
539  *
540  * @devlink: devlink
541  * @resource_name: resource's name
542  * @resource_size: resource's size
543  * @resource_id: resource's id
544  * @parent_resource_id: resource's parent id
545  * @params: size parameters
546  *
547  * Generic resources should reuse the same names across drivers.
548  * Please see the generic resources list at:
549  * Documentation/networking/devlink/devlink-resource.rst
550  *
551  * Return: 0 on success, negative error code otherwise.
552  */
553 int devl_resource_register(struct devlink *devlink, const char *resource_name,
554 			   u64 resource_size, u64 resource_id,
555 			   u64 parent_resource_id,
556 			   const struct devlink_resource_size_params *params)
557 {
558 	return __devl_resource_register(devlink, &devlink->resource_list,
559 					resource_name, resource_size,
560 					resource_id, parent_resource_id,
561 					params);
562 }
563 EXPORT_SYMBOL_GPL(devl_resource_register);
564 
565 static void devlink_resource_unregister(struct devlink_resource *resource)
566 {
567 	struct devlink_resource *tmp, *child_resource;
568 
569 	list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
570 				 list) {
571 		devlink_resource_unregister(child_resource);
572 		list_del(&child_resource->list);
573 		kfree(child_resource);
574 	}
575 }
576 
577 static void
578 __devl_resources_unregister(struct devlink *devlink,
579 			    struct list_head *resource_list_head)
580 {
581 	struct devlink_resource *tmp, *child_resource;
582 
583 	lockdep_assert_held(&devlink->lock);
584 
585 	list_for_each_entry_safe(child_resource, tmp, resource_list_head,
586 				 list) {
587 		devlink_resource_unregister(child_resource);
588 		list_del(&child_resource->list);
589 		kfree(child_resource);
590 	}
591 }
592 
593 /**
594  * devl_resources_unregister - free all resources
595  *
596  * @devlink: devlink
597  */
598 void devl_resources_unregister(struct devlink *devlink)
599 {
600 	__devl_resources_unregister(devlink, &devlink->resource_list);
601 }
602 EXPORT_SYMBOL_GPL(devl_resources_unregister);
603 
604 /**
605  *	devlink_resources_unregister - free all resources
606  *
607  *	@devlink: devlink
608  *
609  *	Context: Takes and release devlink->lock <mutex>.
610  */
611 void devlink_resources_unregister(struct devlink *devlink)
612 {
613 	devl_lock(devlink);
614 	devl_resources_unregister(devlink);
615 	devl_unlock(devlink);
616 }
617 EXPORT_SYMBOL_GPL(devlink_resources_unregister);
618 
619 /**
620  * devl_resource_size_get - get and update size
621  *
622  * @devlink: devlink
623  * @resource_id: the requested resource id
624  * @p_resource_size: ptr to update
625  */
626 int devl_resource_size_get(struct devlink *devlink,
627 			   u64 resource_id,
628 			   u64 *p_resource_size)
629 {
630 	struct devlink_resource *resource;
631 
632 	lockdep_assert_held(&devlink->lock);
633 
634 	resource = devlink_resource_find(devlink, NULL, resource_id);
635 	if (!resource)
636 		return -EINVAL;
637 	*p_resource_size = resource->size_new;
638 	resource->size = resource->size_new;
639 	return 0;
640 }
641 EXPORT_SYMBOL_GPL(devl_resource_size_get);
642 
643 /**
644  * devl_resource_occ_get_register - register occupancy getter
645  *
646  * @devlink: devlink
647  * @resource_id: resource id
648  * @occ_get: occupancy getter callback
649  * @occ_get_priv: occupancy getter callback priv
650  */
651 void devl_resource_occ_get_register(struct devlink *devlink,
652 				    u64 resource_id,
653 				    devlink_resource_occ_get_t *occ_get,
654 				    void *occ_get_priv)
655 {
656 	struct devlink_resource *resource;
657 
658 	lockdep_assert_held(&devlink->lock);
659 
660 	resource = devlink_resource_find(devlink, NULL, resource_id);
661 	if (WARN_ON(!resource))
662 		return;
663 	WARN_ON(resource->occ_get);
664 
665 	resource->occ_get = occ_get;
666 	resource->occ_get_priv = occ_get_priv;
667 }
668 EXPORT_SYMBOL_GPL(devl_resource_occ_get_register);
669 
670 /**
671  * devl_resource_occ_get_unregister - unregister occupancy getter
672  *
673  * @devlink: devlink
674  * @resource_id: resource id
675  */
676 void devl_resource_occ_get_unregister(struct devlink *devlink,
677 				      u64 resource_id)
678 {
679 	struct devlink_resource *resource;
680 
681 	lockdep_assert_held(&devlink->lock);
682 
683 	resource = devlink_resource_find(devlink, NULL, resource_id);
684 	if (WARN_ON(!resource))
685 		return;
686 	WARN_ON(!resource->occ_get);
687 
688 	resource->occ_get = NULL;
689 	resource->occ_get_priv = NULL;
690 }
691 EXPORT_SYMBOL_GPL(devl_resource_occ_get_unregister);
692 
693 /**
694  * devl_port_resource_register - devlink port resource register
695  *
696  * @devlink_port: devlink port
697  * @resource_name: resource's name
698  * @resource_size: resource's size
699  * @resource_id: resource's id
700  * @parent_resource_id: resource's parent id
701  * @params: size parameters
702  *
703  * Generic resources should reuse the same names across drivers.
704  * Please see the generic resources list at:
705  * Documentation/networking/devlink/devlink-resource.rst
706  *
707  * Return: 0 on success, negative error code otherwise.
708  */
709 int
710 devl_port_resource_register(struct devlink_port *devlink_port,
711 			    const char *resource_name,
712 			    u64 resource_size, u64 resource_id,
713 			    u64 parent_resource_id,
714 			    const struct devlink_resource_size_params *params)
715 {
716 	return __devl_resource_register(devlink_port->devlink,
717 					&devlink_port->resource_list,
718 					resource_name, resource_size,
719 					resource_id, parent_resource_id,
720 					params);
721 }
722 EXPORT_SYMBOL_GPL(devl_port_resource_register);
723 
724 /**
725  * devl_port_resources_unregister - unregister all devlink port resources
726  *
727  * @devlink_port: devlink port
728  */
729 void devl_port_resources_unregister(struct devlink_port *devlink_port)
730 {
731 	__devl_resources_unregister(devlink_port->devlink,
732 				    &devlink_port->resource_list);
733 }
734 EXPORT_SYMBOL_GPL(devl_port_resources_unregister);
735