aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/hyperv
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
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')
-rw-r--r--drivers/net/hyperv/hyperv_net.h101
-rw-r--r--drivers/net/hyperv/netvsc.c82
2 files changed, 149 insertions, 34 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index ff1b5209b45f..287767055125 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -134,8 +134,7 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
134#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF) 134#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF)
135 135
136#define NVSP_PROTOCOL_VERSION_1 2 136#define NVSP_PROTOCOL_VERSION_1 2
137#define NVSP_MIN_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1 137#define NVSP_PROTOCOL_VERSION_2 0x30002
138#define NVSP_MAX_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1
139 138
140enum { 139enum {
141 NVSP_MSG_TYPE_NONE = 0, 140 NVSP_MSG_TYPE_NONE = 0,
@@ -160,11 +159,36 @@ enum {
160 NVSP_MSG1_TYPE_SEND_RNDIS_PKT, 159 NVSP_MSG1_TYPE_SEND_RNDIS_PKT,
161 NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE, 160 NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE,
162 161
163 /* 162 /* Version 2 messages */
164 * This should be set to the number of messages for the version with 163 NVSP_MSG2_TYPE_SEND_CHIMNEY_DELEGATED_BUF,
165 * the maximum number of messages. 164 NVSP_MSG2_TYPE_SEND_CHIMNEY_DELEGATED_BUF_COMP,
166 */ 165 NVSP_MSG2_TYPE_REVOKE_CHIMNEY_DELEGATED_BUF,
167 NVSP_NUM_MSG_PER_VERSION = 9, 166
167 NVSP_MSG2_TYPE_RESUME_CHIMNEY_RX_INDICATION,
168
169 NVSP_MSG2_TYPE_TERMINATE_CHIMNEY,
170 NVSP_MSG2_TYPE_TERMINATE_CHIMNEY_COMP,
171
172 NVSP_MSG2_TYPE_INDICATE_CHIMNEY_EVENT,
173
174 NVSP_MSG2_TYPE_SEND_CHIMNEY_PKT,
175 NVSP_MSG2_TYPE_SEND_CHIMNEY_PKT_COMP,
176
177 NVSP_MSG2_TYPE_POST_CHIMNEY_RECV_REQ,
178 NVSP_MSG2_TYPE_POST_CHIMNEY_RECV_REQ_COMP,
179
180 NVSP_MSG2_TYPE_ALLOC_RXBUF,
181 NVSP_MSG2_TYPE_ALLOC_RXBUF_COMP,
182
183 NVSP_MSG2_TYPE_FREE_RXBUF,
184
185 NVSP_MSG2_TYPE_SEND_VMQ_RNDIS_PKT,
186 NVSP_MSG2_TYPE_SEND_VMQ_RNDIS_PKT_COMP,
187
188 NVSP_MSG2_TYPE_SEND_NDIS_CONFIG,
189
190 NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE,
191 NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP,
168}; 192};
169 193
170enum { 194enum {
@@ -175,6 +199,7 @@ enum {
175 NVSP_STAT_PROTOCOL_TOO_OLD, 199 NVSP_STAT_PROTOCOL_TOO_OLD,
176 NVSP_STAT_INVALID_RNDIS_PKT, 200 NVSP_STAT_INVALID_RNDIS_PKT,
177 NVSP_STAT_BUSY, 201 NVSP_STAT_BUSY,
202 NVSP_STAT_PROTOCOL_UNSUPPORTED,
178 NVSP_STAT_MAX, 203 NVSP_STAT_MAX,
179}; 204};
180 205
@@ -359,9 +384,69 @@ union nvsp_1_message_uber {
359 send_rndis_pkt_complete; 384 send_rndis_pkt_complete;
360} __packed; 385} __packed;
361 386
387
388/*
389 * Network VSP protocol version 2 messages:
390 */
391struct nvsp_2_vsc_capability {
392 union {
393 u64 data;
394 struct {
395 u64 vmq:1;
396 u64 chimney:1;
397 u64 sriov:1;
398 u64 ieee8021q:1;
399 u64 correlation_id:1;
400 };
401 };
402} __packed;
403
404struct nvsp_2_send_ndis_config {
405 u32 mtu;
406 u32 reserved;
407 struct nvsp_2_vsc_capability capability;
408} __packed;
409
410/* Allocate receive buffer */
411struct nvsp_2_alloc_rxbuf {
412 /* Allocation ID to match the allocation request and response */
413 u32 alloc_id;
414
415 /* Length of the VM shared memory receive buffer that needs to
416 * be allocated
417 */
418 u32 len;
419} __packed;
420
421/* Allocate receive buffer complete */
422struct nvsp_2_alloc_rxbuf_comp {
423 /* The NDIS_STATUS code for buffer allocation */
424 u32 status;
425
426 u32 alloc_id;
427
428 /* GPADL handle for the allocated receive buffer */
429 u32 gpadl_handle;
430
431 /* Receive buffer ID */
432 u64 recv_buf_id;
433} __packed;
434
435struct nvsp_2_free_rxbuf {
436 u64 recv_buf_id;
437} __packed;
438
439union nvsp_2_message_uber {
440 struct nvsp_2_send_ndis_config send_ndis_config;
441 struct nvsp_2_alloc_rxbuf alloc_rxbuf;
442 struct nvsp_2_alloc_rxbuf_comp alloc_rxbuf_comp;
443 struct nvsp_2_free_rxbuf free_rxbuf;
444} __packed;
445
362union nvsp_all_messages { 446union nvsp_all_messages {
363 union nvsp_message_init_uber init_msg; 447 union nvsp_message_init_uber init_msg;
364 union nvsp_1_message_uber v1_msg; 448 union nvsp_1_message_uber v1_msg;
449 union nvsp_2_message_uber v2_msg;
365} __packed; 450} __packed;
366 451
367/* ALL Messages */ 452/* ALL Messages */
@@ -391,6 +476,8 @@ struct nvsp_message {
391struct netvsc_device { 476struct netvsc_device {
392 struct hv_device *dev; 477 struct hv_device *dev;
393 478
479 u32 nvsp_version;
480
394 atomic_t num_outstanding_sends; 481 atomic_t num_outstanding_sends;
395 bool destroy; 482 bool destroy;
396 /* 483 /*
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index bab627f261c4..46828b4dd8ab 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