aboutsummaryrefslogtreecommitdiffstats
path: root/net/switchdev/switchdev.c
diff options
context:
space:
mode:
authorJiri Pirko <jiri@mellanox.com>2015-10-14 13:40:52 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-15 09:09:49 -0400
commit4d429c5ddc5128fccd3048059ae26bb39f0d8284 (patch)
tree9e0b41720f38dd4a716b42545711067d24f1838b /net/switchdev/switchdev.c
parent850d0cbc9171f63f0418afffb0d89a84db927851 (diff)
switchdev: introduce possibility to defer obj_add/del
Similar to the attr usecase, the caller knows if he is holding RTNL and is in atomic section. So let the called to decide the correct call variant. This allows drivers to sleep inside their ops and wait for hw to get the operation status. Then the status is propagated into switchdev core. This avoids silent errors in drivers. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/switchdev/switchdev.c')
-rw-r--r--net/switchdev/switchdev.c100
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/** 365static 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 */
378int 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}
421EXPORT_SYMBOL_GPL(switchdev_port_obj_add); 408
409static 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
421static 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 */
430int switchdev_port_obj_del(struct net_device *dev, 442int 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}
450EXPORT_SYMBOL_GPL(switchdev_port_obj_add);
451
452static 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
477static 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
489static 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 */
506int 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}
454EXPORT_SYMBOL_GPL(switchdev_port_obj_del); 514EXPORT_SYMBOL_GPL(switchdev_port_obj_del);
455 515
456/** 516/**