aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/hyperv/netvsc.c
diff options
context:
space:
mode:
authorHaiyang Zhang <haiyangz@microsoft.com>2011-12-15 16:45:16 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2012-01-04 19:13:05 -0500
commitf157e78de5923dfb209355f3005ce1b5d64f7998 (patch)
tree188be24418c55525f234e027ec5c516c466d1955 /drivers/net/hyperv/netvsc.c
parent453263421f88b4a7e508c2e7b639c97e99c5b118 (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.c82
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
263static int netvsc_connect_vsp(struct hv_device *device) 264/* Negotiate NVSP protocol version */
265static 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
312static 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