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 | |
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')
-rw-r--r-- | drivers/net/hyperv/hyperv_net.h | 101 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc.c | 82 |
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 | ||
140 | enum { | 139 | enum { |
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 | ||
170 | enum { | 194 | enum { |
@@ -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 | */ | ||
391 | struct 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 | |||
404 | struct 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 */ | ||
411 | struct 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 */ | ||
422 | struct 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 | |||
435 | struct nvsp_2_free_rxbuf { | ||
436 | u64 recv_buf_id; | ||
437 | } __packed; | ||
438 | |||
439 | union 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 | |||
362 | union nvsp_all_messages { | 446 | union 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 { | |||
391 | struct netvsc_device { | 476 | struct 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 | ||
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 | ||