diff options
author | Alexandre Bounine <alexandre.bounine@idt.com> | 2016-03-22 17:26:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-22 18:36:02 -0400 |
commit | b7dfca8bd446721cbc23f4a7cf3c407eb42175dc (patch) | |
tree | 3d2c704ff469f68a49599cbb6cc84dcb6a660d24 | |
parent | 34ed2ebb65b0aa6a82206686870aaaddc12b2271 (diff) |
rapidio/rionet: add mport removal handling
Add handling of a local mport device removal.
RIONET driver registers itself as class interface that supports only
removal notification, 'add_device' callback is not provided because
RIONET network device can be initialized only after enumeration is
completed and the existing method (using remote peer addition) satisfies
this condition.
Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Cc: Matt Porter <mporter@kernel.crashing.org>
Cc: Aurelien Jacquiot <a-jacquiot@ti.com>
Cc: Andre van Herk <andre.van.herk@prodrive-technologies.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/net/rionet.c | 70 |
1 files changed, 44 insertions, 26 deletions
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index c15d9581dd56..9cfe6aeac84e 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c | |||
@@ -676,6 +676,34 @@ static int rionet_shutdown(struct notifier_block *nb, unsigned long code, | |||
676 | return NOTIFY_DONE; | 676 | return NOTIFY_DONE; |
677 | } | 677 | } |
678 | 678 | ||
679 | static void rionet_remove_mport(struct device *dev, | ||
680 | struct class_interface *class_intf) | ||
681 | { | ||
682 | struct rio_mport *mport = to_rio_mport(dev); | ||
683 | struct net_device *ndev; | ||
684 | int id = mport->id; | ||
685 | |||
686 | pr_debug("%s %s\n", __func__, mport->name); | ||
687 | |||
688 | WARN(nets[id].nact, "%s called when connected to %d peers\n", | ||
689 | __func__, nets[id].nact); | ||
690 | WARN(!nets[id].ndev, "%s called for mport without NDEV\n", | ||
691 | __func__); | ||
692 | |||
693 | if (nets[id].ndev) { | ||
694 | ndev = nets[id].ndev; | ||
695 | netif_stop_queue(ndev); | ||
696 | unregister_netdev(ndev); | ||
697 | |||
698 | free_pages((unsigned long)nets[id].active, | ||
699 | get_order(sizeof(void *) * | ||
700 | RIO_MAX_ROUTE_ENTRIES(mport->sys_size))); | ||
701 | nets[id].active = NULL; | ||
702 | free_netdev(ndev); | ||
703 | nets[id].ndev = NULL; | ||
704 | } | ||
705 | } | ||
706 | |||
679 | #ifdef MODULE | 707 | #ifdef MODULE |
680 | static struct rio_device_id rionet_id_table[] = { | 708 | static struct rio_device_id rionet_id_table[] = { |
681 | {RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)}, | 709 | {RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)}, |
@@ -696,6 +724,13 @@ static struct notifier_block rionet_notifier = { | |||
696 | .notifier_call = rionet_shutdown, | 724 | .notifier_call = rionet_shutdown, |
697 | }; | 725 | }; |
698 | 726 | ||
727 | /* the rio_mport_interface is used to handle local mport devices */ | ||
728 | static struct class_interface rio_mport_interface __refdata = { | ||
729 | .class = &rio_mport_class, | ||
730 | .add_dev = NULL, | ||
731 | .remove_dev = rionet_remove_mport, | ||
732 | }; | ||
733 | |||
699 | static int __init rionet_init(void) | 734 | static int __init rionet_init(void) |
700 | { | 735 | { |
701 | int ret; | 736 | int ret; |
@@ -706,39 +741,22 @@ static int __init rionet_init(void) | |||
706 | DRV_NAME, ret); | 741 | DRV_NAME, ret); |
707 | return ret; | 742 | return ret; |
708 | } | 743 | } |
744 | |||
745 | ret = class_interface_register(&rio_mport_interface); | ||
746 | if (ret) { | ||
747 | pr_err("%s: class_interface_register error: %d\n", | ||
748 | DRV_NAME, ret); | ||
749 | return ret; | ||
750 | } | ||
751 | |||
709 | return subsys_interface_register(&rionet_interface); | 752 | return subsys_interface_register(&rionet_interface); |
710 | } | 753 | } |
711 | 754 | ||
712 | static void __exit rionet_exit(void) | 755 | static void __exit rionet_exit(void) |
713 | { | 756 | { |
714 | struct rionet_private *rnet; | ||
715 | struct net_device *ndev; | ||
716 | struct rionet_peer *peer, *tmp; | ||
717 | int i; | ||
718 | |||
719 | for (i = 0; i < RIONET_MAX_NETS; i++) { | ||
720 | if (nets[i].ndev != NULL) { | ||
721 | ndev = nets[i].ndev; | ||
722 | rnet = netdev_priv(ndev); | ||
723 | unregister_netdev(ndev); | ||
724 | |||
725 | list_for_each_entry_safe(peer, | ||
726 | tmp, &nets[i].peers, node) { | ||
727 | list_del(&peer->node); | ||
728 | kfree(peer); | ||
729 | } | ||
730 | |||
731 | free_pages((unsigned long)nets[i].active, | ||
732 | get_order(sizeof(void *) * | ||
733 | RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size))); | ||
734 | nets[i].active = NULL; | ||
735 | |||
736 | free_netdev(ndev); | ||
737 | } | ||
738 | } | ||
739 | |||
740 | unregister_reboot_notifier(&rionet_notifier); | 757 | unregister_reboot_notifier(&rionet_notifier); |
741 | subsys_interface_unregister(&rionet_interface); | 758 | subsys_interface_unregister(&rionet_interface); |
759 | class_interface_unregister(&rio_mport_interface); | ||
742 | } | 760 | } |
743 | 761 | ||
744 | late_initcall(rionet_init); | 762 | late_initcall(rionet_init); |