diff options
Diffstat (limited to 'drivers/net/cnic.c')
| -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) |
