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 'mv88e6xxx-Add-per-port-devlink-regions'

Andrew Lunn says:

====================
mv88e6xxx: Add per port devlink regions

This patchset extends devlink regions to support per port regions, and
them makes use of them to support the ports of the mv88e6xxx switches.

root@rap:~# devlink region show
mdio_bus/gpio-0:00/global1: size 64 snapshot []
mdio_bus/gpio-0:00/global2: size 64 snapshot []
mdio_bus/gpio-0:00/atu: size 49152 snapshot []
mdio_bus/gpio-0:00/0/port: size 64 snapshot []
mdio_bus/gpio-0:00/1/port: size 64 snapshot []
mdio_bus/gpio-0:00/2/port: size 64 snapshot []
mdio_bus/gpio-0:00/3/port: size 64 snapshot []
mdio_bus/gpio-0:00/4/port: size 64 snapshot []
mdio_bus/gpio-0:00/5/port: size 64 snapshot []
mdio_bus/gpio-0:00/6/port: size 64 snapshot []
mdio_bus/gpio-0:00/7/port: size 64 snapshot []
mdio_bus/gpio-0:00/8/port: size 64 snapshot []
mdio_bus/gpio-0:00/9/port: size 64 snapshot []
mdio_bus/gpio-0:00/10/port: size 64 snapshot []

root@rap:~# devlink region new mdio_bus/gpio-0:00/1/port snapshot 42
root@rap:~# devlink region dump mdio_bus/gpio-0:00/1/port snapshot 42
0000000000000000 4f 1e 3e 20 00 01 01 39 3f 05 00 00 fd 07 00 00
0000000000000010 80 00 01 00 00 00 00 00 00 00 00 00 00 00 00 91
0000000000000020 00 00 00 00 00 00 00 00 00 00 00 00 22 00 00 00
0000000000000030 07 3e 00 00 00 00 00 80 00 00 00 00 00 00 5b 00

In order to support all ports of the switch, a new devlink flavour has
been added for unused ports:

mdio_bus/gpio-0:00/0: type notset flavour unused splittable false
mdio_bus/gpio-0:00/1: type notset flavour cpu port 1 splittable false
mdio_bus/gpio-0:00/2: type eth netdev red flavour physical port 2 splittable fae
mdio_bus/gpio-0:00/3: type eth netdev blue flavour physical port 3 splittable fe
mdio_bus/gpio-0:00/4: type eth netdev green flavour physical port 4 splittable e
mdio_bus/gpio-0:00/5: type notset flavour unused splittable false
mdio_bus/gpio-0:00/6: type notset flavour unused splittable false
mdio_bus/gpio-0:00/7: type notset flavour unused splittable false
mdio_bus/gpio-0:00/8: type eth netdev waic0 flavour physical port 8 splittable e
mdio_bus/gpio-0:00/9: type notset flavour unused splittable false
mdio_bus/gpio-0:00/10: type notset flavour unused splittable false

The DSA core now creates the devlink port instances earlier, so that
the driver setup function can make use of them.

v3:
Whitespace cleanup
Added justification for devlink unused flavour
Added Tested-by, Reviewed-by:
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+468 -74
+105 -4
drivers/net/dsa/mv88e6xxx/devlink.c
··· 415 415 return err; 416 416 } 417 417 418 + static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port, 419 + const struct devlink_port_region_ops *ops, 420 + struct netlink_ext_ack *extack, 421 + u8 **data) 422 + { 423 + struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port); 424 + int port = dsa_devlink_port_to_port(devlink_port); 425 + struct mv88e6xxx_chip *chip = ds->priv; 426 + u16 *registers; 427 + int i, err; 428 + 429 + registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL); 430 + if (!registers) 431 + return -ENOMEM; 432 + 433 + mv88e6xxx_reg_lock(chip); 434 + for (i = 0; i < 32; i++) { 435 + err = mv88e6xxx_port_read(chip, port, i, &registers[i]); 436 + if (err) { 437 + kfree(registers); 438 + goto out; 439 + } 440 + } 441 + *data = (u8 *)registers; 442 + out: 443 + mv88e6xxx_reg_unlock(chip); 444 + 445 + return err; 446 + } 447 + 418 448 static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = { 419 449 .id = MV88E6XXX_REGION_GLOBAL1, 420 450 }; ··· 470 440 static struct devlink_region_ops mv88e6xxx_region_atu_ops = { 471 441 .name = "atu", 472 442 .snapshot = mv88e6xxx_region_atu_snapshot, 443 + .destructor = kfree, 444 + }; 445 + 446 + static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = { 447 + .name = "port", 448 + .snapshot = mv88e6xxx_region_port_snapshot, 473 449 .destructor = kfree, 474 450 }; 475 451 ··· 507 471 dsa_devlink_region_destroy(chip->regions[i]); 508 472 } 509 473 510 - void mv88e6xxx_teardown_devlink_regions(struct dsa_switch *ds) 474 + static void 475 + mv88e6xxx_teardown_devlink_regions_port(struct mv88e6xxx_chip *chip, 476 + int port) 511 477 { 512 - struct mv88e6xxx_chip *chip = ds->priv; 478 + dsa_devlink_region_destroy(chip->ports[port].region); 479 + } 513 480 514 - mv88e6xxx_teardown_devlink_regions_global(chip); 481 + static int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, 482 + struct mv88e6xxx_chip *chip, 483 + int port) 484 + { 485 + struct devlink_region *region; 486 + 487 + region = dsa_devlink_port_region_create(ds, 488 + port, 489 + &mv88e6xxx_region_port_ops, 1, 490 + 32 * sizeof(u16)); 491 + if (IS_ERR(region)) 492 + return PTR_ERR(region); 493 + 494 + chip->ports[port].region = region; 495 + 496 + return 0; 497 + } 498 + 499 + static void 500 + mv88e6xxx_teardown_devlink_regions_ports(struct mv88e6xxx_chip *chip) 501 + { 502 + int port; 503 + 504 + for (port = 0; port < mv88e6xxx_num_ports(chip); port++) 505 + mv88e6xxx_teardown_devlink_regions_port(chip, port); 506 + } 507 + 508 + static int mv88e6xxx_setup_devlink_regions_ports(struct dsa_switch *ds, 509 + struct mv88e6xxx_chip *chip) 510 + { 511 + int port; 512 + int err; 513 + 514 + for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 515 + err = mv88e6xxx_setup_devlink_regions_port(ds, chip, port); 516 + if (err) 517 + goto out; 518 + } 519 + 520 + return 0; 521 + 522 + out: 523 + while (port-- > 0) 524 + mv88e6xxx_teardown_devlink_regions_port(chip, port); 525 + 526 + return err; 515 527 } 516 528 517 529 static int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds, ··· 595 511 int mv88e6xxx_setup_devlink_regions(struct dsa_switch *ds) 596 512 { 597 513 struct mv88e6xxx_chip *chip = ds->priv; 514 + int err; 598 515 599 - return mv88e6xxx_setup_devlink_regions_global(ds, chip); 516 + err = mv88e6xxx_setup_devlink_regions_global(ds, chip); 517 + if (err) 518 + return err; 519 + 520 + err = mv88e6xxx_setup_devlink_regions_ports(ds, chip); 521 + if (err) 522 + mv88e6xxx_teardown_devlink_regions_global(chip); 523 + 524 + return err; 525 + } 526 + 527 + void mv88e6xxx_teardown_devlink_regions(struct dsa_switch *ds) 528 + { 529 + struct mv88e6xxx_chip *chip = ds->priv; 530 + 531 + mv88e6xxx_teardown_devlink_regions_ports(chip); 532 + mv88e6xxx_teardown_devlink_regions_global(chip); 600 533 } 601 534 602 535 int mv88e6xxx_devlink_info_get(struct dsa_switch *ds,
+27
include/net/devlink.h
··· 110 110 struct devlink_port { 111 111 struct list_head list; 112 112 struct list_head param_list; 113 + struct list_head region_list; 113 114 struct devlink *devlink; 114 115 unsigned int index; 115 116 bool registered; ··· 587 586 void (*destructor)(const void *data); 588 587 int (*snapshot)(struct devlink *devlink, 589 588 const struct devlink_region_ops *ops, 589 + struct netlink_ext_ack *extack, 590 + u8 **data); 591 + void *priv; 592 + }; 593 + 594 + /** 595 + * struct devlink_port_region_ops - Region operations for a port 596 + * @name: region name 597 + * @destructor: callback used to free snapshot memory when deleting 598 + * @snapshot: callback to request an immediate snapshot. On success, 599 + * the data variable must be updated to point to the snapshot data. 600 + * The function will be called while the devlink instance lock is 601 + * held. 602 + * @priv: Pointer to driver private data for the region operation 603 + */ 604 + struct devlink_port_region_ops { 605 + const char *name; 606 + void (*destructor)(const void *data); 607 + int (*snapshot)(struct devlink_port *port, 608 + const struct devlink_port_region_ops *ops, 590 609 struct netlink_ext_ack *extack, 591 610 u8 **data); 592 611 void *priv; ··· 1466 1445 devlink_region_create(struct devlink *devlink, 1467 1446 const struct devlink_region_ops *ops, 1468 1447 u32 region_max_snapshots, u64 region_size); 1448 + struct devlink_region * 1449 + devlink_port_region_create(struct devlink_port *port, 1450 + const struct devlink_port_region_ops *ops, 1451 + u32 region_max_snapshots, u64 region_size); 1469 1452 void devlink_region_destroy(struct devlink_region *region); 1453 + void devlink_port_region_destroy(struct devlink_region *region); 1454 + 1470 1455 int devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id); 1471 1456 void devlink_region_snapshot_id_put(struct devlink *devlink, u32 id); 1472 1457 int devlink_region_snapshot_create(struct devlink_region *region,
+20
include/net/dsa.h
··· 215 215 u8 stp_state; 216 216 struct net_device *bridge_dev; 217 217 struct devlink_port devlink_port; 218 + bool devlink_port_setup; 218 219 struct phylink *pl; 219 220 struct phylink_config pl_config; 220 221 ··· 681 680 dsa_devlink_region_create(struct dsa_switch *ds, 682 681 const struct devlink_region_ops *ops, 683 682 u32 region_max_snapshots, u64 region_size); 683 + struct devlink_region * 684 + dsa_devlink_port_region_create(struct dsa_switch *ds, 685 + int port, 686 + const struct devlink_port_region_ops *ops, 687 + u32 region_max_snapshots, u64 region_size); 684 688 void dsa_devlink_region_destroy(struct devlink_region *region); 685 689 686 690 struct dsa_port *dsa_port_from_netdev(struct net_device *netdev); ··· 699 693 struct dsa_devlink_priv *dl_priv = devlink_priv(dl); 700 694 701 695 return dl_priv->ds; 696 + } 697 + 698 + static inline 699 + struct dsa_switch *dsa_devlink_port_to_ds(struct devlink_port *port) 700 + { 701 + struct devlink *dl = port->devlink; 702 + struct dsa_devlink_priv *dl_priv = devlink_priv(dl); 703 + 704 + return dl_priv->ds; 705 + } 706 + 707 + static inline int dsa_devlink_port_to_port(struct devlink_port *port) 708 + { 709 + return port->index; 702 710 } 703 711 704 712 struct dsa_switch_driver {
+3
include/uapi/linux/devlink.h
··· 197 197 * port that faces the PCI VF. 198 198 */ 199 199 DEVLINK_PORT_FLAVOUR_VIRTUAL, /* Any virtual port facing the user. */ 200 + DEVLINK_PORT_FLAVOUR_UNUSED, /* Port which exists in the switch, but 201 + * is not used in any way. 202 + */ 200 203 }; 201 204 202 205 enum devlink_param_cmode {
+227 -27
net/core/devlink.c
··· 347 347 348 348 struct devlink_region { 349 349 struct devlink *devlink; 350 + struct devlink_port *port; 350 351 struct list_head list; 351 - const struct devlink_region_ops *ops; 352 + union { 353 + const struct devlink_region_ops *ops; 354 + const struct devlink_port_region_ops *port_ops; 355 + }; 352 356 struct list_head snapshot_list; 353 357 u32 max_snapshots; 354 358 u32 cur_snapshots; ··· 372 368 struct devlink_region *region; 373 369 374 370 list_for_each_entry(region, &devlink->region_list, list) 371 + if (!strcmp(region->ops->name, region_name)) 372 + return region; 373 + 374 + return NULL; 375 + } 376 + 377 + static struct devlink_region * 378 + devlink_port_region_get_by_name(struct devlink_port *port, 379 + const char *region_name) 380 + { 381 + struct devlink_region *region; 382 + 383 + list_for_each_entry(region, &port->region_list, list) 375 384 if (!strcmp(region->ops->name, region_name)) 376 385 return region; 377 386 ··· 3943 3926 if (err) 3944 3927 goto nla_put_failure; 3945 3928 3929 + if (region->port) 3930 + if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, 3931 + region->port->index)) 3932 + goto nla_put_failure; 3933 + 3946 3934 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name); 3947 3935 if (err) 3948 3936 goto nla_put_failure; ··· 3994 3972 err = devlink_nl_put_handle(msg, devlink); 3995 3973 if (err) 3996 3974 goto out_cancel_msg; 3975 + 3976 + if (region->port) 3977 + if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, 3978 + region->port->index)) 3979 + goto out_cancel_msg; 3997 3980 3998 3981 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, 3999 3982 region->ops->name); ··· 4246 4219 struct genl_info *info) 4247 4220 { 4248 4221 struct devlink *devlink = info->user_ptr[0]; 4222 + struct devlink_port *port = NULL; 4249 4223 struct devlink_region *region; 4250 4224 const char *region_name; 4251 4225 struct sk_buff *msg; 4226 + unsigned int index; 4252 4227 int err; 4253 4228 4254 4229 if (!info->attrs[DEVLINK_ATTR_REGION_NAME]) 4255 4230 return -EINVAL; 4256 4231 4232 + if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) { 4233 + index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 4234 + 4235 + port = devlink_port_get_by_index(devlink, index); 4236 + if (!port) 4237 + return -ENODEV; 4238 + } 4239 + 4257 4240 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]); 4258 - region = devlink_region_get_by_name(devlink, region_name); 4241 + if (port) 4242 + region = devlink_port_region_get_by_name(port, region_name); 4243 + else 4244 + region = devlink_region_get_by_name(devlink, region_name); 4245 + 4259 4246 if (!region) 4260 4247 return -EINVAL; 4261 4248 ··· 4288 4247 return genlmsg_reply(msg, info); 4289 4248 } 4290 4249 4250 + static int devlink_nl_cmd_region_get_port_dumpit(struct sk_buff *msg, 4251 + struct netlink_callback *cb, 4252 + struct devlink_port *port, 4253 + int *idx, 4254 + int start) 4255 + { 4256 + struct devlink_region *region; 4257 + int err = 0; 4258 + 4259 + list_for_each_entry(region, &port->region_list, list) { 4260 + if (*idx < start) { 4261 + (*idx)++; 4262 + continue; 4263 + } 4264 + err = devlink_nl_region_fill(msg, port->devlink, 4265 + DEVLINK_CMD_REGION_GET, 4266 + NETLINK_CB(cb->skb).portid, 4267 + cb->nlh->nlmsg_seq, 4268 + NLM_F_MULTI, region); 4269 + if (err) 4270 + goto out; 4271 + (*idx)++; 4272 + } 4273 + 4274 + out: 4275 + return err; 4276 + } 4277 + 4278 + static int devlink_nl_cmd_region_get_devlink_dumpit(struct sk_buff *msg, 4279 + struct netlink_callback *cb, 4280 + struct devlink *devlink, 4281 + int *idx, 4282 + int start) 4283 + { 4284 + struct devlink_region *region; 4285 + struct devlink_port *port; 4286 + int err = 0; 4287 + 4288 + mutex_lock(&devlink->lock); 4289 + list_for_each_entry(region, &devlink->region_list, list) { 4290 + if (*idx < start) { 4291 + (*idx)++; 4292 + continue; 4293 + } 4294 + err = devlink_nl_region_fill(msg, devlink, 4295 + DEVLINK_CMD_REGION_GET, 4296 + NETLINK_CB(cb->skb).portid, 4297 + cb->nlh->nlmsg_seq, 4298 + NLM_F_MULTI, region); 4299 + if (err) 4300 + goto out; 4301 + (*idx)++; 4302 + } 4303 + 4304 + list_for_each_entry(port, &devlink->port_list, list) { 4305 + err = devlink_nl_cmd_region_get_port_dumpit(msg, cb, port, idx, 4306 + start); 4307 + if (err) 4308 + goto out; 4309 + } 4310 + 4311 + out: 4312 + mutex_unlock(&devlink->lock); 4313 + return err; 4314 + } 4315 + 4291 4316 static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg, 4292 4317 struct netlink_callback *cb) 4293 4318 { 4294 - struct devlink_region *region; 4295 4319 struct devlink *devlink; 4296 4320 int start = cb->args[0]; 4297 4321 int idx = 0; ··· 4366 4260 list_for_each_entry(devlink, &devlink_list, list) { 4367 4261 if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) 4368 4262 continue; 4369 - 4370 - mutex_lock(&devlink->lock); 4371 - list_for_each_entry(region, &devlink->region_list, list) { 4372 - if (idx < start) { 4373 - idx++; 4374 - continue; 4375 - } 4376 - err = devlink_nl_region_fill(msg, devlink, 4377 - DEVLINK_CMD_REGION_GET, 4378 - NETLINK_CB(cb->skb).portid, 4379 - cb->nlh->nlmsg_seq, 4380 - NLM_F_MULTI, region); 4381 - if (err) { 4382 - mutex_unlock(&devlink->lock); 4383 - goto out; 4384 - } 4385 - idx++; 4386 - } 4387 - mutex_unlock(&devlink->lock); 4263 + err = devlink_nl_cmd_region_get_devlink_dumpit(msg, cb, devlink, 4264 + &idx, start); 4265 + if (err) 4266 + goto out; 4388 4267 } 4389 4268 out: 4390 4269 mutex_unlock(&devlink_mutex); ··· 4382 4291 { 4383 4292 struct devlink *devlink = info->user_ptr[0]; 4384 4293 struct devlink_snapshot *snapshot; 4294 + struct devlink_port *port = NULL; 4385 4295 struct devlink_region *region; 4386 4296 const char *region_name; 4297 + unsigned int index; 4387 4298 u32 snapshot_id; 4388 4299 4389 4300 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] || ··· 4395 4302 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]); 4396 4303 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]); 4397 4304 4398 - region = devlink_region_get_by_name(devlink, region_name); 4305 + if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) { 4306 + index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 4307 + 4308 + port = devlink_port_get_by_index(devlink, index); 4309 + if (!port) 4310 + return -ENODEV; 4311 + } 4312 + 4313 + if (port) 4314 + region = devlink_port_region_get_by_name(port, region_name); 4315 + else 4316 + region = devlink_region_get_by_name(devlink, region_name); 4317 + 4399 4318 if (!region) 4400 4319 return -EINVAL; 4401 4320 ··· 4424 4319 { 4425 4320 struct devlink *devlink = info->user_ptr[0]; 4426 4321 struct devlink_snapshot *snapshot; 4322 + struct devlink_port *port = NULL; 4427 4323 struct nlattr *snapshot_id_attr; 4428 4324 struct devlink_region *region; 4429 4325 const char *region_name; 4326 + unsigned int index; 4430 4327 u32 snapshot_id; 4431 4328 u8 *data; 4432 4329 int err; ··· 4439 4332 } 4440 4333 4441 4334 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]); 4442 - region = devlink_region_get_by_name(devlink, region_name); 4335 + 4336 + if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) { 4337 + index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 4338 + 4339 + port = devlink_port_get_by_index(devlink, index); 4340 + if (!port) 4341 + return -ENODEV; 4342 + } 4343 + 4344 + if (port) 4345 + region = devlink_port_region_get_by_name(port, region_name); 4346 + else 4347 + region = devlink_region_get_by_name(devlink, region_name); 4348 + 4443 4349 if (!region) { 4444 4350 NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not exist"); 4445 4351 return -EINVAL; ··· 4488 4368 } 4489 4369 } 4490 4370 4491 - err = region->ops->snapshot(devlink, region->ops, info->extack, &data); 4371 + if (port) 4372 + err = region->port_ops->snapshot(port, region->port_ops, 4373 + info->extack, &data); 4374 + else 4375 + err = region->ops->snapshot(devlink, region->ops, 4376 + info->extack, &data); 4492 4377 if (err) 4493 4378 goto err_snapshot_capture; 4494 4379 ··· 4615 4490 const struct genl_dumpit_info *info = genl_dumpit_info(cb); 4616 4491 u64 ret_offset, start_offset, end_offset = U64_MAX; 4617 4492 struct nlattr **attrs = info->attrs; 4493 + struct devlink_port *port = NULL; 4618 4494 struct devlink_region *region; 4619 4495 struct nlattr *chunks_attr; 4620 4496 const char *region_name; 4621 4497 struct devlink *devlink; 4498 + unsigned int index; 4622 4499 void *hdr; 4623 4500 int err; 4624 4501 ··· 4641 4514 goto out_unlock; 4642 4515 } 4643 4516 4517 + if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) { 4518 + index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); 4519 + 4520 + port = devlink_port_get_by_index(devlink, index); 4521 + if (!port) 4522 + return -ENODEV; 4523 + } 4524 + 4644 4525 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]); 4645 - region = devlink_region_get_by_name(devlink, region_name); 4526 + 4527 + if (port) 4528 + region = devlink_port_region_get_by_name(port, region_name); 4529 + else 4530 + region = devlink_region_get_by_name(devlink, region_name); 4531 + 4646 4532 if (!region) { 4647 4533 err = -EINVAL; 4648 4534 goto out_unlock; ··· 4691 4551 err = devlink_nl_put_handle(skb, devlink); 4692 4552 if (err) 4693 4553 goto nla_put_failure; 4554 + 4555 + if (region->port) 4556 + if (nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX, 4557 + region->port->index)) 4558 + goto nla_put_failure; 4694 4559 4695 4560 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name); 4696 4561 if (err) ··· 7757 7612 { 7758 7613 /* Ignore CPU and DSA flavours. */ 7759 7614 return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU && 7760 - devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA; 7615 + devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA && 7616 + devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_UNUSED; 7761 7617 } 7762 7618 7763 7619 #define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600) ··· 7811 7665 mutex_init(&devlink_port->reporters_lock); 7812 7666 list_add_tail(&devlink_port->list, &devlink->port_list); 7813 7667 INIT_LIST_HEAD(&devlink_port->param_list); 7668 + INIT_LIST_HEAD(&devlink_port->region_list); 7814 7669 mutex_unlock(&devlink->lock); 7815 7670 INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn); 7816 7671 devlink_port_type_warn_schedule(devlink_port); ··· 7835 7688 list_del(&devlink_port->list); 7836 7689 mutex_unlock(&devlink->lock); 7837 7690 WARN_ON(!list_empty(&devlink_port->reporter_list)); 7691 + WARN_ON(!list_empty(&devlink_port->region_list)); 7838 7692 mutex_destroy(&devlink_port->reporters_lock); 7839 7693 } 7840 7694 EXPORT_SYMBOL_GPL(devlink_port_unregister); ··· 8045 7897 break; 8046 7898 case DEVLINK_PORT_FLAVOUR_CPU: 8047 7899 case DEVLINK_PORT_FLAVOUR_DSA: 7900 + case DEVLINK_PORT_FLAVOUR_UNUSED: 8048 7901 /* As CPU and DSA ports do not have a netdevice associated 8049 7902 * case should not ever happen. 8050 7903 */ ··· 8914 8765 return ERR_PTR(err); 8915 8766 } 8916 8767 EXPORT_SYMBOL_GPL(devlink_region_create); 8768 + 8769 + /** 8770 + * devlink_port_region_create - create a new address region for a port 8771 + * 8772 + * @port: devlink port 8773 + * @ops: region operations and name 8774 + * @region_max_snapshots: Maximum supported number of snapshots for region 8775 + * @region_size: size of region 8776 + */ 8777 + struct devlink_region * 8778 + devlink_port_region_create(struct devlink_port *port, 8779 + const struct devlink_port_region_ops *ops, 8780 + u32 region_max_snapshots, u64 region_size) 8781 + { 8782 + struct devlink *devlink = port->devlink; 8783 + struct devlink_region *region; 8784 + int err = 0; 8785 + 8786 + if (WARN_ON(!ops) || WARN_ON(!ops->destructor)) 8787 + return ERR_PTR(-EINVAL); 8788 + 8789 + mutex_lock(&devlink->lock); 8790 + 8791 + if (devlink_port_region_get_by_name(port, ops->name)) { 8792 + err = -EEXIST; 8793 + goto unlock; 8794 + } 8795 + 8796 + region = kzalloc(sizeof(*region), GFP_KERNEL); 8797 + if (!region) { 8798 + err = -ENOMEM; 8799 + goto unlock; 8800 + } 8801 + 8802 + region->devlink = devlink; 8803 + region->port = port; 8804 + region->max_snapshots = region_max_snapshots; 8805 + region->port_ops = ops; 8806 + region->size = region_size; 8807 + INIT_LIST_HEAD(&region->snapshot_list); 8808 + list_add_tail(&region->list, &port->region_list); 8809 + devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW); 8810 + 8811 + mutex_unlock(&devlink->lock); 8812 + return region; 8813 + 8814 + unlock: 8815 + mutex_unlock(&devlink->lock); 8816 + return ERR_PTR(err); 8817 + } 8818 + EXPORT_SYMBOL_GPL(devlink_port_region_create); 8917 8819 8918 8820 /** 8919 8821 * devlink_region_destroy - destroy address region
+14
net/dsa/dsa.c
··· 423 423 } 424 424 EXPORT_SYMBOL_GPL(dsa_devlink_region_create); 425 425 426 + struct devlink_region * 427 + dsa_devlink_port_region_create(struct dsa_switch *ds, 428 + int port, 429 + const struct devlink_port_region_ops *ops, 430 + u32 region_max_snapshots, u64 region_size) 431 + { 432 + struct dsa_port *dp = dsa_to_port(ds, port); 433 + 434 + return devlink_port_region_create(&dp->devlink_port, ops, 435 + region_max_snapshots, 436 + region_size); 437 + } 438 + EXPORT_SYMBOL_GPL(dsa_devlink_port_region_create); 439 + 426 440 void dsa_devlink_region_destroy(struct devlink_region *region) 427 441 { 428 442 devlink_region_destroy(region);
+72 -43
net/dsa/dsa2.c
··· 251 251 252 252 static int dsa_port_setup(struct dsa_port *dp) 253 253 { 254 - struct dsa_switch *ds = dp->ds; 255 - struct dsa_switch_tree *dst = ds->dst; 256 - const unsigned char *id = (const unsigned char *)&dst->index; 257 - const unsigned char len = sizeof(dst->index); 258 254 struct devlink_port *dlp = &dp->devlink_port; 259 255 bool dsa_port_link_registered = false; 260 - bool devlink_port_registered = false; 261 - struct devlink_port_attrs attrs = {}; 262 - struct devlink *dl = ds->devlink; 263 256 bool dsa_port_enabled = false; 264 257 int err = 0; 265 - 266 - attrs.phys.port_number = dp->index; 267 - memcpy(attrs.switch_id.id, id, len); 268 - attrs.switch_id.id_len = len; 269 258 270 259 if (dp->setup) 271 260 return 0; ··· 264 275 dsa_port_disable(dp); 265 276 break; 266 277 case DSA_PORT_TYPE_CPU: 267 - memset(dlp, 0, sizeof(*dlp)); 268 - attrs.flavour = DEVLINK_PORT_FLAVOUR_CPU; 269 - devlink_port_attrs_set(dlp, &attrs); 270 - err = devlink_port_register(dl, dlp, dp->index); 271 - if (err) 272 - break; 273 - devlink_port_registered = true; 274 - 275 278 err = dsa_port_link_register_of(dp); 276 279 if (err) 277 280 break; ··· 276 295 277 296 break; 278 297 case DSA_PORT_TYPE_DSA: 279 - memset(dlp, 0, sizeof(*dlp)); 280 - attrs.flavour = DEVLINK_PORT_FLAVOUR_DSA; 281 - devlink_port_attrs_set(dlp, &attrs); 282 - err = devlink_port_register(dl, dlp, dp->index); 283 - if (err) 284 - break; 285 - devlink_port_registered = true; 286 - 287 298 err = dsa_port_link_register_of(dp); 288 299 if (err) 289 300 break; ··· 288 315 289 316 break; 290 317 case DSA_PORT_TYPE_USER: 291 - memset(dlp, 0, sizeof(*dlp)); 292 - attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 293 - devlink_port_attrs_set(dlp, &attrs); 294 - err = devlink_port_register(dl, dlp, dp->index); 295 - if (err) 296 - break; 297 - devlink_port_registered = true; 298 - 299 318 dp->mac = of_get_mac_address(dp->dn); 300 319 err = dsa_slave_create(dp); 301 320 if (err) ··· 301 336 dsa_port_disable(dp); 302 337 if (err && dsa_port_link_registered) 303 338 dsa_port_link_unregister_of(dp); 304 - if (err && devlink_port_registered) 305 - devlink_port_unregister(dlp); 306 339 if (err) 307 340 return err; 308 341 ··· 309 346 return 0; 310 347 } 311 348 312 - static void dsa_port_teardown(struct dsa_port *dp) 349 + static int dsa_port_devlink_setup(struct dsa_port *dp) 313 350 { 314 351 struct devlink_port *dlp = &dp->devlink_port; 352 + struct dsa_switch_tree *dst = dp->ds->dst; 353 + struct devlink_port_attrs attrs = {}; 354 + struct devlink *dl = dp->ds->devlink; 355 + const unsigned char *id; 356 + unsigned char len; 357 + int err; 315 358 359 + id = (const unsigned char *)&dst->index; 360 + len = sizeof(dst->index); 361 + 362 + attrs.phys.port_number = dp->index; 363 + memcpy(attrs.switch_id.id, id, len); 364 + attrs.switch_id.id_len = len; 365 + memset(dlp, 0, sizeof(*dlp)); 366 + 367 + switch (dp->type) { 368 + case DSA_PORT_TYPE_UNUSED: 369 + attrs.flavour = DEVLINK_PORT_FLAVOUR_UNUSED; 370 + break; 371 + case DSA_PORT_TYPE_CPU: 372 + attrs.flavour = DEVLINK_PORT_FLAVOUR_CPU; 373 + break; 374 + case DSA_PORT_TYPE_DSA: 375 + attrs.flavour = DEVLINK_PORT_FLAVOUR_DSA; 376 + break; 377 + case DSA_PORT_TYPE_USER: 378 + attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 379 + break; 380 + } 381 + 382 + devlink_port_attrs_set(dlp, &attrs); 383 + err = devlink_port_register(dl, dlp, dp->index); 384 + 385 + if (!err) 386 + dp->devlink_port_setup = true; 387 + 388 + return err; 389 + } 390 + 391 + static void dsa_port_teardown(struct dsa_port *dp) 392 + { 316 393 if (!dp->setup) 317 394 return; 318 395 ··· 362 359 case DSA_PORT_TYPE_CPU: 363 360 dsa_port_disable(dp); 364 361 dsa_tag_driver_put(dp->tag_ops); 365 - devlink_port_unregister(dlp); 366 362 dsa_port_link_unregister_of(dp); 367 363 break; 368 364 case DSA_PORT_TYPE_DSA: 369 365 dsa_port_disable(dp); 370 - devlink_port_unregister(dlp); 371 366 dsa_port_link_unregister_of(dp); 372 367 break; 373 368 case DSA_PORT_TYPE_USER: 374 - devlink_port_unregister(dlp); 375 369 if (dp->slave) { 376 370 dsa_slave_destroy(dp->slave); 377 371 dp->slave = NULL; ··· 377 377 } 378 378 379 379 dp->setup = false; 380 + } 381 + 382 + static void dsa_port_devlink_teardown(struct dsa_port *dp) 383 + { 384 + struct devlink_port *dlp = &dp->devlink_port; 385 + 386 + if (dp->devlink_port_setup) 387 + devlink_port_unregister(dlp); 388 + dp->devlink_port_setup = false; 380 389 } 381 390 382 391 static int dsa_devlink_info_get(struct devlink *dl, ··· 407 398 static int dsa_switch_setup(struct dsa_switch *ds) 408 399 { 409 400 struct dsa_devlink_priv *dl_priv; 401 + struct dsa_port *dp; 410 402 int err; 411 403 412 404 if (ds->setup) ··· 433 423 if (err) 434 424 goto free_devlink; 435 425 426 + /* Setup devlink port instances now, so that the switch 427 + * setup() can register regions etc, against the ports 428 + */ 429 + list_for_each_entry(dp, &ds->dst->ports, list) { 430 + if (dp->ds == ds) { 431 + err = dsa_port_devlink_setup(dp); 432 + if (err) 433 + goto unregister_devlink_ports; 434 + } 435 + } 436 + 436 437 err = dsa_switch_register_notifier(ds); 437 438 if (err) 438 - goto unregister_devlink; 439 + goto unregister_devlink_ports; 439 440 440 441 err = ds->ops->setup(ds); 441 442 if (err < 0) ··· 474 453 475 454 unregister_notifier: 476 455 dsa_switch_unregister_notifier(ds); 477 - unregister_devlink: 456 + unregister_devlink_ports: 457 + list_for_each_entry(dp, &ds->dst->ports, list) 458 + if (dp->ds == ds) 459 + dsa_port_devlink_teardown(dp); 478 460 devlink_unregister(ds->devlink); 479 461 free_devlink: 480 462 devlink_free(ds->devlink); ··· 488 464 489 465 static void dsa_switch_teardown(struct dsa_switch *ds) 490 466 { 467 + struct dsa_port *dp; 468 + 491 469 if (!ds->setup) 492 470 return; 493 471 ··· 502 476 ds->ops->teardown(ds); 503 477 504 478 if (ds->devlink) { 479 + list_for_each_entry(dp, &ds->dst->ports, list) 480 + if (dp->ds == ds) 481 + dsa_port_devlink_teardown(dp); 505 482 devlink_unregister(ds->devlink); 506 483 devlink_free(ds->devlink); 507 484 ds->devlink = NULL;