diff options
Diffstat (limited to 'net/switchdev/switchdev.c')
-rw-r--r-- | net/switchdev/switchdev.c | 100 |
1 files changed, 80 insertions, 20 deletions
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 5963d7ac1026..eac68c4e57ec 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c | |||
@@ -362,21 +362,8 @@ static int __switchdev_port_obj_add(struct net_device *dev, | |||
362 | return err; | 362 | return err; |
363 | } | 363 | } |
364 | 364 | ||
365 | /** | 365 | static int switchdev_port_obj_add_now(struct net_device *dev, |
366 | * switchdev_port_obj_add - Add port object | 366 | const struct switchdev_obj *obj) |
367 | * | ||
368 | * @dev: port device | ||
369 | * @id: object ID | ||
370 | * @obj: object to add | ||
371 | * | ||
372 | * Use a 2-phase prepare-commit transaction model to ensure | ||
373 | * system is not left in a partially updated state due to | ||
374 | * failure from driver/device. | ||
375 | * | ||
376 | * rtnl_lock must be held. | ||
377 | */ | ||
378 | int switchdev_port_obj_add(struct net_device *dev, | ||
379 | const struct switchdev_obj *obj) | ||
380 | { | 367 | { |
381 | struct switchdev_trans trans; | 368 | struct switchdev_trans trans; |
382 | int err; | 369 | int err; |
@@ -418,18 +405,53 @@ int switchdev_port_obj_add(struct net_device *dev, | |||
418 | 405 | ||
419 | return err; | 406 | return err; |
420 | } | 407 | } |
421 | EXPORT_SYMBOL_GPL(switchdev_port_obj_add); | 408 | |
409 | static void switchdev_port_obj_add_deferred(struct net_device *dev, | ||
410 | const void *data) | ||
411 | { | ||
412 | const struct switchdev_obj *obj = data; | ||
413 | int err; | ||
414 | |||
415 | err = switchdev_port_obj_add_now(dev, obj); | ||
416 | if (err && err != -EOPNOTSUPP) | ||
417 | netdev_err(dev, "failed (err=%d) to add object (id=%d)\n", | ||
418 | err, obj->id); | ||
419 | } | ||
420 | |||
421 | static int switchdev_port_obj_add_defer(struct net_device *dev, | ||
422 | const struct switchdev_obj *obj) | ||
423 | { | ||
424 | return switchdev_deferred_enqueue(dev, obj, sizeof(*obj), | ||
425 | switchdev_port_obj_add_deferred); | ||
426 | } | ||
422 | 427 | ||
423 | /** | 428 | /** |
424 | * switchdev_port_obj_del - Delete port object | 429 | * switchdev_port_obj_add - Add port object |
425 | * | 430 | * |
426 | * @dev: port device | 431 | * @dev: port device |
427 | * @id: object ID | 432 | * @id: object ID |
428 | * @obj: object to delete | 433 | * @obj: object to add |
434 | * | ||
435 | * Use a 2-phase prepare-commit transaction model to ensure | ||
436 | * system is not left in a partially updated state due to | ||
437 | * failure from driver/device. | ||
438 | * | ||
439 | * rtnl_lock must be held and must not be in atomic section, | ||
440 | * in case SWITCHDEV_F_DEFER flag is not set. | ||
429 | */ | 441 | */ |
430 | int switchdev_port_obj_del(struct net_device *dev, | 442 | int switchdev_port_obj_add(struct net_device *dev, |
431 | const struct switchdev_obj *obj) | 443 | const struct switchdev_obj *obj) |
432 | { | 444 | { |
445 | if (obj->flags & SWITCHDEV_F_DEFER) | ||
446 | return switchdev_port_obj_add_defer(dev, obj); | ||
447 | ASSERT_RTNL(); | ||
448 | return switchdev_port_obj_add_now(dev, obj); | ||
449 | } | ||
450 | EXPORT_SYMBOL_GPL(switchdev_port_obj_add); | ||
451 | |||
452 | static int switchdev_port_obj_del_now(struct net_device *dev, | ||
453 | const struct switchdev_obj *obj) | ||
454 | { | ||
433 | const struct switchdev_ops *ops = dev->switchdev_ops; | 455 | const struct switchdev_ops *ops = dev->switchdev_ops; |
434 | struct net_device *lower_dev; | 456 | struct net_device *lower_dev; |
435 | struct list_head *iter; | 457 | struct list_head *iter; |
@@ -444,13 +466,51 @@ int switchdev_port_obj_del(struct net_device *dev, | |||
444 | */ | 466 | */ |
445 | 467 | ||
446 | netdev_for_each_lower_dev(dev, lower_dev, iter) { | 468 | netdev_for_each_lower_dev(dev, lower_dev, iter) { |
447 | err = switchdev_port_obj_del(lower_dev, obj); | 469 | err = switchdev_port_obj_del_now(lower_dev, obj); |
448 | if (err) | 470 | if (err) |
449 | break; | 471 | break; |
450 | } | 472 | } |
451 | 473 | ||
452 | return err; | 474 | return err; |
453 | } | 475 | } |
476 | |||
477 | static void switchdev_port_obj_del_deferred(struct net_device *dev, | ||
478 | const void *data) | ||
479 | { | ||
480 | const struct switchdev_obj *obj = data; | ||
481 | int err; | ||
482 | |||
483 | err = switchdev_port_obj_del_now(dev, obj); | ||
484 | if (err && err != -EOPNOTSUPP) | ||
485 | netdev_err(dev, "failed (err=%d) to del object (id=%d)\n", | ||
486 | err, obj->id); | ||
487 | } | ||
488 | |||
489 | static int switchdev_port_obj_del_defer(struct net_device *dev, | ||
490 | const struct switchdev_obj *obj) | ||
491 | { | ||
492 | return switchdev_deferred_enqueue(dev, obj, sizeof(*obj), | ||
493 | switchdev_port_obj_del_deferred); | ||
494 | } | ||
495 | |||
496 | /** | ||
497 | * switchdev_port_obj_del - Delete port object | ||
498 | * | ||
499 | * @dev: port device | ||
500 | * @id: object ID | ||
501 | * @obj: object to delete | ||
502 | * | ||
503 | * rtnl_lock must be held and must not be in atomic section, | ||
504 | * in case SWITCHDEV_F_DEFER flag is not set. | ||
505 | */ | ||
506 | int switchdev_port_obj_del(struct net_device *dev, | ||
507 | const struct switchdev_obj *obj) | ||
508 | { | ||
509 | if (obj->flags & SWITCHDEV_F_DEFER) | ||
510 | return switchdev_port_obj_del_defer(dev, obj); | ||
511 | ASSERT_RTNL(); | ||
512 | return switchdev_port_obj_del_now(dev, obj); | ||
513 | } | ||
454 | EXPORT_SYMBOL_GPL(switchdev_port_obj_del); | 514 | EXPORT_SYMBOL_GPL(switchdev_port_obj_del); |
455 | 515 | ||
456 | /** | 516 | /** |