Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Haiyang Zhang and committed by
Greg Kroah-Hartman
f157e78d 45326342

+155 -40
+94 -7
drivers/net/hyperv/hyperv_net.h
··· 134 134 #define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF) 135 135 136 136 #define NVSP_PROTOCOL_VERSION_1 2 137 - #define NVSP_MIN_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1 138 - #define NVSP_MAX_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1 137 + #define NVSP_PROTOCOL_VERSION_2 0x30002 139 138 140 139 enum { 141 140 NVSP_MSG_TYPE_NONE = 0, ··· 159 160 NVSP_MSG1_TYPE_SEND_RNDIS_PKT, 160 161 NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE, 161 162 162 - /* 163 - * This should be set to the number of messages for the version with 164 - * the maximum number of messages. 165 - */ 166 - NVSP_NUM_MSG_PER_VERSION = 9, 163 + /* Version 2 messages */ 164 + NVSP_MSG2_TYPE_SEND_CHIMNEY_DELEGATED_BUF, 165 + NVSP_MSG2_TYPE_SEND_CHIMNEY_DELEGATED_BUF_COMP, 166 + NVSP_MSG2_TYPE_REVOKE_CHIMNEY_DELEGATED_BUF, 167 + 168 + NVSP_MSG2_TYPE_RESUME_CHIMNEY_RX_INDICATION, 169 + 170 + NVSP_MSG2_TYPE_TERMINATE_CHIMNEY, 171 + NVSP_MSG2_TYPE_TERMINATE_CHIMNEY_COMP, 172 + 173 + NVSP_MSG2_TYPE_INDICATE_CHIMNEY_EVENT, 174 + 175 + NVSP_MSG2_TYPE_SEND_CHIMNEY_PKT, 176 + NVSP_MSG2_TYPE_SEND_CHIMNEY_PKT_COMP, 177 + 178 + NVSP_MSG2_TYPE_POST_CHIMNEY_RECV_REQ, 179 + NVSP_MSG2_TYPE_POST_CHIMNEY_RECV_REQ_COMP, 180 + 181 + NVSP_MSG2_TYPE_ALLOC_RXBUF, 182 + NVSP_MSG2_TYPE_ALLOC_RXBUF_COMP, 183 + 184 + NVSP_MSG2_TYPE_FREE_RXBUF, 185 + 186 + NVSP_MSG2_TYPE_SEND_VMQ_RNDIS_PKT, 187 + NVSP_MSG2_TYPE_SEND_VMQ_RNDIS_PKT_COMP, 188 + 189 + NVSP_MSG2_TYPE_SEND_NDIS_CONFIG, 190 + 191 + NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE, 192 + NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP, 167 193 }; 168 194 169 195 enum { ··· 199 175 NVSP_STAT_PROTOCOL_TOO_OLD, 200 176 NVSP_STAT_INVALID_RNDIS_PKT, 201 177 NVSP_STAT_BUSY, 178 + NVSP_STAT_PROTOCOL_UNSUPPORTED, 202 179 NVSP_STAT_MAX, 203 180 }; 204 181 ··· 384 359 send_rndis_pkt_complete; 385 360 } __packed; 386 361 362 + 363 + /* 364 + * Network VSP protocol version 2 messages: 365 + */ 366 + struct nvsp_2_vsc_capability { 367 + union { 368 + u64 data; 369 + struct { 370 + u64 vmq:1; 371 + u64 chimney:1; 372 + u64 sriov:1; 373 + u64 ieee8021q:1; 374 + u64 correlation_id:1; 375 + }; 376 + }; 377 + } __packed; 378 + 379 + struct nvsp_2_send_ndis_config { 380 + u32 mtu; 381 + u32 reserved; 382 + struct nvsp_2_vsc_capability capability; 383 + } __packed; 384 + 385 + /* Allocate receive buffer */ 386 + struct nvsp_2_alloc_rxbuf { 387 + /* Allocation ID to match the allocation request and response */ 388 + u32 alloc_id; 389 + 390 + /* Length of the VM shared memory receive buffer that needs to 391 + * be allocated 392 + */ 393 + u32 len; 394 + } __packed; 395 + 396 + /* Allocate receive buffer complete */ 397 + struct nvsp_2_alloc_rxbuf_comp { 398 + /* The NDIS_STATUS code for buffer allocation */ 399 + u32 status; 400 + 401 + u32 alloc_id; 402 + 403 + /* GPADL handle for the allocated receive buffer */ 404 + u32 gpadl_handle; 405 + 406 + /* Receive buffer ID */ 407 + u64 recv_buf_id; 408 + } __packed; 409 + 410 + struct nvsp_2_free_rxbuf { 411 + u64 recv_buf_id; 412 + } __packed; 413 + 414 + union nvsp_2_message_uber { 415 + struct nvsp_2_send_ndis_config send_ndis_config; 416 + struct nvsp_2_alloc_rxbuf alloc_rxbuf; 417 + struct nvsp_2_alloc_rxbuf_comp alloc_rxbuf_comp; 418 + struct nvsp_2_free_rxbuf free_rxbuf; 419 + } __packed; 420 + 387 421 union nvsp_all_messages { 388 422 union nvsp_message_init_uber init_msg; 389 423 union nvsp_1_message_uber v1_msg; 424 + union nvsp_2_message_uber v2_msg; 390 425 } __packed; 391 426 392 427 /* ALL Messages */ ··· 475 390 /* Per netvsc channel-specific */ 476 391 struct netvsc_device { 477 392 struct hv_device *dev; 393 + 394 + u32 nvsp_version; 478 395 479 396 atomic_t num_outstanding_sends; 480 397 bool destroy;
+61 -33
drivers/net/hyperv/netvsc.c
··· 28 28 #include <linux/io.h> 29 29 #include <linux/slab.h> 30 30 #include <linux/netdevice.h> 31 + #include <linux/if_ether.h> 31 32 32 33 #include "hyperv_net.h" 33 34 ··· 261 260 } 262 261 263 262 264 - static int netvsc_connect_vsp(struct hv_device *device) 263 + /* Negotiate NVSP protocol version */ 264 + static int negotiate_nvsp_ver(struct hv_device *device, 265 + struct netvsc_device *net_device, 266 + struct nvsp_message *init_packet, 267 + u32 nvsp_ver) 265 268 { 266 269 int ret, t; 270 + 271 + memset(init_packet, 0, sizeof(struct nvsp_message)); 272 + init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT; 273 + init_packet->msg.init_msg.init.min_protocol_ver = nvsp_ver; 274 + init_packet->msg.init_msg.init.max_protocol_ver = nvsp_ver; 275 + 276 + /* Send the init request */ 277 + ret = vmbus_sendpacket(device->channel, init_packet, 278 + sizeof(struct nvsp_message), 279 + (unsigned long)init_packet, 280 + VM_PKT_DATA_INBAND, 281 + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 282 + 283 + if (ret != 0) 284 + return ret; 285 + 286 + t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ); 287 + 288 + if (t == 0) 289 + return -ETIMEDOUT; 290 + 291 + if (init_packet->msg.init_msg.init_complete.status != 292 + NVSP_STAT_SUCCESS) 293 + return -EINVAL; 294 + 295 + if (nvsp_ver != NVSP_PROTOCOL_VERSION_2) 296 + return 0; 297 + 298 + /* NVSPv2 only: Send NDIS config */ 299 + memset(init_packet, 0, sizeof(struct nvsp_message)); 300 + init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG; 301 + init_packet->msg.v2_msg.send_ndis_config.mtu = ETH_DATA_LEN; 302 + 303 + ret = vmbus_sendpacket(device->channel, init_packet, 304 + sizeof(struct nvsp_message), 305 + (unsigned long)init_packet, 306 + VM_PKT_DATA_INBAND, 0); 307 + 308 + return ret; 309 + } 310 + 311 + static int netvsc_connect_vsp(struct hv_device *device) 312 + { 313 + int ret; 267 314 struct netvsc_device *net_device; 268 315 struct nvsp_message *init_packet; 269 316 int ndis_version; ··· 324 275 325 276 init_packet = &net_device->channel_init_pkt; 326 277 327 - memset(init_packet, 0, sizeof(struct nvsp_message)); 328 - init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT; 329 - init_packet->msg.init_msg.init.min_protocol_ver = 330 - NVSP_MIN_PROTOCOL_VERSION; 331 - init_packet->msg.init_msg.init.max_protocol_ver = 332 - NVSP_MAX_PROTOCOL_VERSION; 333 - 334 - /* Send the init request */ 335 - ret = vmbus_sendpacket(device->channel, init_packet, 336 - sizeof(struct nvsp_message), 337 - (unsigned long)init_packet, 338 - VM_PKT_DATA_INBAND, 339 - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 340 - 341 - if (ret != 0) 342 - goto cleanup; 343 - 344 - t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ); 345 - 346 - if (t == 0) { 347 - ret = -ETIMEDOUT; 348 - goto cleanup; 349 - } 350 - 351 - if (init_packet->msg.init_msg.init_complete.status != 352 - NVSP_STAT_SUCCESS) { 353 - ret = -EINVAL; 354 - goto cleanup; 355 - } 356 - 357 - if (init_packet->msg.init_msg.init_complete. 358 - negotiated_protocol_ver != NVSP_PROTOCOL_VERSION_1) { 278 + /* Negotiate the latest NVSP protocol supported */ 279 + if (negotiate_nvsp_ver(device, net_device, init_packet, 280 + NVSP_PROTOCOL_VERSION_2) == 0) { 281 + net_device->nvsp_version = NVSP_PROTOCOL_VERSION_2; 282 + } else if (negotiate_nvsp_ver(device, net_device, init_packet, 283 + NVSP_PROTOCOL_VERSION_1) == 0) { 284 + net_device->nvsp_version = NVSP_PROTOCOL_VERSION_1; 285 + } else { 359 286 ret = -EPROTO; 360 287 goto cleanup; 361 288 } 289 + 290 + pr_debug("Negotiated NVSP version:%x\n", net_device->nvsp_version); 291 + 362 292 /* Send the ndis version */ 363 293 memset(init_packet, 0, sizeof(struct nvsp_message)); 364 294