diff options
author | Haiyang Zhang <haiyangz@microsoft.com> | 2011-12-15 16:45:16 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2012-01-04 19:13:05 -0500 |
commit | f157e78de5923dfb209355f3005ce1b5d64f7998 (patch) | |
tree | 188be24418c55525f234e027ec5c516c466d1955 /drivers/net/hyperv/netvsc.c | |
parent | 453263421f88b4a7e508c2e7b639c97e99c5b118 (diff) |
net/hyperv: Add NETVSP protocol version negotiation
Automatically negotiate the highest protocol version mutually recognized by
both host and guest.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/net/hyperv/netvsc.c')
-rw-r--r-- | drivers/net/hyperv/netvsc.c | 82 |
1 files changed, 55 insertions, 27 deletions
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index bab627f261c..46828b4dd8a 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/io.h> | 28 | #include <linux/io.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/netdevice.h> | 30 | #include <linux/netdevice.h> |
31 | #include <linux/if_ether.h> | ||
31 | 32 | ||
32 | #include "hyperv_net.h" | 33 | #include "hyperv_net.h" |
33 | 34 | ||
@@ -260,27 +261,18 @@ exit: | |||
260 | } | 261 | } |
261 | 262 | ||
262 | 263 | ||
263 | static int netvsc_connect_vsp(struct hv_device *device) | 264 | /* Negotiate NVSP protocol version */ |
265 | static int negotiate_nvsp_ver(struct hv_device *device, | ||
266 | struct netvsc_device *net_device, | ||
267 | struct nvsp_message *init_packet, | ||
268 | u32 nvsp_ver) | ||
264 | { | 269 | { |
265 | int ret, t; | 270 | int ret, t; |
266 | struct netvsc_device *net_device; | ||
267 | struct nvsp_message *init_packet; | ||
268 | int ndis_version; | ||
269 | struct net_device *ndev; | ||
270 | |||
271 | net_device = get_outbound_net_device(device); | ||
272 | if (!net_device) | ||
273 | return -ENODEV; | ||
274 | ndev = net_device->ndev; | ||
275 | |||
276 | init_packet = &net_device->channel_init_pkt; | ||
277 | 271 | ||
278 | memset(init_packet, 0, sizeof(struct nvsp_message)); | 272 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
279 | init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT; | 273 | init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT; |
280 | init_packet->msg.init_msg.init.min_protocol_ver = | 274 | init_packet->msg.init_msg.init.min_protocol_ver = nvsp_ver; |
281 | NVSP_MIN_PROTOCOL_VERSION; | 275 | init_packet->msg.init_msg.init.max_protocol_ver = nvsp_ver; |
282 | init_packet->msg.init_msg.init.max_protocol_ver = | ||
283 | NVSP_MAX_PROTOCOL_VERSION; | ||
284 | 276 | ||
285 | /* Send the init request */ | 277 | /* Send the init request */ |
286 | ret = vmbus_sendpacket(device->channel, init_packet, | 278 | ret = vmbus_sendpacket(device->channel, init_packet, |
@@ -290,26 +282,62 @@ static int netvsc_connect_vsp(struct hv_device *device) | |||
290 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | 282 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
291 | 283 | ||
292 | if (ret != 0) | 284 | if (ret != 0) |
293 | goto cleanup; | 285 | return ret; |
294 | 286 | ||
295 | t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ); | 287 | t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ); |
296 | 288 | ||
297 | if (t == 0) { | 289 | if (t == 0) |
298 | ret = -ETIMEDOUT; | 290 | return -ETIMEDOUT; |
299 | goto cleanup; | ||
300 | } | ||
301 | 291 | ||
302 | if (init_packet->msg.init_msg.init_complete.status != | 292 | if (init_packet->msg.init_msg.init_complete.status != |
303 | NVSP_STAT_SUCCESS) { | 293 | NVSP_STAT_SUCCESS) |
304 | ret = -EINVAL; | 294 | return -EINVAL; |
305 | goto cleanup; | ||
306 | } | ||
307 | 295 | ||
308 | if (init_packet->msg.init_msg.init_complete. | 296 | if (nvsp_ver != NVSP_PROTOCOL_VERSION_2) |
309 | negotiated_protocol_ver != NVSP_PROTOCOL_VERSION_1) { | 297 | return 0; |
298 | |||
299 | /* NVSPv2 only: Send NDIS config */ | ||
300 | memset(init_packet, 0, sizeof(struct nvsp_message)); | ||
301 | init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG; | ||
302 | init_packet->msg.v2_msg.send_ndis_config.mtu = ETH_DATA_LEN; | ||
303 | |||
304 | ret = vmbus_sendpacket(device->channel, init_packet, | ||
305 | sizeof(struct nvsp_message), | ||
306 | (unsigned long)init_packet, | ||
307 | VM_PKT_DATA_INBAND, 0); | ||
308 | |||
309 | return ret; | ||
310 | } | ||
311 | |||
312 | static int netvsc_connect_vsp(struct hv_device *device) | ||
313 | { | ||
314 | int ret; | ||
315 | struct netvsc_device *net_device; | ||
316 | struct nvsp_message *init_packet; | ||
317 | int ndis_version; | ||
318 | struct net_device *ndev; | ||
319 | |||
320 | net_device = get_outbound_net_device(device); | ||
321 | if (!net_device) | ||
322 | return -ENODEV; | ||
323 | ndev = net_device->ndev; | ||
324 | |||
325 | init_packet = &net_device->channel_init_pkt; | ||
326 | |||
327 | /* Negotiate the latest NVSP protocol supported */ | ||
328 | if (negotiate_nvsp_ver(device, net_device, init_packet, | ||
329 | NVSP_PROTOCOL_VERSION_2) == 0) { | ||
330 | net_device->nvsp_version = NVSP_PROTOCOL_VERSION_2; | ||
331 | } else if (negotiate_nvsp_ver(device, net_device, init_packet, | ||
332 | NVSP_PROTOCOL_VERSION_1) == 0) { | ||
333 | net_device->nvsp_version = NVSP_PROTOCOL_VERSION_1; | ||
334 | } else { | ||
310 | ret = -EPROTO; | 335 | ret = -EPROTO; |
311 | goto cleanup; | 336 | goto cleanup; |
312 | } | 337 | } |
338 | |||
339 | pr_debug("Negotiated NVSP version:%x\n", net_device->nvsp_version); | ||
340 | |||
313 | /* Send the ndis version */ | 341 | /* Send the ndis version */ |
314 | memset(init_packet, 0, sizeof(struct nvsp_message)); | 342 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
315 | 343 | ||