Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'devlink-add-per-port-resource-support'

Tariq Toukan says:

====================
devlink: add per-port resource support

This series by Or adds devlink per-port resource support:

Currently, devlink resources are only available at the device level.
However, some resources are inherently per-port, such as the maximum
number of subfunctions (SFs) that can be created on a specific PF port.
This limitation prevents user space from obtaining accurate per-port
capacity information.
This series adds infrastructure for per-port resources in devlink core
and implements it in the mlx5 driver to expose the max_SFs resource
on PF devlink ports.

Patch #1 refactors resource functions to be generic
Patch #2 adds port-level resource registration infrastructure
Patch #3 registers SF resource on PF port representor in mlx5
Patch #4 adds devlink port resource registration to netdevsim for testing
Patch #5 adds dump support for device-level resources
Patch #6 includes port resources in the resource dump dumpit path
Patch #7 adds port-specific option to resource dump doit path
Patch #8 adds selftest for devlink port resource doit
Patch #9 documents port-level resources and full dump
Patch #10 adds resource scope filtering to resource dump
Patch #11 adds selftest for resource dump and scope filter
Patch #12 documents resource scope filtering
====================

Link: https://patch.msgid.link/20260407194107.148063-1-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+570 -59
+30 -2
Documentation/netlink/specs/devlink.yaml
··· 159 159 name: entry 160 160 - 161 161 type: enum 162 + name: resource-scope 163 + entries: 164 + - 165 + name: dev 166 + - 167 + name: port 168 + - 169 + type: enum 162 170 name: reload-action 163 171 entries: 164 172 - ··· 881 873 doc: Unique devlink instance index. 882 874 checks: 883 875 max: u32-max 876 + - 877 + name: resource-scope-mask 878 + type: u32 879 + enum: resource-scope 880 + enum-as-flags: true 881 + doc: | 882 + Bitmask selecting which resource classes to include in a 883 + resource-dump response. Bit 0 (dev) selects device-level 884 + resources; bit 1 (port) selects port-level resources. 885 + When absent all classes are returned. 884 886 - 885 887 name: dl-dev-stats 886 888 subset-of: devlink ··· 1775 1757 attribute-set: devlink 1776 1758 dont-validate: [strict] 1777 1759 do: 1778 - pre: devlink-nl-pre-doit 1760 + pre: devlink-nl-pre-doit-port-optional 1779 1761 post: devlink-nl-post-doit 1780 1762 request: 1781 1763 attributes: 1782 1764 - bus-name 1783 1765 - dev-name 1784 1766 - index 1785 - reply: 1767 + - port-index 1768 + reply: &resource-dump-reply 1786 1769 value: 36 1787 1770 attributes: 1788 1771 - bus-name 1789 1772 - dev-name 1790 1773 - index 1774 + - port-index 1791 1775 - resource-list 1776 + dump: 1777 + request: 1778 + attributes: 1779 + - bus-name 1780 + - dev-name 1781 + - index 1782 + - resource-scope-mask 1783 + reply: *resource-dump-reply 1792 1784 1793 1785 - 1794 1786 name: reload
+4
drivers/net/ethernet/mellanox/mlx5/core/devlink.h
··· 14 14 MLX5_ID_RES_MAX = __MLX5_ID_RES_MAX - 1, 15 15 }; 16 16 17 + enum mlx5_devlink_port_resource_id { 18 + MLX5_DL_PORT_RES_MAX_SFS = 1, 19 + }; 20 + 17 21 enum mlx5_devlink_param_id { 18 22 MLX5_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 19 23 MLX5_DEVLINK_PARAM_ID_FLOW_STEERING_MODE,
+22 -1
drivers/net/netdevsim/dev.c
··· 1486 1486 if (err) 1487 1487 goto err_port_free; 1488 1488 1489 + if (nsim_dev_port_is_pf(nsim_dev_port)) { 1490 + u64 parent_id = DEVLINK_RESOURCE_ID_PARENT_TOP; 1491 + struct devlink_resource_size_params params = { 1492 + .size_max = 100, 1493 + .size_granularity = 1, 1494 + .unit = DEVLINK_RESOURCE_UNIT_ENTRY 1495 + }; 1496 + 1497 + err = devl_port_resource_register(devlink_port, 1498 + "test_resource", 20, 1499 + NSIM_PORT_RESOURCE_TEST, 1500 + parent_id, &params); 1501 + if (err) 1502 + goto err_dl_port_unregister; 1503 + } 1504 + 1489 1505 err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port); 1490 1506 if (err) 1491 - goto err_dl_port_unregister; 1507 + goto err_port_resource_unregister; 1492 1508 1493 1509 nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port, perm_addr); 1494 1510 if (IS_ERR(nsim_dev_port->ns)) { ··· 1527 1511 nsim_destroy(nsim_dev_port->ns); 1528 1512 err_port_debugfs_exit: 1529 1513 nsim_dev_port_debugfs_exit(nsim_dev_port); 1514 + err_port_resource_unregister: 1515 + if (nsim_dev_port_is_pf(nsim_dev_port)) 1516 + devl_port_resources_unregister(devlink_port); 1530 1517 err_dl_port_unregister: 1531 1518 devl_port_unregister(devlink_port); 1532 1519 err_port_free: ··· 1546 1527 devl_rate_leaf_destroy(&nsim_dev_port->devlink_port); 1547 1528 nsim_destroy(nsim_dev_port->ns); 1548 1529 nsim_dev_port_debugfs_exit(nsim_dev_port); 1530 + if (nsim_dev_port_is_pf(nsim_dev_port)) 1531 + devl_port_resources_unregister(devlink_port); 1549 1532 devl_port_unregister(devlink_port); 1550 1533 kfree(nsim_dev_port); 1551 1534 }
+4
drivers/net/netdevsim/netdevsim.h
··· 224 224 NSIM_RESOURCE_NEXTHOPS, 225 225 }; 226 226 227 + enum nsim_port_resource_id { 228 + NSIM_PORT_RESOURCE_TEST = 1, 229 + }; 230 + 227 231 struct nsim_dev_health { 228 232 struct devlink_health_reporter *empty_reporter; 229 233 struct devlink_health_reporter *dummy_reporter;
+9 -1
include/net/devlink.h
··· 129 129 struct devlink_port { 130 130 struct list_head list; 131 131 struct list_head region_list; 132 + struct list_head resource_list; 132 133 struct devlink *devlink; 133 134 const struct devlink_port_ops *ops; 134 135 unsigned int index; ··· 1886 1885 u64 resource_size, 1887 1886 u64 resource_id, 1888 1887 u64 parent_resource_id, 1889 - const struct devlink_resource_size_params *size_params); 1888 + const struct devlink_resource_size_params *params); 1890 1889 void devl_resources_unregister(struct devlink *devlink); 1891 1890 void devlink_resources_unregister(struct devlink *devlink); 1892 1891 int devl_resource_size_get(struct devlink *devlink, 1893 1892 u64 resource_id, 1894 1893 u64 *p_resource_size); 1894 + int 1895 + devl_port_resource_register(struct devlink_port *devlink_port, 1896 + const char *resource_name, 1897 + u64 resource_size, u64 resource_id, 1898 + u64 parent_resource_id, 1899 + const struct devlink_resource_size_params *params); 1900 + void devl_port_resources_unregister(struct devlink_port *devlink_port); 1895 1901 int devl_dpipe_table_resource_set(struct devlink *devlink, 1896 1902 const char *table_name, u64 resource_id, 1897 1903 u64 resource_units);
+11
include/uapi/linux/devlink.h
··· 645 645 DEVLINK_ATTR_PARAM_RESET_DEFAULT, /* flag */ 646 646 647 647 DEVLINK_ATTR_INDEX, /* uint */ 648 + DEVLINK_ATTR_RESOURCE_SCOPE_MASK, /* u32 */ 648 649 649 650 /* Add new attributes above here, update the spec in 650 651 * Documentation/netlink/specs/devlink.yaml and re-generate ··· 704 703 enum devlink_resource_unit { 705 704 DEVLINK_RESOURCE_UNIT_ENTRY, 706 705 }; 706 + 707 + enum devlink_resource_scope { 708 + DEVLINK_RESOURCE_SCOPE_DEV_BIT, 709 + DEVLINK_RESOURCE_SCOPE_PORT_BIT, 710 + }; 711 + 712 + #define DEVLINK_RESOURCE_SCOPE_DEV \ 713 + _BITUL(DEVLINK_RESOURCE_SCOPE_DEV_BIT) 714 + #define DEVLINK_RESOURCE_SCOPE_PORT \ 715 + _BITUL(DEVLINK_RESOURCE_SCOPE_PORT_BIT) 707 716 708 717 enum devlink_port_fn_attr_cap { 709 718 DEVLINK_PORT_FN_ATTR_CAP_ROCE_BIT,
+5
net/devlink/devl_internal.h
··· 164 164 struct { 165 165 u64 dump_ts; 166 166 }; 167 + /* DEVLINK_CMD_RESOURCE_DUMP */ 168 + struct { 169 + u32 index; 170 + bool index_valid; 171 + } port_ctx; 167 172 }; 168 173 }; 169 174
+2
net/devlink/netlink.c
··· 370 370 371 371 /* restart sub-object walk for the next instance */ 372 372 state->idx = 0; 373 + state->port_ctx.index = 0; 374 + state->port_ctx.index_valid = false; 373 375 } 374 376 375 377 if (err != -EMSGSIZE)
+2
net/devlink/port.c
··· 1025 1025 return; 1026 1026 devlink_port->devlink = devlink; 1027 1027 INIT_LIST_HEAD(&devlink_port->region_list); 1028 + INIT_LIST_HEAD(&devlink_port->resource_list); 1028 1029 devlink_port->initialized = true; 1029 1030 } 1030 1031 EXPORT_SYMBOL_GPL(devlink_port_init); ··· 1043 1042 void devlink_port_fini(struct devlink_port *devlink_port) 1044 1043 { 1045 1044 WARN_ON(!list_empty(&devlink_port->region_list)); 1045 + WARN_ON(!list_empty(&devlink_port->resource_list)); 1046 1046 } 1047 1047 EXPORT_SYMBOL_GPL(devlink_port_fini); 1048 1048
+271 -47
net/devlink/resource.c
··· 36 36 }; 37 37 38 38 static struct devlink_resource * 39 - devlink_resource_find(struct devlink *devlink, 40 - struct devlink_resource *resource, u64 resource_id) 39 + __devlink_resource_find(struct list_head *resource_list_head, 40 + struct devlink_resource *resource, 41 + u64 resource_id) 41 42 { 42 43 struct list_head *resource_list; 43 44 44 45 if (resource) 45 46 resource_list = &resource->resource_list; 46 47 else 47 - resource_list = &devlink->resource_list; 48 + resource_list = resource_list_head; 48 49 49 50 list_for_each_entry(resource, resource_list, list) { 50 51 struct devlink_resource *child_resource; ··· 53 52 if (resource->id == resource_id) 54 53 return resource; 55 54 56 - child_resource = devlink_resource_find(devlink, resource, 57 - resource_id); 55 + child_resource = __devlink_resource_find(resource_list_head, 56 + resource, 57 + resource_id); 58 58 if (child_resource) 59 59 return child_resource; 60 60 } 61 61 return NULL; 62 + } 63 + 64 + static struct devlink_resource * 65 + devlink_resource_find(struct devlink *devlink, 66 + struct devlink_resource *resource, u64 resource_id) 67 + { 68 + return __devlink_resource_find(&devlink->resource_list, 69 + resource, resource_id); 62 70 } 63 71 64 72 static void ··· 223 213 return -EMSGSIZE; 224 214 } 225 215 216 + static int devlink_resource_list_fill(struct sk_buff *skb, 217 + struct devlink *devlink, 218 + struct list_head *resource_list_head, 219 + int *idx) 220 + { 221 + struct devlink_resource *resource; 222 + int i = 0; 223 + int err; 224 + 225 + list_for_each_entry(resource, resource_list_head, list) { 226 + if (i < *idx) { 227 + i++; 228 + continue; 229 + } 230 + err = devlink_resource_put(devlink, skb, resource); 231 + if (err) { 232 + *idx = i; 233 + return err; 234 + } 235 + i++; 236 + } 237 + *idx = 0; 238 + return 0; 239 + } 240 + 226 241 static int devlink_resource_fill(struct genl_info *info, 227 242 enum devlink_command cmd, int flags) 228 243 { 244 + struct devlink_port *devlink_port = info->user_ptr[1]; 229 245 struct devlink *devlink = info->user_ptr[0]; 230 246 struct devlink_resource *resource; 247 + struct list_head *resource_list; 231 248 struct nlattr *resources_attr; 232 249 struct sk_buff *skb = NULL; 233 250 struct nlmsghdr *nlh; ··· 263 226 int i; 264 227 int err; 265 228 266 - resource = list_first_entry(&devlink->resource_list, 229 + resource_list = devlink_port ? 230 + &devlink_port->resource_list : &devlink->resource_list; 231 + resource = list_first_entry(resource_list, 267 232 struct devlink_resource, list); 268 233 start_again: 269 234 err = devlink_nl_msg_reply_and_new(&skb, info); ··· 281 242 282 243 if (devlink_nl_put_handle(skb, devlink)) 283 244 goto nla_put_failure; 245 + if (devlink_port && 246 + nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX, devlink_port->index)) 247 + goto nla_put_failure; 284 248 285 249 resources_attr = nla_nest_start_noflag(skb, 286 250 DEVLINK_ATTR_RESOURCE_LIST); ··· 292 250 293 251 incomplete = false; 294 252 i = 0; 295 - list_for_each_entry_from(resource, &devlink->resource_list, list) { 253 + list_for_each_entry_from(resource, resource_list, list) { 296 254 err = devlink_resource_put(devlink, skb, resource); 297 255 if (err) { 298 256 if (!i) ··· 326 284 327 285 int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info) 328 286 { 287 + struct devlink_port *devlink_port = info->user_ptr[1]; 329 288 struct devlink *devlink = info->user_ptr[0]; 289 + struct list_head *resource_list; 330 290 331 - if (list_empty(&devlink->resource_list)) 291 + if (info->attrs[DEVLINK_ATTR_PORT_INDEX] && !devlink_port) 292 + return -ENODEV; 293 + 294 + resource_list = devlink_port ? 295 + &devlink_port->resource_list : &devlink->resource_list; 296 + if (list_empty(resource_list)) 332 297 return -EOPNOTSUPP; 333 298 334 299 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0); 300 + } 301 + 302 + static int 303 + devlink_resource_dump_fill_one(struct sk_buff *skb, struct devlink *devlink, 304 + struct devlink_port *devlink_port, 305 + struct netlink_callback *cb, int flags, int *idx) 306 + { 307 + struct list_head *resource_list; 308 + struct nlattr *resources_attr; 309 + int start_idx = *idx; 310 + void *hdr; 311 + int err; 312 + 313 + resource_list = devlink_port ? 314 + &devlink_port->resource_list : &devlink->resource_list; 315 + 316 + if (list_empty(resource_list)) 317 + return 0; 318 + 319 + err = -EMSGSIZE; 320 + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 321 + &devlink_nl_family, flags, DEVLINK_CMD_RESOURCE_DUMP); 322 + if (!hdr) 323 + return err; 324 + 325 + if (devlink_nl_put_handle(skb, devlink)) 326 + goto nla_put_failure; 327 + if (devlink_port && 328 + nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX, devlink_port->index)) 329 + goto nla_put_failure; 330 + 331 + resources_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE_LIST); 332 + if (!resources_attr) 333 + goto nla_put_failure; 334 + 335 + err = devlink_resource_list_fill(skb, devlink, resource_list, idx); 336 + if (err) { 337 + if (*idx == start_idx) 338 + goto resource_list_cancel; 339 + nla_nest_end(skb, resources_attr); 340 + genlmsg_end(skb, hdr); 341 + return err; 342 + } 343 + nla_nest_end(skb, resources_attr); 344 + genlmsg_end(skb, hdr); 345 + return 0; 346 + 347 + resource_list_cancel: 348 + nla_nest_cancel(skb, resources_attr); 349 + nla_put_failure: 350 + genlmsg_cancel(skb, hdr); 351 + return err; 352 + } 353 + 354 + static int 355 + devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink, 356 + struct netlink_callback *cb, int flags) 357 + { 358 + struct devlink_nl_dump_state *state = devlink_dump_state(cb); 359 + const struct genl_info *info = genl_info_dump(cb); 360 + struct devlink_port *devlink_port; 361 + struct nlattr *scope_attr = NULL; 362 + unsigned long port_idx; 363 + u32 scope = 0; 364 + int err; 365 + 366 + if (info->attrs && info->attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK]) { 367 + scope_attr = info->attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK]; 368 + scope = nla_get_u32(scope_attr); 369 + if (!scope) { 370 + NL_SET_ERR_MSG_ATTR(info->extack, scope_attr, 371 + "empty resource scope selection"); 372 + return -EINVAL; 373 + } 374 + } 375 + 376 + if (!state->port_ctx.index_valid && 377 + (!scope || (scope & DEVLINK_RESOURCE_SCOPE_DEV))) { 378 + err = devlink_resource_dump_fill_one(skb, devlink, NULL, 379 + cb, flags, &state->idx); 380 + if (err) 381 + return err; 382 + state->idx = 0; 383 + } 384 + 385 + if (scope && !(scope & DEVLINK_RESOURCE_SCOPE_PORT)) 386 + goto out; 387 + /* Check in case port was removed between dump callbacks. */ 388 + if (state->port_ctx.index_valid && 389 + !xa_load(&devlink->ports, state->port_ctx.index)) 390 + state->idx = 0; 391 + state->port_ctx.index_valid = true; 392 + xa_for_each_start(&devlink->ports, port_idx, devlink_port, 393 + state->port_ctx.index) { 394 + err = devlink_resource_dump_fill_one(skb, devlink, devlink_port, 395 + cb, flags, &state->idx); 396 + if (err) { 397 + state->port_ctx.index = port_idx; 398 + return err; 399 + } 400 + state->idx = 0; 401 + } 402 + out: 403 + state->port_ctx.index_valid = false; 404 + state->port_ctx.index = 0; 405 + return 0; 406 + } 407 + 408 + int devlink_nl_resource_dump_dumpit(struct sk_buff *skb, 409 + struct netlink_callback *cb) 410 + { 411 + return devlink_nl_dumpit(skb, cb, devlink_nl_resource_dump_one); 335 412 } 336 413 337 414 int devlink_resources_validate(struct devlink *devlink, ··· 475 314 return err; 476 315 } 477 316 478 - /** 479 - * devl_resource_register - devlink resource register 480 - * 481 - * @devlink: devlink 482 - * @resource_name: resource's name 483 - * @resource_size: resource's size 484 - * @resource_id: resource's id 485 - * @parent_resource_id: resource's parent id 486 - * @size_params: size parameters 487 - * 488 - * Generic resources should reuse the same names across drivers. 489 - * Please see the generic resources list at: 490 - * Documentation/networking/devlink/devlink-resource.rst 491 - */ 492 - int devl_resource_register(struct devlink *devlink, 493 - const char *resource_name, 494 - u64 resource_size, 495 - u64 resource_id, 496 - u64 parent_resource_id, 497 - const struct devlink_resource_size_params *size_params) 317 + static int 318 + __devl_resource_register(struct devlink *devlink, 319 + struct list_head *resource_list_head, 320 + const char *resource_name, u64 resource_size, 321 + u64 resource_id, u64 parent_resource_id, 322 + const struct devlink_resource_size_params *params) 498 323 { 499 324 struct devlink_resource *resource; 500 325 struct list_head *resource_list; ··· 490 343 491 344 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP; 492 345 493 - resource = devlink_resource_find(devlink, NULL, resource_id); 346 + resource = __devlink_resource_find(resource_list_head, NULL, 347 + resource_id); 494 348 if (resource) 495 349 return -EEXIST; 496 350 ··· 500 352 return -ENOMEM; 501 353 502 354 if (top_hierarchy) { 503 - resource_list = &devlink->resource_list; 355 + resource_list = resource_list_head; 504 356 } else { 505 357 struct devlink_resource *parent_resource; 506 358 507 - parent_resource = devlink_resource_find(devlink, NULL, 508 - parent_resource_id); 359 + parent_resource = __devlink_resource_find(resource_list_head, 360 + NULL, 361 + parent_resource_id); 509 362 if (parent_resource) { 510 363 resource_list = &parent_resource->resource_list; 511 364 resource->parent = parent_resource; ··· 521 372 resource->size_new = resource_size; 522 373 resource->id = resource_id; 523 374 resource->size_valid = true; 524 - memcpy(&resource->size_params, size_params, 525 - sizeof(resource->size_params)); 375 + memcpy(&resource->size_params, params, sizeof(resource->size_params)); 526 376 INIT_LIST_HEAD(&resource->resource_list); 527 377 list_add_tail(&resource->list, resource_list); 528 378 529 379 return 0; 530 380 } 381 + 382 + /** 383 + * devl_resource_register - devlink resource register 384 + * 385 + * @devlink: devlink 386 + * @resource_name: resource's name 387 + * @resource_size: resource's size 388 + * @resource_id: resource's id 389 + * @parent_resource_id: resource's parent id 390 + * @params: size parameters 391 + * 392 + * Generic resources should reuse the same names across drivers. 393 + * Please see the generic resources list at: 394 + * Documentation/networking/devlink/devlink-resource.rst 395 + * 396 + * Return: 0 on success, negative error code otherwise. 397 + */ 398 + int devl_resource_register(struct devlink *devlink, const char *resource_name, 399 + u64 resource_size, u64 resource_id, 400 + u64 parent_resource_id, 401 + const struct devlink_resource_size_params *params) 402 + { 403 + return __devl_resource_register(devlink, &devlink->resource_list, 404 + resource_name, resource_size, 405 + resource_id, parent_resource_id, 406 + params); 407 + } 531 408 EXPORT_SYMBOL_GPL(devl_resource_register); 532 409 533 - static void devlink_resource_unregister(struct devlink *devlink, 534 - struct devlink_resource *resource) 410 + static void devlink_resource_unregister(struct devlink_resource *resource) 535 411 { 536 412 struct devlink_resource *tmp, *child_resource; 537 413 538 414 list_for_each_entry_safe(child_resource, tmp, &resource->resource_list, 539 415 list) { 540 - devlink_resource_unregister(devlink, child_resource); 416 + devlink_resource_unregister(child_resource); 417 + list_del(&child_resource->list); 418 + kfree(child_resource); 419 + } 420 + } 421 + 422 + static void 423 + __devl_resources_unregister(struct devlink *devlink, 424 + struct list_head *resource_list_head) 425 + { 426 + struct devlink_resource *tmp, *child_resource; 427 + 428 + lockdep_assert_held(&devlink->lock); 429 + 430 + list_for_each_entry_safe(child_resource, tmp, resource_list_head, 431 + list) { 432 + devlink_resource_unregister(child_resource); 541 433 list_del(&child_resource->list); 542 434 kfree(child_resource); 543 435 } ··· 591 401 */ 592 402 void devl_resources_unregister(struct devlink *devlink) 593 403 { 594 - struct devlink_resource *tmp, *child_resource; 595 - 596 - lockdep_assert_held(&devlink->lock); 597 - 598 - list_for_each_entry_safe(child_resource, tmp, &devlink->resource_list, 599 - list) { 600 - devlink_resource_unregister(devlink, child_resource); 601 - list_del(&child_resource->list); 602 - kfree(child_resource); 603 - } 404 + __devl_resources_unregister(devlink, &devlink->resource_list); 604 405 } 605 406 EXPORT_SYMBOL_GPL(devl_resources_unregister); 606 407 ··· 683 502 resource->occ_get_priv = NULL; 684 503 } 685 504 EXPORT_SYMBOL_GPL(devl_resource_occ_get_unregister); 505 + 506 + /** 507 + * devl_port_resource_register - devlink port resource register 508 + * 509 + * @devlink_port: devlink port 510 + * @resource_name: resource's name 511 + * @resource_size: resource's size 512 + * @resource_id: resource's id 513 + * @parent_resource_id: resource's parent id 514 + * @params: size parameters 515 + * 516 + * Generic resources should reuse the same names across drivers. 517 + * Please see the generic resources list at: 518 + * Documentation/networking/devlink/devlink-resource.rst 519 + * 520 + * Return: 0 on success, negative error code otherwise. 521 + */ 522 + int 523 + devl_port_resource_register(struct devlink_port *devlink_port, 524 + const char *resource_name, 525 + u64 resource_size, u64 resource_id, 526 + u64 parent_resource_id, 527 + const struct devlink_resource_size_params *params) 528 + { 529 + return __devl_resource_register(devlink_port->devlink, 530 + &devlink_port->resource_list, 531 + resource_name, resource_size, 532 + resource_id, parent_resource_id, 533 + params); 534 + } 535 + EXPORT_SYMBOL_GPL(devl_port_resource_register); 536 + 537 + /** 538 + * devl_port_resources_unregister - unregister all devlink port resources 539 + * 540 + * @devlink_port: devlink port 541 + */ 542 + void devl_port_resources_unregister(struct devlink_port *devlink_port) 543 + { 544 + __devl_resources_unregister(devlink_port->devlink, 545 + &devlink_port->resource_list); 546 + } 547 + EXPORT_SYMBOL_GPL(devl_port_resources_unregister);
+78 -1
tools/testing/selftests/drivers/net/netdevsim/devlink.sh
··· 5 5 6 6 ALL_TESTS="fw_flash_test params_test \ 7 7 params_default_test regions_test reload_test \ 8 - netns_reload_test resource_test dev_info_test \ 8 + netns_reload_test resource_test resource_dump_test \ 9 + port_resource_doit_test dev_info_test \ 9 10 empty_reporter_test dummy_reporter_test rate_test" 10 11 NUM_NETIFS=0 11 12 source $lib_dir/lib.sh ··· 483 482 log_test "resource test" 484 483 } 485 484 485 + resource_dump_test() 486 + { 487 + RET=0 488 + 489 + local port_jq 490 + local dev_jq 491 + local dl_jq 492 + local count 493 + 494 + dl_jq="with_entries(select(.key | startswith(\"$DL_HANDLE\")))" 495 + port_jq="[.[] | $dl_jq | keys |" 496 + port_jq+=" map(select(test(\"/.+/\"))) | length] | add" 497 + dev_jq="[.[] | $dl_jq | keys |" 498 + dev_jq+=" map(select(test(\"/.+/\")|not)) | length] | add" 499 + 500 + if ! devlink resource help 2>&1 | grep -q "scope"; then 501 + echo "SKIP: devlink resource show not supported" 502 + return 503 + fi 504 + 505 + devlink resource show > /dev/null 2>&1 506 + check_err $? "Failed to dump all resources" 507 + 508 + count=$(cmd_jq "devlink resource show -j" "$port_jq") 509 + [ "$count" -gt "0" ] 510 + check_err $? "missing port resources in resource dump" 511 + 512 + count=$(cmd_jq "devlink resource show -j" "$dev_jq") 513 + [ "$count" -gt "0" ] 514 + check_err $? "missing device resources in resource dump" 515 + 516 + count=$(cmd_jq "devlink resource show scope dev -j" "$dev_jq") 517 + [ "$count" -gt "0" ] 518 + check_err $? "dev scope missing device resources" 519 + 520 + count=$(cmd_jq "devlink resource show scope dev -j" "$port_jq") 521 + [ "$count" -eq "0" ] 522 + check_err $? "dev scope returned port resources" 523 + 524 + count=$(cmd_jq "devlink resource show scope port -j" "$port_jq") 525 + [ "$count" -gt "0" ] 526 + check_err $? "port scope missing port resources" 527 + 528 + count=$(cmd_jq "devlink resource show scope port -j" "$dev_jq") 529 + [ "$count" -eq "0" ] 530 + check_err $? "port scope returned device resources" 531 + 532 + log_test "resource dump test" 533 + } 534 + 486 535 info_get() 487 536 { 488 537 local name=$1 ··· 817 766 local handle=$1 818 767 819 768 devlink port function rate del $handle 769 + } 770 + 771 + port_resource_doit_test() 772 + { 773 + RET=0 774 + 775 + local port_handle="${DL_HANDLE}/0" 776 + local name 777 + local size 778 + 779 + if ! devlink resource help 2>&1 | grep -q "PORT_INDEX"; then 780 + echo "SKIP: devlink resource show with port not supported" 781 + return 782 + fi 783 + 784 + name=$(cmd_jq "devlink resource show $port_handle -j" \ 785 + '.[][][].name') 786 + [ "$name" == "test_resource" ] 787 + check_err $? "wrong port resource name (got $name)" 788 + 789 + size=$(cmd_jq "devlink resource show $port_handle -j" \ 790 + '.[][][].size') 791 + [ "$size" == "20" ] 792 + check_err $? "wrong port resource size (got $size)" 793 + 794 + log_test "port resource doit test" 820 795 } 821 796 822 797 rate_test()