diff options
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 293 |
1 files changed, 167 insertions, 126 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index cdb78eefab67..f28c85d212ce 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -46,7 +46,10 @@ | |||
46 | 46 | ||
47 | #include "hyperv_net.h" | 47 | #include "hyperv_net.h" |
48 | 48 | ||
49 | #define RING_SIZE_MIN 64 | 49 | #define RING_SIZE_MIN 64 |
50 | #define RETRY_US_LO 5000 | ||
51 | #define RETRY_US_HI 10000 | ||
52 | #define RETRY_MAX 2000 /* >10 sec */ | ||
50 | 53 | ||
51 | #define LINKCHANGE_INT (2 * HZ) | 54 | #define LINKCHANGE_INT (2 * HZ) |
52 | #define VF_TAKEOVER_INT (HZ / 10) | 55 | #define VF_TAKEOVER_INT (HZ / 10) |
@@ -89,15 +92,20 @@ static void netvsc_change_rx_flags(struct net_device *net, int change) | |||
89 | static void netvsc_set_rx_mode(struct net_device *net) | 92 | static void netvsc_set_rx_mode(struct net_device *net) |
90 | { | 93 | { |
91 | struct net_device_context *ndev_ctx = netdev_priv(net); | 94 | struct net_device_context *ndev_ctx = netdev_priv(net); |
92 | struct net_device *vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); | 95 | struct net_device *vf_netdev; |
93 | struct netvsc_device *nvdev = rtnl_dereference(ndev_ctx->nvdev); | 96 | struct netvsc_device *nvdev; |
94 | 97 | ||
98 | rcu_read_lock(); | ||
99 | vf_netdev = rcu_dereference(ndev_ctx->vf_netdev); | ||
95 | if (vf_netdev) { | 100 | if (vf_netdev) { |
96 | dev_uc_sync(vf_netdev, net); | 101 | dev_uc_sync(vf_netdev, net); |
97 | dev_mc_sync(vf_netdev, net); | 102 | dev_mc_sync(vf_netdev, net); |
98 | } | 103 | } |
99 | 104 | ||
100 | rndis_filter_update(nvdev); | 105 | nvdev = rcu_dereference(ndev_ctx->nvdev); |
106 | if (nvdev) | ||
107 | rndis_filter_update(nvdev); | ||
108 | rcu_read_unlock(); | ||
101 | } | 109 | } |
102 | 110 | ||
103 | static int netvsc_open(struct net_device *net) | 111 | static int netvsc_open(struct net_device *net) |
@@ -118,10 +126,8 @@ static int netvsc_open(struct net_device *net) | |||
118 | } | 126 | } |
119 | 127 | ||
120 | rdev = nvdev->extension; | 128 | rdev = nvdev->extension; |
121 | if (!rdev->link_state) { | 129 | if (!rdev->link_state) |
122 | netif_carrier_on(net); | 130 | netif_carrier_on(net); |
123 | netif_tx_wake_all_queues(net); | ||
124 | } | ||
125 | 131 | ||
126 | if (vf_netdev) { | 132 | if (vf_netdev) { |
127 | /* Setting synthetic device up transparently sets | 133 | /* Setting synthetic device up transparently sets |
@@ -137,36 +143,25 @@ static int netvsc_open(struct net_device *net) | |||
137 | return 0; | 143 | return 0; |
138 | } | 144 | } |
139 | 145 | ||
140 | static int netvsc_close(struct net_device *net) | 146 | static int netvsc_wait_until_empty(struct netvsc_device *nvdev) |
141 | { | 147 | { |
142 | struct net_device_context *net_device_ctx = netdev_priv(net); | 148 | unsigned int retry = 0; |
143 | struct net_device *vf_netdev | 149 | int i; |
144 | = rtnl_dereference(net_device_ctx->vf_netdev); | ||
145 | struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); | ||
146 | int ret = 0; | ||
147 | u32 aread, i, msec = 10, retry = 0, retry_max = 20; | ||
148 | struct vmbus_channel *chn; | ||
149 | |||
150 | netif_tx_disable(net); | ||
151 | |||
152 | /* No need to close rndis filter if it is removed already */ | ||
153 | if (!nvdev) | ||
154 | goto out; | ||
155 | |||
156 | ret = rndis_filter_close(nvdev); | ||
157 | if (ret != 0) { | ||
158 | netdev_err(net, "unable to close device (ret %d).\n", ret); | ||
159 | return ret; | ||
160 | } | ||
161 | 150 | ||
162 | /* Ensure pending bytes in ring are read */ | 151 | /* Ensure pending bytes in ring are read */ |
163 | while (true) { | 152 | for (;;) { |
164 | aread = 0; | 153 | u32 aread = 0; |
154 | |||
165 | for (i = 0; i < nvdev->num_chn; i++) { | 155 | for (i = 0; i < nvdev->num_chn; i++) { |
166 | chn = nvdev->chan_table[i].channel; | 156 | struct vmbus_channel *chn |
157 | = nvdev->chan_table[i].channel; | ||
158 | |||
167 | if (!chn) | 159 | if (!chn) |
168 | continue; | 160 | continue; |
169 | 161 | ||
162 | /* make sure receive not running now */ | ||
163 | napi_synchronize(&nvdev->chan_table[i].napi); | ||
164 | |||
170 | aread = hv_get_bytes_to_read(&chn->inbound); | 165 | aread = hv_get_bytes_to_read(&chn->inbound); |
171 | if (aread) | 166 | if (aread) |
172 | break; | 167 | break; |
@@ -176,22 +171,40 @@ static int netvsc_close(struct net_device *net) | |||
176 | break; | 171 | break; |
177 | } | 172 | } |
178 | 173 | ||
179 | retry++; | 174 | if (aread == 0) |
180 | if (retry > retry_max || aread == 0) | 175 | return 0; |
181 | break; | ||
182 | 176 | ||
183 | msleep(msec); | 177 | if (++retry > RETRY_MAX) |
178 | return -ETIMEDOUT; | ||
184 | 179 | ||
185 | if (msec < 1000) | 180 | usleep_range(RETRY_US_LO, RETRY_US_HI); |
186 | msec *= 2; | ||
187 | } | 181 | } |
182 | } | ||
188 | 183 | ||
189 | if (aread) { | 184 | static int netvsc_close(struct net_device *net) |
190 | netdev_err(net, "Ring buffer not empty after closing rndis\n"); | 185 | { |
191 | ret = -ETIMEDOUT; | 186 | struct net_device_context *net_device_ctx = netdev_priv(net); |
187 | struct net_device *vf_netdev | ||
188 | = rtnl_dereference(net_device_ctx->vf_netdev); | ||
189 | struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); | ||
190 | int ret; | ||
191 | |||
192 | netif_tx_disable(net); | ||
193 | |||
194 | /* No need to close rndis filter if it is removed already */ | ||
195 | if (!nvdev) | ||
196 | return 0; | ||
197 | |||
198 | ret = rndis_filter_close(nvdev); | ||
199 | if (ret != 0) { | ||
200 | netdev_err(net, "unable to close device (ret %d).\n", ret); | ||
201 | return ret; | ||
192 | } | 202 | } |
193 | 203 | ||
194 | out: | 204 | ret = netvsc_wait_until_empty(nvdev); |
205 | if (ret) | ||
206 | netdev_err(net, "Ring buffer not empty after closing rndis\n"); | ||
207 | |||
195 | if (vf_netdev) | 208 | if (vf_netdev) |
196 | dev_close(vf_netdev); | 209 | dev_close(vf_netdev); |
197 | 210 | ||
@@ -840,16 +853,81 @@ static void netvsc_get_channels(struct net_device *net, | |||
840 | } | 853 | } |
841 | } | 854 | } |
842 | 855 | ||
856 | static int netvsc_detach(struct net_device *ndev, | ||
857 | struct netvsc_device *nvdev) | ||
858 | { | ||
859 | struct net_device_context *ndev_ctx = netdev_priv(ndev); | ||
860 | struct hv_device *hdev = ndev_ctx->device_ctx; | ||
861 | int ret; | ||
862 | |||
863 | /* Don't try continuing to try and setup sub channels */ | ||
864 | if (cancel_work_sync(&nvdev->subchan_work)) | ||
865 | nvdev->num_chn = 1; | ||
866 | |||
867 | /* If device was up (receiving) then shutdown */ | ||
868 | if (netif_running(ndev)) { | ||
869 | netif_tx_disable(ndev); | ||
870 | |||
871 | ret = rndis_filter_close(nvdev); | ||
872 | if (ret) { | ||
873 | netdev_err(ndev, | ||
874 | "unable to close device (ret %d).\n", ret); | ||
875 | return ret; | ||
876 | } | ||
877 | |||
878 | ret = netvsc_wait_until_empty(nvdev); | ||
879 | if (ret) { | ||
880 | netdev_err(ndev, | ||
881 | "Ring buffer not empty after closing rndis\n"); | ||
882 | return ret; | ||
883 | } | ||
884 | } | ||
885 | |||
886 | netif_device_detach(ndev); | ||
887 | |||
888 | rndis_filter_device_remove(hdev, nvdev); | ||
889 | |||
890 | return 0; | ||
891 | } | ||
892 | |||
893 | static int netvsc_attach(struct net_device *ndev, | ||
894 | struct netvsc_device_info *dev_info) | ||
895 | { | ||
896 | struct net_device_context *ndev_ctx = netdev_priv(ndev); | ||
897 | struct hv_device *hdev = ndev_ctx->device_ctx; | ||
898 | struct netvsc_device *nvdev; | ||
899 | struct rndis_device *rdev; | ||
900 | int ret; | ||
901 | |||
902 | nvdev = rndis_filter_device_add(hdev, dev_info); | ||
903 | if (IS_ERR(nvdev)) | ||
904 | return PTR_ERR(nvdev); | ||
905 | |||
906 | /* Note: enable and attach happen when sub-channels setup */ | ||
907 | |||
908 | netif_carrier_off(ndev); | ||
909 | |||
910 | if (netif_running(ndev)) { | ||
911 | ret = rndis_filter_open(nvdev); | ||
912 | if (ret) | ||
913 | return ret; | ||
914 | |||
915 | rdev = nvdev->extension; | ||
916 | if (!rdev->link_state) | ||
917 | netif_carrier_on(ndev); | ||
918 | } | ||
919 | |||
920 | return 0; | ||
921 | } | ||
922 | |||
843 | static int netvsc_set_channels(struct net_device *net, | 923 | static int netvsc_set_channels(struct net_device *net, |
844 | struct ethtool_channels *channels) | 924 | struct ethtool_channels *channels) |
845 | { | 925 | { |
846 | struct net_device_context *net_device_ctx = netdev_priv(net); | 926 | struct net_device_context *net_device_ctx = netdev_priv(net); |
847 | struct hv_device *dev = net_device_ctx->device_ctx; | ||
848 | struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); | 927 | struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); |
849 | unsigned int orig, count = channels->combined_count; | 928 | unsigned int orig, count = channels->combined_count; |
850 | struct netvsc_device_info device_info; | 929 | struct netvsc_device_info device_info; |
851 | bool was_opened; | 930 | int ret; |
852 | int ret = 0; | ||
853 | 931 | ||
854 | /* We do not support separate count for rx, tx, or other */ | 932 | /* We do not support separate count for rx, tx, or other */ |
855 | if (count == 0 || | 933 | if (count == 0 || |
@@ -866,9 +944,6 @@ static int netvsc_set_channels(struct net_device *net, | |||
866 | return -EINVAL; | 944 | return -EINVAL; |
867 | 945 | ||
868 | orig = nvdev->num_chn; | 946 | orig = nvdev->num_chn; |
869 | was_opened = rndis_filter_opened(nvdev); | ||
870 | if (was_opened) | ||
871 | rndis_filter_close(nvdev); | ||
872 | 947 | ||
873 | memset(&device_info, 0, sizeof(device_info)); | 948 | memset(&device_info, 0, sizeof(device_info)); |
874 | device_info.num_chn = count; | 949 | device_info.num_chn = count; |
@@ -877,28 +952,17 @@ static int netvsc_set_channels(struct net_device *net, | |||
877 | device_info.recv_sections = nvdev->recv_section_cnt; | 952 | device_info.recv_sections = nvdev->recv_section_cnt; |
878 | device_info.recv_section_size = nvdev->recv_section_size; | 953 | device_info.recv_section_size = nvdev->recv_section_size; |
879 | 954 | ||
880 | rndis_filter_device_remove(dev, nvdev); | 955 | ret = netvsc_detach(net, nvdev); |
956 | if (ret) | ||
957 | return ret; | ||
881 | 958 | ||
882 | nvdev = rndis_filter_device_add(dev, &device_info); | 959 | ret = netvsc_attach(net, &device_info); |
883 | if (IS_ERR(nvdev)) { | 960 | if (ret) { |
884 | ret = PTR_ERR(nvdev); | ||
885 | device_info.num_chn = orig; | 961 | device_info.num_chn = orig; |
886 | nvdev = rndis_filter_device_add(dev, &device_info); | 962 | if (netvsc_attach(net, &device_info)) |
887 | 963 | netdev_err(net, "restoring channel setting failed\n"); | |
888 | if (IS_ERR(nvdev)) { | ||
889 | netdev_err(net, "restoring channel setting failed: %ld\n", | ||
890 | PTR_ERR(nvdev)); | ||
891 | return ret; | ||
892 | } | ||
893 | } | 964 | } |
894 | 965 | ||
895 | if (was_opened) | ||
896 | rndis_filter_open(nvdev); | ||
897 | |||
898 | /* We may have missed link change notifications */ | ||
899 | net_device_ctx->last_reconfig = 0; | ||
900 | schedule_delayed_work(&net_device_ctx->dwork, 0); | ||
901 | |||
902 | return ret; | 966 | return ret; |
903 | } | 967 | } |
904 | 968 | ||
@@ -964,10 +1028,8 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) | |||
964 | struct net_device_context *ndevctx = netdev_priv(ndev); | 1028 | struct net_device_context *ndevctx = netdev_priv(ndev); |
965 | struct net_device *vf_netdev = rtnl_dereference(ndevctx->vf_netdev); | 1029 | struct net_device *vf_netdev = rtnl_dereference(ndevctx->vf_netdev); |
966 | struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev); | 1030 | struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev); |
967 | struct hv_device *hdev = ndevctx->device_ctx; | ||
968 | int orig_mtu = ndev->mtu; | 1031 | int orig_mtu = ndev->mtu; |
969 | struct netvsc_device_info device_info; | 1032 | struct netvsc_device_info device_info; |
970 | bool was_opened; | ||
971 | int ret = 0; | 1033 | int ret = 0; |
972 | 1034 | ||
973 | if (!nvdev || nvdev->destroy) | 1035 | if (!nvdev || nvdev->destroy) |
@@ -980,11 +1042,6 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) | |||
980 | return ret; | 1042 | return ret; |
981 | } | 1043 | } |
982 | 1044 | ||
983 | netif_device_detach(ndev); | ||
984 | was_opened = rndis_filter_opened(nvdev); | ||
985 | if (was_opened) | ||
986 | rndis_filter_close(nvdev); | ||
987 | |||
988 | memset(&device_info, 0, sizeof(device_info)); | 1045 | memset(&device_info, 0, sizeof(device_info)); |
989 | device_info.num_chn = nvdev->num_chn; | 1046 | device_info.num_chn = nvdev->num_chn; |
990 | device_info.send_sections = nvdev->send_section_cnt; | 1047 | device_info.send_sections = nvdev->send_section_cnt; |
@@ -992,35 +1049,27 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) | |||
992 | device_info.recv_sections = nvdev->recv_section_cnt; | 1049 | device_info.recv_sections = nvdev->recv_section_cnt; |
993 | device_info.recv_section_size = nvdev->recv_section_size; | 1050 | device_info.recv_section_size = nvdev->recv_section_size; |
994 | 1051 | ||
995 | rndis_filter_device_remove(hdev, nvdev); | 1052 | ret = netvsc_detach(ndev, nvdev); |
1053 | if (ret) | ||
1054 | goto rollback_vf; | ||
996 | 1055 | ||
997 | ndev->mtu = mtu; | 1056 | ndev->mtu = mtu; |
998 | 1057 | ||
999 | nvdev = rndis_filter_device_add(hdev, &device_info); | 1058 | ret = netvsc_attach(ndev, &device_info); |
1000 | if (IS_ERR(nvdev)) { | 1059 | if (ret) |
1001 | ret = PTR_ERR(nvdev); | 1060 | goto rollback; |
1002 | |||
1003 | /* Attempt rollback to original MTU */ | ||
1004 | ndev->mtu = orig_mtu; | ||
1005 | nvdev = rndis_filter_device_add(hdev, &device_info); | ||
1006 | |||
1007 | if (vf_netdev) | ||
1008 | dev_set_mtu(vf_netdev, orig_mtu); | ||
1009 | |||
1010 | if (IS_ERR(nvdev)) { | ||
1011 | netdev_err(ndev, "restoring mtu failed: %ld\n", | ||
1012 | PTR_ERR(nvdev)); | ||
1013 | return ret; | ||
1014 | } | ||
1015 | } | ||
1016 | 1061 | ||
1017 | if (was_opened) | 1062 | return 0; |
1018 | rndis_filter_open(nvdev); | ||
1019 | 1063 | ||
1020 | netif_device_attach(ndev); | 1064 | rollback: |
1065 | /* Attempt rollback to original MTU */ | ||
1066 | ndev->mtu = orig_mtu; | ||
1021 | 1067 | ||
1022 | /* We may have missed link change notifications */ | 1068 | if (netvsc_attach(ndev, &device_info)) |
1023 | schedule_delayed_work(&ndevctx->dwork, 0); | 1069 | netdev_err(ndev, "restoring mtu failed\n"); |
1070 | rollback_vf: | ||
1071 | if (vf_netdev) | ||
1072 | dev_set_mtu(vf_netdev, orig_mtu); | ||
1024 | 1073 | ||
1025 | return ret; | 1074 | return ret; |
1026 | } | 1075 | } |
@@ -1526,11 +1575,9 @@ static int netvsc_set_ringparam(struct net_device *ndev, | |||
1526 | { | 1575 | { |
1527 | struct net_device_context *ndevctx = netdev_priv(ndev); | 1576 | struct net_device_context *ndevctx = netdev_priv(ndev); |
1528 | struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev); | 1577 | struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev); |
1529 | struct hv_device *hdev = ndevctx->device_ctx; | ||
1530 | struct netvsc_device_info device_info; | 1578 | struct netvsc_device_info device_info; |
1531 | struct ethtool_ringparam orig; | 1579 | struct ethtool_ringparam orig; |
1532 | u32 new_tx, new_rx; | 1580 | u32 new_tx, new_rx; |
1533 | bool was_opened; | ||
1534 | int ret = 0; | 1581 | int ret = 0; |
1535 | 1582 | ||
1536 | if (!nvdev || nvdev->destroy) | 1583 | if (!nvdev || nvdev->destroy) |
@@ -1555,34 +1602,18 @@ static int netvsc_set_ringparam(struct net_device *ndev, | |||
1555 | device_info.recv_sections = new_rx; | 1602 | device_info.recv_sections = new_rx; |
1556 | device_info.recv_section_size = nvdev->recv_section_size; | 1603 | device_info.recv_section_size = nvdev->recv_section_size; |
1557 | 1604 | ||
1558 | netif_device_detach(ndev); | 1605 | ret = netvsc_detach(ndev, nvdev); |
1559 | was_opened = rndis_filter_opened(nvdev); | 1606 | if (ret) |
1560 | if (was_opened) | 1607 | return ret; |
1561 | rndis_filter_close(nvdev); | ||
1562 | |||
1563 | rndis_filter_device_remove(hdev, nvdev); | ||
1564 | |||
1565 | nvdev = rndis_filter_device_add(hdev, &device_info); | ||
1566 | if (IS_ERR(nvdev)) { | ||
1567 | ret = PTR_ERR(nvdev); | ||
1568 | 1608 | ||
1609 | ret = netvsc_attach(ndev, &device_info); | ||
1610 | if (ret) { | ||
1569 | device_info.send_sections = orig.tx_pending; | 1611 | device_info.send_sections = orig.tx_pending; |
1570 | device_info.recv_sections = orig.rx_pending; | 1612 | device_info.recv_sections = orig.rx_pending; |
1571 | nvdev = rndis_filter_device_add(hdev, &device_info); | ||
1572 | if (IS_ERR(nvdev)) { | ||
1573 | netdev_err(ndev, "restoring ringparam failed: %ld\n", | ||
1574 | PTR_ERR(nvdev)); | ||
1575 | return ret; | ||
1576 | } | ||
1577 | } | ||
1578 | |||
1579 | if (was_opened) | ||
1580 | rndis_filter_open(nvdev); | ||
1581 | netif_device_attach(ndev); | ||
1582 | 1613 | ||
1583 | /* We may have missed link change notifications */ | 1614 | if (netvsc_attach(ndev, &device_info)) |
1584 | ndevctx->last_reconfig = 0; | 1615 | netdev_err(ndev, "restoring ringparam failed"); |
1585 | schedule_delayed_work(&ndevctx->dwork, 0); | 1616 | } |
1586 | 1617 | ||
1587 | return ret; | 1618 | return ret; |
1588 | } | 1619 | } |
@@ -1846,8 +1877,12 @@ static void __netvsc_vf_setup(struct net_device *ndev, | |||
1846 | 1877 | ||
1847 | /* set multicast etc flags on VF */ | 1878 | /* set multicast etc flags on VF */ |
1848 | dev_change_flags(vf_netdev, ndev->flags | IFF_SLAVE); | 1879 | dev_change_flags(vf_netdev, ndev->flags | IFF_SLAVE); |
1880 | |||
1881 | /* sync address list from ndev to VF */ | ||
1882 | netif_addr_lock_bh(ndev); | ||
1849 | dev_uc_sync(vf_netdev, ndev); | 1883 | dev_uc_sync(vf_netdev, ndev); |
1850 | dev_mc_sync(vf_netdev, ndev); | 1884 | dev_mc_sync(vf_netdev, ndev); |
1885 | netif_addr_unlock_bh(ndev); | ||
1851 | 1886 | ||
1852 | if (netif_running(ndev)) { | 1887 | if (netif_running(ndev)) { |
1853 | ret = dev_open(vf_netdev); | 1888 | ret = dev_open(vf_netdev); |
@@ -2063,8 +2098,8 @@ no_net: | |||
2063 | static int netvsc_remove(struct hv_device *dev) | 2098 | static int netvsc_remove(struct hv_device *dev) |
2064 | { | 2099 | { |
2065 | struct net_device_context *ndev_ctx; | 2100 | struct net_device_context *ndev_ctx; |
2066 | struct net_device *vf_netdev; | 2101 | struct net_device *vf_netdev, *net; |
2067 | struct net_device *net; | 2102 | struct netvsc_device *nvdev; |
2068 | 2103 | ||
2069 | net = hv_get_drvdata(dev); | 2104 | net = hv_get_drvdata(dev); |
2070 | if (net == NULL) { | 2105 | if (net == NULL) { |
@@ -2074,10 +2109,14 @@ static int netvsc_remove(struct hv_device *dev) | |||
2074 | 2109 | ||
2075 | ndev_ctx = netdev_priv(net); | 2110 | ndev_ctx = netdev_priv(net); |
2076 | 2111 | ||
2077 | netif_device_detach(net); | ||
2078 | |||
2079 | cancel_delayed_work_sync(&ndev_ctx->dwork); | 2112 | cancel_delayed_work_sync(&ndev_ctx->dwork); |
2080 | 2113 | ||
2114 | rcu_read_lock(); | ||
2115 | nvdev = rcu_dereference(ndev_ctx->nvdev); | ||
2116 | |||
2117 | if (nvdev) | ||
2118 | cancel_work_sync(&nvdev->subchan_work); | ||
2119 | |||
2081 | /* | 2120 | /* |
2082 | * Call to the vsc driver to let it know that the device is being | 2121 | * Call to the vsc driver to let it know that the device is being |
2083 | * removed. Also blocks mtu and channel changes. | 2122 | * removed. Also blocks mtu and channel changes. |
@@ -2087,11 +2126,13 @@ static int netvsc_remove(struct hv_device *dev) | |||
2087 | if (vf_netdev) | 2126 | if (vf_netdev) |
2088 | netvsc_unregister_vf(vf_netdev); | 2127 | netvsc_unregister_vf(vf_netdev); |
2089 | 2128 | ||
2129 | if (nvdev) | ||
2130 | rndis_filter_device_remove(dev, nvdev); | ||
2131 | |||
2090 | unregister_netdevice(net); | 2132 | unregister_netdevice(net); |
2091 | 2133 | ||
2092 | rndis_filter_device_remove(dev, | ||
2093 | rtnl_dereference(ndev_ctx->nvdev)); | ||
2094 | rtnl_unlock(); | 2134 | rtnl_unlock(); |
2135 | rcu_read_unlock(); | ||
2095 | 2136 | ||
2096 | hv_set_drvdata(dev, NULL); | 2137 | hv_set_drvdata(dev, NULL); |
2097 | 2138 | ||