diff options
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 78 |
1 files changed, 46 insertions, 32 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 1121a1ec407c..3af6d8d15233 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -1894,20 +1894,6 @@ out_unlock: | |||
1894 | rtnl_unlock(); | 1894 | rtnl_unlock(); |
1895 | } | 1895 | } |
1896 | 1896 | ||
1897 | static struct net_device *get_netvsc_bymac(const u8 *mac) | ||
1898 | { | ||
1899 | struct net_device_context *ndev_ctx; | ||
1900 | |||
1901 | list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) { | ||
1902 | struct net_device *dev = hv_get_drvdata(ndev_ctx->device_ctx); | ||
1903 | |||
1904 | if (ether_addr_equal(mac, dev->perm_addr)) | ||
1905 | return dev; | ||
1906 | } | ||
1907 | |||
1908 | return NULL; | ||
1909 | } | ||
1910 | |||
1911 | static struct net_device *get_netvsc_byref(struct net_device *vf_netdev) | 1897 | static struct net_device *get_netvsc_byref(struct net_device *vf_netdev) |
1912 | { | 1898 | { |
1913 | struct net_device_context *net_device_ctx; | 1899 | struct net_device_context *net_device_ctx; |
@@ -2036,26 +2022,48 @@ static void netvsc_vf_setup(struct work_struct *w) | |||
2036 | rtnl_unlock(); | 2022 | rtnl_unlock(); |
2037 | } | 2023 | } |
2038 | 2024 | ||
2025 | /* Find netvsc by VMBus serial number. | ||
2026 | * The PCI hyperv controller records the serial number as the slot. | ||
2027 | */ | ||
2028 | static struct net_device *get_netvsc_byslot(const struct net_device *vf_netdev) | ||
2029 | { | ||
2030 | struct device *parent = vf_netdev->dev.parent; | ||
2031 | struct net_device_context *ndev_ctx; | ||
2032 | struct pci_dev *pdev; | ||
2033 | |||
2034 | if (!parent || !dev_is_pci(parent)) | ||
2035 | return NULL; /* not a PCI device */ | ||
2036 | |||
2037 | pdev = to_pci_dev(parent); | ||
2038 | if (!pdev->slot) { | ||
2039 | netdev_notice(vf_netdev, "no PCI slot information\n"); | ||
2040 | return NULL; | ||
2041 | } | ||
2042 | |||
2043 | list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) { | ||
2044 | if (!ndev_ctx->vf_alloc) | ||
2045 | continue; | ||
2046 | |||
2047 | if (ndev_ctx->vf_serial == pdev->slot->number) | ||
2048 | return hv_get_drvdata(ndev_ctx->device_ctx); | ||
2049 | } | ||
2050 | |||
2051 | netdev_notice(vf_netdev, | ||
2052 | "no netdev found for slot %u\n", pdev->slot->number); | ||
2053 | return NULL; | ||
2054 | } | ||
2055 | |||
2039 | static int netvsc_register_vf(struct net_device *vf_netdev) | 2056 | static int netvsc_register_vf(struct net_device *vf_netdev) |
2040 | { | 2057 | { |
2041 | struct net_device *ndev; | ||
2042 | struct net_device_context *net_device_ctx; | 2058 | struct net_device_context *net_device_ctx; |
2043 | struct device *pdev = vf_netdev->dev.parent; | ||
2044 | struct netvsc_device *netvsc_dev; | 2059 | struct netvsc_device *netvsc_dev; |
2060 | struct net_device *ndev; | ||
2045 | int ret; | 2061 | int ret; |
2046 | 2062 | ||
2047 | if (vf_netdev->addr_len != ETH_ALEN) | 2063 | if (vf_netdev->addr_len != ETH_ALEN) |
2048 | return NOTIFY_DONE; | 2064 | return NOTIFY_DONE; |
2049 | 2065 | ||
2050 | if (!pdev || !dev_is_pci(pdev) || dev_is_pf(pdev)) | 2066 | ndev = get_netvsc_byslot(vf_netdev); |
2051 | return NOTIFY_DONE; | ||
2052 | |||
2053 | /* | ||
2054 | * We will use the MAC address to locate the synthetic interface to | ||
2055 | * associate with the VF interface. If we don't find a matching | ||
2056 | * synthetic interface, move on. | ||
2057 | */ | ||
2058 | ndev = get_netvsc_bymac(vf_netdev->perm_addr); | ||
2059 | if (!ndev) | 2067 | if (!ndev) |
2060 | return NOTIFY_DONE; | 2068 | return NOTIFY_DONE; |
2061 | 2069 | ||
@@ -2206,6 +2214,16 @@ static int netvsc_probe(struct hv_device *dev, | |||
2206 | 2214 | ||
2207 | memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); | 2215 | memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); |
2208 | 2216 | ||
2217 | /* We must get rtnl lock before scheduling nvdev->subchan_work, | ||
2218 | * otherwise netvsc_subchan_work() can get rtnl lock first and wait | ||
2219 | * all subchannels to show up, but that may not happen because | ||
2220 | * netvsc_probe() can't get rtnl lock and as a result vmbus_onoffer() | ||
2221 | * -> ... -> device_add() -> ... -> __device_attach() can't get | ||
2222 | * the device lock, so all the subchannels can't be processed -- | ||
2223 | * finally netvsc_subchan_work() hangs for ever. | ||
2224 | */ | ||
2225 | rtnl_lock(); | ||
2226 | |||
2209 | if (nvdev->num_chn > 1) | 2227 | if (nvdev->num_chn > 1) |
2210 | schedule_work(&nvdev->subchan_work); | 2228 | schedule_work(&nvdev->subchan_work); |
2211 | 2229 | ||
@@ -2224,7 +2242,6 @@ static int netvsc_probe(struct hv_device *dev, | |||
2224 | else | 2242 | else |
2225 | net->max_mtu = ETH_DATA_LEN; | 2243 | net->max_mtu = ETH_DATA_LEN; |
2226 | 2244 | ||
2227 | rtnl_lock(); | ||
2228 | ret = register_netdevice(net); | 2245 | ret = register_netdevice(net); |
2229 | if (ret != 0) { | 2246 | if (ret != 0) { |
2230 | pr_err("Unable to register netdev.\n"); | 2247 | pr_err("Unable to register netdev.\n"); |
@@ -2263,17 +2280,15 @@ static int netvsc_remove(struct hv_device *dev) | |||
2263 | 2280 | ||
2264 | cancel_delayed_work_sync(&ndev_ctx->dwork); | 2281 | cancel_delayed_work_sync(&ndev_ctx->dwork); |
2265 | 2282 | ||
2266 | rcu_read_lock(); | 2283 | rtnl_lock(); |
2267 | nvdev = rcu_dereference(ndev_ctx->nvdev); | 2284 | nvdev = rtnl_dereference(ndev_ctx->nvdev); |
2268 | 2285 | if (nvdev) | |
2269 | if (nvdev) | ||
2270 | cancel_work_sync(&nvdev->subchan_work); | 2286 | cancel_work_sync(&nvdev->subchan_work); |
2271 | 2287 | ||
2272 | /* | 2288 | /* |
2273 | * Call to the vsc driver to let it know that the device is being | 2289 | * Call to the vsc driver to let it know that the device is being |
2274 | * removed. Also blocks mtu and channel changes. | 2290 | * removed. Also blocks mtu and channel changes. |
2275 | */ | 2291 | */ |
2276 | rtnl_lock(); | ||
2277 | vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); | 2292 | vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); |
2278 | if (vf_netdev) | 2293 | if (vf_netdev) |
2279 | netvsc_unregister_vf(vf_netdev); | 2294 | netvsc_unregister_vf(vf_netdev); |
@@ -2285,7 +2300,6 @@ static int netvsc_remove(struct hv_device *dev) | |||
2285 | list_del(&ndev_ctx->list); | 2300 | list_del(&ndev_ctx->list); |
2286 | 2301 | ||
2287 | rtnl_unlock(); | 2302 | rtnl_unlock(); |
2288 | rcu_read_unlock(); | ||
2289 | 2303 | ||
2290 | hv_set_drvdata(dev, NULL); | 2304 | hv_set_drvdata(dev, NULL); |
2291 | 2305 | ||