diff options
-rw-r--r-- | drivers/net/cnic.c | 56 |
1 files changed, 42 insertions, 14 deletions
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index e8f2836b6301..3f923a78e22e 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c | |||
@@ -60,6 +60,7 @@ MODULE_LICENSE("GPL"); | |||
60 | MODULE_VERSION(CNIC_MODULE_VERSION); | 60 | MODULE_VERSION(CNIC_MODULE_VERSION); |
61 | 61 | ||
62 | static LIST_HEAD(cnic_dev_list); | 62 | static LIST_HEAD(cnic_dev_list); |
63 | static LIST_HEAD(cnic_udev_list); | ||
63 | static DEFINE_RWLOCK(cnic_dev_lock); | 64 | static DEFINE_RWLOCK(cnic_dev_lock); |
64 | static DEFINE_MUTEX(cnic_lock); | 65 | static DEFINE_MUTEX(cnic_lock); |
65 | 66 | ||
@@ -101,13 +102,14 @@ static int cnic_uio_open(struct uio_info *uinfo, struct inode *inode) | |||
101 | rtnl_lock(); | 102 | rtnl_lock(); |
102 | dev = udev->dev; | 103 | dev = udev->dev; |
103 | 104 | ||
104 | if (!test_bit(CNIC_F_CNIC_UP, &dev->flags)) { | 105 | if (!dev || !test_bit(CNIC_F_CNIC_UP, &dev->flags)) { |
105 | rtnl_unlock(); | 106 | rtnl_unlock(); |
106 | return -ENODEV; | 107 | return -ENODEV; |
107 | } | 108 | } |
108 | 109 | ||
109 | udev->uio_dev = iminor(inode); | 110 | udev->uio_dev = iminor(inode); |
110 | 111 | ||
112 | cnic_shutdown_rings(dev); | ||
111 | cnic_init_rings(dev); | 113 | cnic_init_rings(dev); |
112 | rtnl_unlock(); | 114 | rtnl_unlock(); |
113 | 115 | ||
@@ -117,9 +119,6 @@ static int cnic_uio_open(struct uio_info *uinfo, struct inode *inode) | |||
117 | static int cnic_uio_close(struct uio_info *uinfo, struct inode *inode) | 119 | static int cnic_uio_close(struct uio_info *uinfo, struct inode *inode) |
118 | { | 120 | { |
119 | struct cnic_uio_dev *udev = uinfo->priv; | 121 | struct cnic_uio_dev *udev = uinfo->priv; |
120 | struct cnic_dev *dev = udev->dev; | ||
121 | |||
122 | cnic_shutdown_rings(dev); | ||
123 | 122 | ||
124 | udev->uio_dev = -1; | 123 | udev->uio_dev = -1; |
125 | return 0; | 124 | return 0; |
@@ -787,6 +786,9 @@ static void __cnic_free_uio(struct cnic_uio_dev *udev) | |||
787 | udev->l2_ring, udev->l2_ring_map); | 786 | udev->l2_ring, udev->l2_ring_map); |
788 | udev->l2_ring = NULL; | 787 | udev->l2_ring = NULL; |
789 | } | 788 | } |
789 | |||
790 | pci_dev_put(udev->pdev); | ||
791 | kfree(udev); | ||
790 | } | 792 | } |
791 | 793 | ||
792 | static void cnic_free_uio(struct cnic_uio_dev *udev) | 794 | static void cnic_free_uio(struct cnic_uio_dev *udev) |
@@ -794,6 +796,9 @@ static void cnic_free_uio(struct cnic_uio_dev *udev) | |||
794 | if (!udev) | 796 | if (!udev) |
795 | return; | 797 | return; |
796 | 798 | ||
799 | write_lock(&cnic_dev_lock); | ||
800 | list_del_init(&udev->list); | ||
801 | write_unlock(&cnic_dev_lock); | ||
797 | __cnic_free_uio(udev); | 802 | __cnic_free_uio(udev); |
798 | } | 803 | } |
799 | 804 | ||
@@ -801,14 +806,9 @@ static void cnic_free_resc(struct cnic_dev *dev) | |||
801 | { | 806 | { |
802 | struct cnic_local *cp = dev->cnic_priv; | 807 | struct cnic_local *cp = dev->cnic_priv; |
803 | struct cnic_uio_dev *udev = cp->udev; | 808 | struct cnic_uio_dev *udev = cp->udev; |
804 | int i = 0; | ||
805 | 809 | ||
806 | if (udev) { | 810 | if (udev) { |
807 | while (udev->uio_dev != -1 && i < 15) { | 811 | udev->dev = NULL; |
808 | msleep(100); | ||
809 | i++; | ||
810 | } | ||
811 | cnic_free_uio(udev); | ||
812 | cp->udev = NULL; | 812 | cp->udev = NULL; |
813 | } | 813 | } |
814 | 814 | ||
@@ -916,6 +916,17 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages) | |||
916 | struct cnic_local *cp = dev->cnic_priv; | 916 | struct cnic_local *cp = dev->cnic_priv; |
917 | struct cnic_uio_dev *udev; | 917 | struct cnic_uio_dev *udev; |
918 | 918 | ||
919 | read_lock(&cnic_dev_lock); | ||
920 | list_for_each_entry(udev, &cnic_udev_list, list) { | ||
921 | if (udev->pdev == dev->pcidev) { | ||
922 | udev->dev = dev; | ||
923 | cp->udev = udev; | ||
924 | read_unlock(&cnic_dev_lock); | ||
925 | return 0; | ||
926 | } | ||
927 | } | ||
928 | read_unlock(&cnic_dev_lock); | ||
929 | |||
919 | udev = kzalloc(sizeof(struct cnic_uio_dev), GFP_ATOMIC); | 930 | udev = kzalloc(sizeof(struct cnic_uio_dev), GFP_ATOMIC); |
920 | if (!udev) | 931 | if (!udev) |
921 | return -ENOMEM; | 932 | return -ENOMEM; |
@@ -939,6 +950,12 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages) | |||
939 | if (!udev->l2_buf) | 950 | if (!udev->l2_buf) |
940 | return -ENOMEM; | 951 | return -ENOMEM; |
941 | 952 | ||
953 | write_lock(&cnic_dev_lock); | ||
954 | list_add(&udev->list, &cnic_udev_list); | ||
955 | write_unlock(&cnic_dev_lock); | ||
956 | |||
957 | pci_dev_get(udev->pdev); | ||
958 | |||
942 | cp->udev = udev; | 959 | cp->udev = udev; |
943 | 960 | ||
944 | return 0; | 961 | return 0; |
@@ -954,8 +971,6 @@ static int cnic_init_uio(struct cnic_dev *dev) | |||
954 | if (!udev) | 971 | if (!udev) |
955 | return -ENOMEM; | 972 | return -ENOMEM; |
956 | 973 | ||
957 | udev->uio_dev = -1; | ||
958 | |||
959 | uinfo = &udev->cnic_uinfo; | 974 | uinfo = &udev->cnic_uinfo; |
960 | 975 | ||
961 | uinfo->mem[0].addr = dev->netdev->base_addr; | 976 | uinfo->mem[0].addr = dev->netdev->base_addr; |
@@ -996,9 +1011,15 @@ static int cnic_init_uio(struct cnic_dev *dev) | |||
996 | uinfo->open = cnic_uio_open; | 1011 | uinfo->open = cnic_uio_open; |
997 | uinfo->release = cnic_uio_close; | 1012 | uinfo->release = cnic_uio_close; |
998 | 1013 | ||
999 | uinfo->priv = udev; | 1014 | if (udev->uio_dev == -1) { |
1015 | if (!uinfo->priv) { | ||
1016 | uinfo->priv = udev; | ||
1000 | 1017 | ||
1001 | ret = uio_register_device(&udev->pdev->dev, uinfo); | 1018 | ret = uio_register_device(&udev->pdev->dev, uinfo); |
1019 | } | ||
1020 | } else { | ||
1021 | cnic_init_rings(dev); | ||
1022 | } | ||
1002 | 1023 | ||
1003 | return ret; | 1024 | return ret; |
1004 | } | 1025 | } |
@@ -4559,6 +4580,7 @@ static void cnic_stop_hw(struct cnic_dev *dev) | |||
4559 | msleep(100); | 4580 | msleep(100); |
4560 | i++; | 4581 | i++; |
4561 | } | 4582 | } |
4583 | cnic_shutdown_rings(dev); | ||
4562 | clear_bit(CNIC_F_CNIC_UP, &dev->flags); | 4584 | clear_bit(CNIC_F_CNIC_UP, &dev->flags); |
4563 | rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], NULL); | 4585 | rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], NULL); |
4564 | synchronize_rcu(); | 4586 | synchronize_rcu(); |
@@ -4834,6 +4856,7 @@ static struct notifier_block cnic_netdev_notifier = { | |||
4834 | static void cnic_release(void) | 4856 | static void cnic_release(void) |
4835 | { | 4857 | { |
4836 | struct cnic_dev *dev; | 4858 | struct cnic_dev *dev; |
4859 | struct cnic_uio_dev *udev; | ||
4837 | 4860 | ||
4838 | while (!list_empty(&cnic_dev_list)) { | 4861 | while (!list_empty(&cnic_dev_list)) { |
4839 | dev = list_entry(cnic_dev_list.next, struct cnic_dev, list); | 4862 | dev = list_entry(cnic_dev_list.next, struct cnic_dev, list); |
@@ -4847,6 +4870,11 @@ static void cnic_release(void) | |||
4847 | list_del_init(&dev->list); | 4870 | list_del_init(&dev->list); |
4848 | cnic_free_dev(dev); | 4871 | cnic_free_dev(dev); |
4849 | } | 4872 | } |
4873 | while (!list_empty(&cnic_udev_list)) { | ||
4874 | udev = list_entry(cnic_udev_list.next, struct cnic_uio_dev, | ||
4875 | list); | ||
4876 | cnic_free_uio(udev); | ||
4877 | } | ||
4850 | } | 4878 | } |
4851 | 4879 | ||
4852 | static int __init cnic_init(void) | 4880 | static int __init cnic_init(void) |