|
Lines 48-54
Link Here
|
| 48 |
#include "hv_rndis.h" |
48 |
#include "hv_rndis.h" |
| 49 |
#include "hv_rndis_filter.h" |
49 |
#include "hv_rndis_filter.h" |
| 50 |
|
50 |
|
| 51 |
MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver"); |
|
|
| 52 |
|
51 |
|
| 53 |
/* |
52 |
/* |
| 54 |
* Forward declarations |
53 |
* Forward declarations |
|
Lines 59-69
Link Here
|
| 59 |
static int hv_nv_destroy_send_buffer(netvsc_dev *net_dev); |
58 |
static int hv_nv_destroy_send_buffer(netvsc_dev *net_dev); |
| 60 |
static int hv_nv_destroy_rx_buffer(netvsc_dev *net_dev); |
59 |
static int hv_nv_destroy_rx_buffer(netvsc_dev *net_dev); |
| 61 |
static int hv_nv_connect_to_vsp(struct hv_device *device); |
60 |
static int hv_nv_connect_to_vsp(struct hv_device *device); |
| 62 |
static void hv_nv_on_send_completion(netvsc_dev *net_dev, |
61 |
static void hv_nv_on_send_completion(struct hv_device *device, |
| 63 |
struct hv_device *device, hv_vm_packet_descriptor *pkt); |
62 |
hv_vm_packet_descriptor *pkt); |
| 64 |
static void hv_nv_on_receive(netvsc_dev *net_dev, |
63 |
static void hv_nv_on_receive(struct hv_device *device, |
| 65 |
struct hv_device *device, hv_vm_packet_descriptor *pkt); |
64 |
hv_vm_packet_descriptor *pkt); |
|
|
65 |
static void hv_nv_send_receive_completion(struct hv_device *device, |
| 66 |
uint64_t tid); |
| 66 |
|
67 |
|
|
|
68 |
|
| 67 |
/* |
69 |
/* |
| 68 |
* |
70 |
* |
| 69 |
*/ |
71 |
*/ |
|
Lines 73-79
Link Here
|
| 73 |
netvsc_dev *net_dev; |
75 |
netvsc_dev *net_dev; |
| 74 |
hn_softc_t *sc = device_get_softc(device->device); |
76 |
hn_softc_t *sc = device_get_softc(device->device); |
| 75 |
|
77 |
|
| 76 |
net_dev = malloc(sizeof(netvsc_dev), M_NETVSC, M_NOWAIT | M_ZERO); |
78 |
net_dev = malloc(sizeof(netvsc_dev), M_DEVBUF, M_NOWAIT | M_ZERO); |
| 77 |
if (net_dev == NULL) { |
79 |
if (net_dev == NULL) { |
| 78 |
return (NULL); |
80 |
return (NULL); |
| 79 |
} |
81 |
} |
|
Lines 125-158
Link Here
|
| 125 |
return (net_dev); |
127 |
return (net_dev); |
| 126 |
} |
128 |
} |
| 127 |
|
129 |
|
| 128 |
int |
|
|
| 129 |
hv_nv_get_next_send_section(netvsc_dev *net_dev) |
| 130 |
{ |
| 131 |
unsigned long bitsmap_words = net_dev->bitsmap_words; |
| 132 |
unsigned long *bitsmap = net_dev->send_section_bitsmap; |
| 133 |
unsigned long idx; |
| 134 |
int ret = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX; |
| 135 |
int i; |
| 136 |
|
| 137 |
for (i = 0; i < bitsmap_words; i++) { |
| 138 |
idx = ffs(~bitsmap[i]); |
| 139 |
if (0 == idx) |
| 140 |
continue; |
| 141 |
|
| 142 |
idx--; |
| 143 |
if (i * BITS_PER_LONG + idx >= net_dev->send_section_count) |
| 144 |
return (ret); |
| 145 |
|
| 146 |
if (synch_test_and_set_bit(idx, &bitsmap[i])) |
| 147 |
continue; |
| 148 |
|
| 149 |
ret = i * BITS_PER_LONG + idx; |
| 150 |
break; |
| 151 |
} |
| 152 |
|
| 153 |
return (ret); |
| 154 |
} |
| 155 |
|
| 156 |
/* |
130 |
/* |
| 157 |
* Net VSC initialize receive buffer with net VSP |
131 |
* Net VSC initialize receive buffer with net VSP |
| 158 |
* |
132 |
* |
|
Lines 171-178
Link Here
|
| 171 |
return (ENODEV); |
145 |
return (ENODEV); |
| 172 |
} |
146 |
} |
| 173 |
|
147 |
|
| 174 |
net_dev->rx_buf = contigmalloc(net_dev->rx_buf_size, M_NETVSC, |
148 |
net_dev->rx_buf = contigmalloc(net_dev->rx_buf_size, M_DEVBUF, |
| 175 |
M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); |
149 |
M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); |
|
|
150 |
if (net_dev->rx_buf == NULL) { |
| 151 |
ret = ENOMEM; |
| 152 |
goto cleanup; |
| 153 |
} |
| 176 |
|
154 |
|
| 177 |
/* |
155 |
/* |
| 178 |
* Establish the GPADL handle for this buffer on this channel. |
156 |
* Establish the GPADL handle for this buffer on this channel. |
|
Lines 223-229
Link Here
|
| 223 |
init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.num_sections; |
201 |
init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.num_sections; |
| 224 |
|
202 |
|
| 225 |
net_dev->rx_sections = malloc(net_dev->rx_section_count * |
203 |
net_dev->rx_sections = malloc(net_dev->rx_section_count * |
| 226 |
sizeof(nvsp_1_rx_buf_section), M_NETVSC, M_NOWAIT); |
204 |
sizeof(nvsp_1_rx_buf_section), M_DEVBUF, M_NOWAIT); |
| 227 |
if (net_dev->rx_sections == NULL) { |
205 |
if (net_dev->rx_sections == NULL) { |
| 228 |
ret = EINVAL; |
206 |
ret = EINVAL; |
| 229 |
goto cleanup; |
207 |
goto cleanup; |
|
Lines 267-273
Link Here
|
| 267 |
return (ENODEV); |
245 |
return (ENODEV); |
| 268 |
} |
246 |
} |
| 269 |
|
247 |
|
| 270 |
net_dev->send_buf = contigmalloc(net_dev->send_buf_size, M_NETVSC, |
248 |
net_dev->send_buf = contigmalloc(net_dev->send_buf_size, M_DEVBUF, |
| 271 |
M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); |
249 |
M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); |
| 272 |
if (net_dev->send_buf == NULL) { |
250 |
if (net_dev->send_buf == NULL) { |
| 273 |
ret = ENOMEM; |
251 |
ret = ENOMEM; |
|
Lines 280-286
Link Here
|
| 280 |
* channel to establish the gpadl handle. |
258 |
* channel to establish the gpadl handle. |
| 281 |
*/ |
259 |
*/ |
| 282 |
ret = hv_vmbus_channel_establish_gpadl(device->channel, |
260 |
ret = hv_vmbus_channel_establish_gpadl(device->channel, |
| 283 |
net_dev->send_buf, net_dev->send_buf_size, |
261 |
net_dev->send_buf, net_dev->send_buf_size, |
| 284 |
&net_dev->send_buf_gpadl_handle); |
262 |
&net_dev->send_buf_gpadl_handle); |
| 285 |
if (ret != 0) { |
263 |
if (ret != 0) { |
| 286 |
goto cleanup; |
264 |
goto cleanup; |
|
Lines 301-307
Link Here
|
| 301 |
/* Send the gpadl notification request */ |
279 |
/* Send the gpadl notification request */ |
| 302 |
|
280 |
|
| 303 |
ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, |
281 |
ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, |
| 304 |
sizeof(nvsp_msg), (uint64_t)init_pkt, |
282 |
sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, |
| 305 |
HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, |
283 |
HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, |
| 306 |
HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
284 |
HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
| 307 |
if (ret != 0) { |
285 |
if (ret != 0) { |
|
Lines 319-335
Link Here
|
| 319 |
|
297 |
|
| 320 |
net_dev->send_section_size = |
298 |
net_dev->send_section_size = |
| 321 |
init_pkt->msgs.vers_1_msgs.send_send_buf_complete.section_size; |
299 |
init_pkt->msgs.vers_1_msgs.send_send_buf_complete.section_size; |
| 322 |
net_dev->send_section_count = |
|
|
| 323 |
net_dev->send_buf_size / net_dev->send_section_size; |
| 324 |
net_dev->bitsmap_words = howmany(net_dev->send_section_count, |
| 325 |
BITS_PER_LONG); |
| 326 |
net_dev->send_section_bitsmap = |
| 327 |
malloc(net_dev->bitsmap_words * sizeof(long), M_NETVSC, |
| 328 |
M_NOWAIT | M_ZERO); |
| 329 |
if (NULL == net_dev->send_section_bitsmap) { |
| 330 |
ret = ENOMEM; |
| 331 |
goto cleanup; |
| 332 |
} |
| 333 |
|
300 |
|
| 334 |
goto exit; |
301 |
goto exit; |
| 335 |
|
302 |
|
|
Lines 394-405
Link Here
|
| 394 |
|
361 |
|
| 395 |
if (net_dev->rx_buf) { |
362 |
if (net_dev->rx_buf) { |
| 396 |
/* Free up the receive buffer */ |
363 |
/* Free up the receive buffer */ |
| 397 |
contigfree(net_dev->rx_buf, net_dev->rx_buf_size, M_NETVSC); |
364 |
contigfree(net_dev->rx_buf, net_dev->rx_buf_size, M_DEVBUF); |
| 398 |
net_dev->rx_buf = NULL; |
365 |
net_dev->rx_buf = NULL; |
| 399 |
} |
366 |
} |
| 400 |
|
367 |
|
| 401 |
if (net_dev->rx_sections) { |
368 |
if (net_dev->rx_sections) { |
| 402 |
free(net_dev->rx_sections, M_NETVSC); |
369 |
free(net_dev->rx_sections, M_DEVBUF); |
| 403 |
net_dev->rx_sections = NULL; |
370 |
net_dev->rx_sections = NULL; |
| 404 |
net_dev->rx_section_count = 0; |
371 |
net_dev->rx_section_count = 0; |
| 405 |
} |
372 |
} |
|
Lines 462-475
Link Here
|
| 462 |
|
429 |
|
| 463 |
if (net_dev->send_buf) { |
430 |
if (net_dev->send_buf) { |
| 464 |
/* Free up the receive buffer */ |
431 |
/* Free up the receive buffer */ |
| 465 |
contigfree(net_dev->send_buf, net_dev->send_buf_size, M_NETVSC); |
432 |
contigfree(net_dev->send_buf, net_dev->send_buf_size, M_DEVBUF); |
| 466 |
net_dev->send_buf = NULL; |
433 |
net_dev->send_buf = NULL; |
| 467 |
} |
434 |
} |
| 468 |
|
435 |
|
| 469 |
if (net_dev->send_section_bitsmap) { |
|
|
| 470 |
free(net_dev->send_section_bitsmap, M_NETVSC); |
| 471 |
} |
| 472 |
|
| 473 |
return (ret); |
436 |
return (ret); |
| 474 |
} |
437 |
} |
| 475 |
|
438 |
|
|
Lines 483-489
Link Here
|
| 483 |
*/ |
446 |
*/ |
| 484 |
static int |
447 |
static int |
| 485 |
hv_nv_negotiate_nvsp_protocol(struct hv_device *device, netvsc_dev *net_dev, |
448 |
hv_nv_negotiate_nvsp_protocol(struct hv_device *device, netvsc_dev *net_dev, |
| 486 |
uint32_t nvsp_ver) |
449 |
uint32_t nvsp_ver) |
| 487 |
{ |
450 |
{ |
| 488 |
nvsp_msg *init_pkt; |
451 |
nvsp_msg *init_pkt; |
| 489 |
int ret; |
452 |
int ret; |
|
Lines 560-572
Link Here
|
| 560 |
{ |
523 |
{ |
| 561 |
netvsc_dev *net_dev; |
524 |
netvsc_dev *net_dev; |
| 562 |
nvsp_msg *init_pkt; |
525 |
nvsp_msg *init_pkt; |
|
|
526 |
uint32_t nvsp_vers; |
| 563 |
uint32_t ndis_version; |
527 |
uint32_t ndis_version; |
| 564 |
uint32_t protocol_list[] = { NVSP_PROTOCOL_VERSION_1, |
|
|
| 565 |
NVSP_PROTOCOL_VERSION_2, |
| 566 |
NVSP_PROTOCOL_VERSION_4, |
| 567 |
NVSP_PROTOCOL_VERSION_5 }; |
| 568 |
int i; |
| 569 |
int protocol_number = nitems(protocol_list); |
| 570 |
int ret = 0; |
528 |
int ret = 0; |
| 571 |
device_t dev = device->device; |
529 |
device_t dev = device->device; |
| 572 |
hn_softc_t *sc = device_get_softc(dev); |
530 |
hn_softc_t *sc = device_get_softc(dev); |
|
Lines 578-608
Link Here
|
| 578 |
} |
536 |
} |
| 579 |
|
537 |
|
| 580 |
/* |
538 |
/* |
| 581 |
* Negotiate the NVSP version. Try the latest NVSP first. |
539 |
* Negotiate the NVSP version. Try NVSP v2 first. |
| 582 |
*/ |
540 |
*/ |
| 583 |
for (i = protocol_number - 1; i >= 0; i--) { |
541 |
nvsp_vers = NVSP_PROTOCOL_VERSION_2; |
| 584 |
if (hv_nv_negotiate_nvsp_protocol(device, net_dev, |
542 |
ret = hv_nv_negotiate_nvsp_protocol(device, net_dev, nvsp_vers); |
| 585 |
protocol_list[i]) == 0) { |
543 |
if (ret != 0) { |
| 586 |
net_dev->nvsp_version = protocol_list[i]; |
544 |
/* NVSP v2 failed, try NVSP v1 */ |
| 587 |
if (bootverbose) |
545 |
nvsp_vers = NVSP_PROTOCOL_VERSION_1; |
| 588 |
device_printf(dev, "Netvsc: got version 0x%x\n", |
546 |
ret = hv_nv_negotiate_nvsp_protocol(device, net_dev, nvsp_vers); |
| 589 |
net_dev->nvsp_version); |
547 |
if (ret != 0) { |
| 590 |
break; |
548 |
/* NVSP v1 failed, return bad status */ |
|
|
549 |
return (ret); |
| 591 |
} |
550 |
} |
| 592 |
} |
551 |
} |
|
|
552 |
net_dev->nvsp_version = nvsp_vers; |
| 593 |
|
553 |
|
| 594 |
if (i < 0) { |
|
|
| 595 |
if (bootverbose) |
| 596 |
device_printf(dev, "failed to negotiate a valid " |
| 597 |
"protocol.\n"); |
| 598 |
return (EPROTO); |
| 599 |
} |
| 600 |
|
| 601 |
/* |
554 |
/* |
| 602 |
* Set the MTU if supported by this NVSP protocol version |
555 |
* Set the MTU if supported by this NVSP protocol version |
| 603 |
* This needs to be right after the NVSP init message per Haiyang |
556 |
* This needs to be right after the NVSP init message per Haiyang |
| 604 |
*/ |
557 |
*/ |
| 605 |
if (net_dev->nvsp_version >= NVSP_PROTOCOL_VERSION_2) |
558 |
if (nvsp_vers >= NVSP_PROTOCOL_VERSION_2) |
| 606 |
ret = hv_nv_send_ndis_config(device, ifp->if_mtu); |
559 |
ret = hv_nv_send_ndis_config(device, ifp->if_mtu); |
| 607 |
|
560 |
|
| 608 |
/* |
561 |
/* |
|
Lines 612-622
Link Here
|
| 612 |
|
565 |
|
| 613 |
memset(init_pkt, 0, sizeof(nvsp_msg)); |
566 |
memset(init_pkt, 0, sizeof(nvsp_msg)); |
| 614 |
|
567 |
|
| 615 |
if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_4) { |
568 |
/* |
| 616 |
ndis_version = NDIS_VERSION_6_1; |
569 |
* Updated to version 5.1, minimum, for VLAN per Haiyang |
| 617 |
} else { |
570 |
*/ |
| 618 |
ndis_version = NDIS_VERSION_6_30; |
571 |
ndis_version = NDIS_VERSION; |
| 619 |
} |
|
|
| 620 |
|
572 |
|
| 621 |
init_pkt->hdr.msg_type = nvsp_msg_1_type_send_ndis_vers; |
573 |
init_pkt->hdr.msg_type = nvsp_msg_1_type_send_ndis_vers; |
| 622 |
init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_major_vers = |
574 |
init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_major_vers = |
|
Lines 668-674
Link Here
|
| 668 |
hv_nv_on_device_add(struct hv_device *device, void *additional_info) |
620 |
hv_nv_on_device_add(struct hv_device *device, void *additional_info) |
| 669 |
{ |
621 |
{ |
| 670 |
netvsc_dev *net_dev; |
622 |
netvsc_dev *net_dev; |
| 671 |
int ret = 0; |
623 |
netvsc_packet *packet; |
|
|
624 |
netvsc_packet *next_packet; |
| 625 |
int i, ret = 0; |
| 672 |
|
626 |
|
| 673 |
net_dev = hv_nv_alloc_net_device(device); |
627 |
net_dev = hv_nv_alloc_net_device(device); |
| 674 |
if (!net_dev) |
628 |
if (!net_dev) |
|
Lines 676-684
Link Here
|
| 676 |
|
630 |
|
| 677 |
/* Initialize the NetVSC channel extension */ |
631 |
/* Initialize the NetVSC channel extension */ |
| 678 |
net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; |
632 |
net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; |
|
|
633 |
mtx_init(&net_dev->rx_pkt_list_lock, "HV-RPL", NULL, |
| 634 |
MTX_SPIN | MTX_RECURSE); |
| 679 |
|
635 |
|
| 680 |
net_dev->send_buf_size = NETVSC_SEND_BUFFER_SIZE; |
636 |
net_dev->send_buf_size = NETVSC_SEND_BUFFER_SIZE; |
| 681 |
|
637 |
|
|
|
638 |
/* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */ |
| 639 |
STAILQ_INIT(&net_dev->myrx_packet_list); |
| 640 |
|
| 641 |
/* |
| 642 |
* malloc a sufficient number of netvsc_packet buffers to hold |
| 643 |
* a packet list. Add them to the netvsc device packet queue. |
| 644 |
*/ |
| 645 |
for (i=0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) { |
| 646 |
packet = malloc(sizeof(netvsc_packet) + |
| 647 |
(NETVSC_RECEIVE_SG_COUNT * sizeof(hv_vmbus_page_buffer)), |
| 648 |
M_DEVBUF, M_NOWAIT | M_ZERO); |
| 649 |
if (!packet) { |
| 650 |
break; |
| 651 |
} |
| 652 |
STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, packet, |
| 653 |
mylist_entry); |
| 654 |
} |
| 655 |
|
| 682 |
sema_init(&net_dev->channel_init_sema, 0, "netdev_sema"); |
656 |
sema_init(&net_dev->channel_init_sema, 0, "netdev_sema"); |
| 683 |
|
657 |
|
| 684 |
/* |
658 |
/* |
|
Lines 711-717
Link Here
|
| 711 |
*/ |
685 |
*/ |
| 712 |
if (net_dev) { |
686 |
if (net_dev) { |
| 713 |
sema_destroy(&net_dev->channel_init_sema); |
687 |
sema_destroy(&net_dev->channel_init_sema); |
| 714 |
free(net_dev, M_NETVSC); |
688 |
|
|
|
689 |
packet = STAILQ_FIRST(&net_dev->myrx_packet_list); |
| 690 |
while (packet != NULL) { |
| 691 |
next_packet = STAILQ_NEXT(packet, mylist_entry); |
| 692 |
free(packet, M_DEVBUF); |
| 693 |
packet = next_packet; |
| 694 |
} |
| 695 |
/* Reset the list to initial state */ |
| 696 |
STAILQ_INIT(&net_dev->myrx_packet_list); |
| 697 |
|
| 698 |
mtx_destroy(&net_dev->rx_pkt_list_lock); |
| 699 |
|
| 700 |
free(net_dev, M_DEVBUF); |
| 715 |
} |
701 |
} |
| 716 |
|
702 |
|
| 717 |
return (NULL); |
703 |
return (NULL); |
|
Lines 723-728
Link Here
|
| 723 |
int |
709 |
int |
| 724 |
hv_nv_on_device_remove(struct hv_device *device, boolean_t destroy_channel) |
710 |
hv_nv_on_device_remove(struct hv_device *device, boolean_t destroy_channel) |
| 725 |
{ |
711 |
{ |
|
|
712 |
netvsc_packet *net_vsc_pkt; |
| 713 |
netvsc_packet *next_net_vsc_pkt; |
| 726 |
hn_softc_t *sc = device_get_softc(device->device); |
714 |
hn_softc_t *sc = device_get_softc(device->device); |
| 727 |
netvsc_dev *net_dev = sc->net_dev;; |
715 |
netvsc_dev *net_dev = sc->net_dev;; |
| 728 |
|
716 |
|
|
Lines 749-756
Link Here
|
| 749 |
|
737 |
|
| 750 |
hv_vmbus_channel_close(device->channel); |
738 |
hv_vmbus_channel_close(device->channel); |
| 751 |
|
739 |
|
|
|
740 |
/* Release all resources */ |
| 741 |
net_vsc_pkt = STAILQ_FIRST(&net_dev->myrx_packet_list); |
| 742 |
while (net_vsc_pkt != NULL) { |
| 743 |
next_net_vsc_pkt = STAILQ_NEXT(net_vsc_pkt, mylist_entry); |
| 744 |
free(net_vsc_pkt, M_DEVBUF); |
| 745 |
net_vsc_pkt = next_net_vsc_pkt; |
| 746 |
} |
| 747 |
|
| 748 |
/* Reset the list to initial state */ |
| 749 |
STAILQ_INIT(&net_dev->myrx_packet_list); |
| 750 |
|
| 751 |
mtx_destroy(&net_dev->rx_pkt_list_lock); |
| 752 |
sema_destroy(&net_dev->channel_init_sema); |
752 |
sema_destroy(&net_dev->channel_init_sema); |
| 753 |
free(net_dev, M_NETVSC); |
753 |
free(net_dev, M_DEVBUF); |
| 754 |
|
754 |
|
| 755 |
return (0); |
755 |
return (0); |
| 756 |
} |
756 |
} |
|
Lines 758-770
Link Here
|
| 758 |
/* |
758 |
/* |
| 759 |
* Net VSC on send completion |
759 |
* Net VSC on send completion |
| 760 |
*/ |
760 |
*/ |
| 761 |
static void |
761 |
static void |
| 762 |
hv_nv_on_send_completion(netvsc_dev *net_dev, |
762 |
hv_nv_on_send_completion(struct hv_device *device, hv_vm_packet_descriptor *pkt) |
| 763 |
struct hv_device *device, hv_vm_packet_descriptor *pkt) |
|
|
| 764 |
{ |
763 |
{ |
|
|
764 |
netvsc_dev *net_dev; |
| 765 |
nvsp_msg *nvsp_msg_pkt; |
765 |
nvsp_msg *nvsp_msg_pkt; |
| 766 |
netvsc_packet *net_vsc_pkt; |
766 |
netvsc_packet *net_vsc_pkt; |
| 767 |
|
767 |
|
|
|
768 |
net_dev = hv_nv_get_inbound_net_device(device); |
| 769 |
if (!net_dev) { |
| 770 |
return; |
| 771 |
} |
| 772 |
|
| 768 |
nvsp_msg_pkt = |
773 |
nvsp_msg_pkt = |
| 769 |
(nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3)); |
774 |
(nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3)); |
| 770 |
|
775 |
|
|
Lines 775-799
Link Here
|
| 775 |
== nvsp_msg_1_type_send_send_buf_complete) { |
780 |
== nvsp_msg_1_type_send_send_buf_complete) { |
| 776 |
/* Copy the response back */ |
781 |
/* Copy the response back */ |
| 777 |
memcpy(&net_dev->channel_init_packet, nvsp_msg_pkt, |
782 |
memcpy(&net_dev->channel_init_packet, nvsp_msg_pkt, |
| 778 |
sizeof(nvsp_msg)); |
783 |
sizeof(nvsp_msg)); |
| 779 |
sema_post(&net_dev->channel_init_sema); |
784 |
sema_post(&net_dev->channel_init_sema); |
| 780 |
} else if (nvsp_msg_pkt->hdr.msg_type == |
785 |
} else if (nvsp_msg_pkt->hdr.msg_type == |
| 781 |
nvsp_msg_1_type_send_rndis_pkt_complete) { |
786 |
nvsp_msg_1_type_send_rndis_pkt_complete) { |
| 782 |
/* Get the send context */ |
787 |
/* Get the send context */ |
| 783 |
net_vsc_pkt = |
788 |
net_vsc_pkt = |
| 784 |
(netvsc_packet *)(unsigned long)pkt->transaction_id; |
789 |
(netvsc_packet *)(unsigned long)pkt->transaction_id; |
| 785 |
if (NULL != net_vsc_pkt) { |
|
|
| 786 |
if (net_vsc_pkt->send_buf_section_idx != |
| 787 |
NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) { |
| 788 |
synch_change_bit(net_vsc_pkt->send_buf_section_idx, |
| 789 |
net_dev->send_section_bitsmap); |
| 790 |
} |
| 791 |
|
| 792 |
/* Notify the layer above us */ |
| 793 |
net_vsc_pkt->compl.send.on_send_completion( |
| 794 |
net_vsc_pkt->compl.send.send_completion_context); |
| 795 |
|
790 |
|
| 796 |
} |
791 |
/* Notify the layer above us */ |
|
|
792 |
net_vsc_pkt->compl.send.on_send_completion( |
| 793 |
net_vsc_pkt->compl.send.send_completion_context); |
| 797 |
|
794 |
|
| 798 |
atomic_subtract_int(&net_dev->num_outstanding_sends, 1); |
795 |
atomic_subtract_int(&net_dev->num_outstanding_sends, 1); |
| 799 |
} |
796 |
} |
|
Lines 824-833
Link Here
|
| 824 |
send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 1; |
821 |
send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 1; |
| 825 |
} |
822 |
} |
| 826 |
|
823 |
|
|
|
824 |
/* Not using send buffer section */ |
| 827 |
send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx = |
825 |
send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx = |
| 828 |
pkt->send_buf_section_idx; |
826 |
0xFFFFFFFF; |
| 829 |
send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size = |
827 |
send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size = 0; |
| 830 |
pkt->send_buf_section_size; |
|
|
| 831 |
|
828 |
|
| 832 |
if (pkt->page_buf_count) { |
829 |
if (pkt->page_buf_count) { |
| 833 |
ret = hv_vmbus_channel_send_packet_pagebuffer(device->channel, |
830 |
ret = hv_vmbus_channel_send_packet_pagebuffer(device->channel, |
|
Lines 853-933
Link Here
|
| 853 |
* In the FreeBSD Hyper-V virtual world, this function deals exclusively |
850 |
* In the FreeBSD Hyper-V virtual world, this function deals exclusively |
| 854 |
* with virtual addresses. |
851 |
* with virtual addresses. |
| 855 |
*/ |
852 |
*/ |
| 856 |
static void |
853 |
static void |
| 857 |
hv_nv_on_receive(netvsc_dev *net_dev, struct hv_device *device, |
854 |
hv_nv_on_receive(struct hv_device *device, hv_vm_packet_descriptor *pkt) |
| 858 |
hv_vm_packet_descriptor *pkt) |
|
|
| 859 |
{ |
855 |
{ |
|
|
856 |
netvsc_dev *net_dev; |
| 860 |
hv_vm_transfer_page_packet_header *vm_xfer_page_pkt; |
857 |
hv_vm_transfer_page_packet_header *vm_xfer_page_pkt; |
| 861 |
nvsp_msg *nvsp_msg_pkt; |
858 |
nvsp_msg *nvsp_msg_pkt; |
| 862 |
netvsc_packet vsc_pkt; |
859 |
netvsc_packet *net_vsc_pkt = NULL; |
| 863 |
netvsc_packet *net_vsc_pkt = &vsc_pkt; |
860 |
unsigned long start; |
| 864 |
device_t dev = device->device; |
861 |
xfer_page_packet *xfer_page_pkt = NULL; |
|
|
862 |
STAILQ_HEAD(PKT_LIST, netvsc_packet_) mylist_head = |
| 863 |
STAILQ_HEAD_INITIALIZER(mylist_head); |
| 865 |
int count = 0; |
864 |
int count = 0; |
| 866 |
int i = 0; |
865 |
int i = 0; |
| 867 |
int status = nvsp_status_success; |
|
|
| 868 |
|
866 |
|
|
|
867 |
net_dev = hv_nv_get_inbound_net_device(device); |
| 868 |
if (!net_dev) |
| 869 |
return; |
| 870 |
|
| 869 |
/* |
871 |
/* |
| 870 |
* All inbound packets other than send completion should be |
872 |
* All inbound packets other than send completion should be |
| 871 |
* xfer page packet. |
873 |
* xfer page packet. |
| 872 |
*/ |
874 |
*/ |
| 873 |
if (pkt->type != HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES) { |
875 |
if (pkt->type != HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES) |
| 874 |
device_printf(dev, "packet type %d is invalid!\n", pkt->type); |
|
|
| 875 |
return; |
876 |
return; |
| 876 |
} |
|
|
| 877 |
|
877 |
|
| 878 |
nvsp_msg_pkt = (nvsp_msg *)((unsigned long)pkt |
878 |
nvsp_msg_pkt = (nvsp_msg *)((unsigned long)pkt |
| 879 |
+ (pkt->data_offset8 << 3)); |
879 |
+ (pkt->data_offset8 << 3)); |
| 880 |
|
880 |
|
| 881 |
/* Make sure this is a valid nvsp packet */ |
881 |
/* Make sure this is a valid nvsp packet */ |
| 882 |
if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt) { |
882 |
if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt) |
| 883 |
device_printf(dev, "packet hdr type %d is invalid!\n", |
|
|
| 884 |
pkt->type); |
| 885 |
return; |
883 |
return; |
| 886 |
} |
|
|
| 887 |
|
884 |
|
| 888 |
vm_xfer_page_pkt = (hv_vm_transfer_page_packet_header *)pkt; |
885 |
vm_xfer_page_pkt = (hv_vm_transfer_page_packet_header *)pkt; |
| 889 |
|
886 |
|
| 890 |
if (vm_xfer_page_pkt->transfer_page_set_id != |
887 |
if (vm_xfer_page_pkt->transfer_page_set_id |
| 891 |
NETVSC_RECEIVE_BUFFER_ID) { |
888 |
!= NETVSC_RECEIVE_BUFFER_ID) { |
| 892 |
device_printf(dev, "transfer_page_set_id %d is invalid!\n", |
|
|
| 893 |
vm_xfer_page_pkt->transfer_page_set_id); |
| 894 |
return; |
889 |
return; |
| 895 |
} |
890 |
} |
| 896 |
|
891 |
|
| 897 |
count = vm_xfer_page_pkt->range_count; |
892 |
STAILQ_INIT(&mylist_head); |
| 898 |
net_vsc_pkt->device = device; |
|
|
| 899 |
|
893 |
|
|
|
894 |
/* |
| 895 |
* Grab free packets (range count + 1) to represent this xfer page |
| 896 |
* packet. +1 to represent the xfer page packet itself. We grab it |
| 897 |
* here so that we know exactly how many we can fulfill. |
| 898 |
*/ |
| 899 |
mtx_lock_spin(&net_dev->rx_pkt_list_lock); |
| 900 |
while (!STAILQ_EMPTY(&net_dev->myrx_packet_list)) { |
| 901 |
net_vsc_pkt = STAILQ_FIRST(&net_dev->myrx_packet_list); |
| 902 |
STAILQ_REMOVE_HEAD(&net_dev->myrx_packet_list, mylist_entry); |
| 903 |
|
| 904 |
STAILQ_INSERT_TAIL(&mylist_head, net_vsc_pkt, mylist_entry); |
| 905 |
|
| 906 |
if (++count == vm_xfer_page_pkt->range_count + 1) |
| 907 |
break; |
| 908 |
} |
| 909 |
|
| 910 |
mtx_unlock_spin(&net_dev->rx_pkt_list_lock); |
| 911 |
|
| 912 |
/* |
| 913 |
* We need at least 2 netvsc pkts (1 to represent the xfer page |
| 914 |
* and at least 1 for the range) i.e. we can handle some of the |
| 915 |
* xfer page packet ranges... |
| 916 |
*/ |
| 917 |
if (count < 2) { |
| 918 |
/* Return netvsc packet to the freelist */ |
| 919 |
mtx_lock_spin(&net_dev->rx_pkt_list_lock); |
| 920 |
for (i=count; i != 0; i--) { |
| 921 |
net_vsc_pkt = STAILQ_FIRST(&mylist_head); |
| 922 |
STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry); |
| 923 |
|
| 924 |
STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, |
| 925 |
net_vsc_pkt, mylist_entry); |
| 926 |
} |
| 927 |
mtx_unlock_spin(&net_dev->rx_pkt_list_lock); |
| 928 |
|
| 929 |
hv_nv_send_receive_completion(device, |
| 930 |
vm_xfer_page_pkt->d.transaction_id); |
| 931 |
|
| 932 |
return; |
| 933 |
} |
| 934 |
|
| 935 |
/* Take the first packet in the list */ |
| 936 |
xfer_page_pkt = (xfer_page_packet *)STAILQ_FIRST(&mylist_head); |
| 937 |
STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry); |
| 938 |
|
| 939 |
/* This is how many data packets we can supply */ |
| 940 |
xfer_page_pkt->count = count - 1; |
| 941 |
|
| 900 |
/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ |
942 |
/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ |
| 901 |
for (i = 0; i < count; i++) { |
943 |
for (i=0; i < (count - 1); i++) { |
| 902 |
net_vsc_pkt->status = nvsp_status_success; |
944 |
net_vsc_pkt = STAILQ_FIRST(&mylist_head); |
| 903 |
net_vsc_pkt->data = (void *)((unsigned long)net_dev->rx_buf + |
945 |
STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry); |
| 904 |
vm_xfer_page_pkt->ranges[i].byte_offset); |
946 |
|
| 905 |
net_vsc_pkt->tot_data_buf_len = |
947 |
/* |
|
|
948 |
* Initialize the netvsc packet |
| 949 |
*/ |
| 950 |
net_vsc_pkt->xfer_page_pkt = xfer_page_pkt; |
| 951 |
net_vsc_pkt->compl.rx.rx_completion_context = net_vsc_pkt; |
| 952 |
net_vsc_pkt->device = device; |
| 953 |
/* Save this so that we can send it back */ |
| 954 |
net_vsc_pkt->compl.rx.rx_completion_tid = |
| 955 |
vm_xfer_page_pkt->d.transaction_id; |
| 956 |
|
| 957 |
net_vsc_pkt->tot_data_buf_len = |
| 906 |
vm_xfer_page_pkt->ranges[i].byte_count; |
958 |
vm_xfer_page_pkt->ranges[i].byte_count; |
|
|
959 |
net_vsc_pkt->page_buf_count = 1; |
| 907 |
|
960 |
|
| 908 |
hv_rf_on_receive(net_dev, device, net_vsc_pkt); |
961 |
net_vsc_pkt->page_buffers[0].length = |
| 909 |
if (net_vsc_pkt->status != nvsp_status_success) { |
962 |
vm_xfer_page_pkt->ranges[i].byte_count; |
| 910 |
status = nvsp_status_failure; |
963 |
|
| 911 |
} |
964 |
/* The virtual address of the packet in the receive buffer */ |
|
|
965 |
start = ((unsigned long)net_dev->rx_buf + |
| 966 |
vm_xfer_page_pkt->ranges[i].byte_offset); |
| 967 |
start = ((unsigned long)start) & ~(PAGE_SIZE - 1); |
| 968 |
|
| 969 |
/* Page number of the virtual page containing packet start */ |
| 970 |
net_vsc_pkt->page_buffers[0].pfn = start >> PAGE_SHIFT; |
| 971 |
|
| 972 |
/* Calculate the page relative offset */ |
| 973 |
net_vsc_pkt->page_buffers[0].offset = |
| 974 |
vm_xfer_page_pkt->ranges[i].byte_offset & (PAGE_SIZE - 1); |
| 975 |
|
| 976 |
/* |
| 977 |
* In this implementation, we are dealing with virtual |
| 978 |
* addresses exclusively. Since we aren't using physical |
| 979 |
* addresses at all, we don't care if a packet crosses a |
| 980 |
* page boundary. For this reason, the original code to |
| 981 |
* check for and handle page crossings has been removed. |
| 982 |
*/ |
| 983 |
|
| 984 |
/* |
| 985 |
* Pass it to the upper layer. The receive completion call |
| 986 |
* has been moved into this function. |
| 987 |
*/ |
| 988 |
hv_rf_on_receive(device, net_vsc_pkt); |
| 989 |
|
| 990 |
/* |
| 991 |
* Moved completion call back here so that all received |
| 992 |
* messages (not just data messages) will trigger a response |
| 993 |
* message back to the host. |
| 994 |
*/ |
| 995 |
hv_nv_on_receive_completion(net_vsc_pkt); |
| 912 |
} |
996 |
} |
| 913 |
|
|
|
| 914 |
/* |
| 915 |
* Moved completion call back here so that all received |
| 916 |
* messages (not just data messages) will trigger a response |
| 917 |
* message back to the host. |
| 918 |
*/ |
| 919 |
hv_nv_on_receive_completion(device, vm_xfer_page_pkt->d.transaction_id, |
| 920 |
status); |
| 921 |
} |
997 |
} |
| 922 |
|
998 |
|
| 923 |
/* |
999 |
/* |
| 924 |
* Net VSC on receive completion |
1000 |
* Net VSC send receive completion |
| 925 |
* |
|
|
| 926 |
* Send a receive completion packet to RNDIS device (ie NetVsp) |
| 927 |
*/ |
1001 |
*/ |
| 928 |
void |
1002 |
static void |
| 929 |
hv_nv_on_receive_completion(struct hv_device *device, uint64_t tid, |
1003 |
hv_nv_send_receive_completion(struct hv_device *device, uint64_t tid) |
| 930 |
uint32_t status) |
|
|
| 931 |
{ |
1004 |
{ |
| 932 |
nvsp_msg rx_comp_msg; |
1005 |
nvsp_msg rx_comp_msg; |
| 933 |
int retries = 0; |
1006 |
int retries = 0; |
|
Lines 937-943
Link Here
|
| 937 |
|
1010 |
|
| 938 |
/* Pass in the status */ |
1011 |
/* Pass in the status */ |
| 939 |
rx_comp_msg.msgs.vers_1_msgs.send_rndis_pkt_complete.status = |
1012 |
rx_comp_msg.msgs.vers_1_msgs.send_rndis_pkt_complete.status = |
| 940 |
status; |
1013 |
nvsp_status_success; |
| 941 |
|
1014 |
|
| 942 |
retry_send_cmplt: |
1015 |
retry_send_cmplt: |
| 943 |
/* Send the completion */ |
1016 |
/* Send the completion */ |
|
Lines 958-984
Link Here
|
| 958 |
} |
1031 |
} |
| 959 |
|
1032 |
|
| 960 |
/* |
1033 |
/* |
|
|
1034 |
* Net VSC on receive completion |
| 1035 |
* |
| 1036 |
* Send a receive completion packet to RNDIS device (ie NetVsp) |
| 1037 |
*/ |
| 1038 |
void |
| 1039 |
hv_nv_on_receive_completion(void *context) |
| 1040 |
{ |
| 1041 |
netvsc_packet *packet = (netvsc_packet *)context; |
| 1042 |
struct hv_device *device = (struct hv_device *)packet->device; |
| 1043 |
netvsc_dev *net_dev; |
| 1044 |
uint64_t tid = 0; |
| 1045 |
boolean_t send_rx_completion = FALSE; |
| 1046 |
|
| 1047 |
/* |
| 1048 |
* Even though it seems logical to do a hv_nv_get_outbound_net_device() |
| 1049 |
* here to send out receive completion, we are using |
| 1050 |
* hv_nv_get_inbound_net_device() since we may have disabled |
| 1051 |
* outbound traffic already. |
| 1052 |
*/ |
| 1053 |
net_dev = hv_nv_get_inbound_net_device(device); |
| 1054 |
if (net_dev == NULL) |
| 1055 |
return; |
| 1056 |
|
| 1057 |
/* Overloading use of the lock. */ |
| 1058 |
mtx_lock_spin(&net_dev->rx_pkt_list_lock); |
| 1059 |
|
| 1060 |
packet->xfer_page_pkt->count--; |
| 1061 |
|
| 1062 |
/* |
| 1063 |
* Last one in the line that represent 1 xfer page packet. |
| 1064 |
* Return the xfer page packet itself to the free list. |
| 1065 |
*/ |
| 1066 |
if (packet->xfer_page_pkt->count == 0) { |
| 1067 |
send_rx_completion = TRUE; |
| 1068 |
tid = packet->compl.rx.rx_completion_tid; |
| 1069 |
STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, |
| 1070 |
(netvsc_packet *)(packet->xfer_page_pkt), mylist_entry); |
| 1071 |
} |
| 1072 |
|
| 1073 |
/* Put the packet back on the free list */ |
| 1074 |
STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, packet, mylist_entry); |
| 1075 |
mtx_unlock_spin(&net_dev->rx_pkt_list_lock); |
| 1076 |
|
| 1077 |
/* Send a receive completion for the xfer page packet */ |
| 1078 |
if (send_rx_completion) |
| 1079 |
hv_nv_send_receive_completion(device, tid); |
| 1080 |
} |
| 1081 |
|
| 1082 |
/* |
| 961 |
* Net VSC on channel callback |
1083 |
* Net VSC on channel callback |
| 962 |
*/ |
1084 |
*/ |
| 963 |
static void |
1085 |
static void |
| 964 |
hv_nv_on_channel_callback(void *context) |
1086 |
hv_nv_on_channel_callback(void *context) |
| 965 |
{ |
1087 |
{ |
|
|
1088 |
/* Fixme: Magic number */ |
| 1089 |
const int net_pkt_size = 2048; |
| 966 |
struct hv_device *device = (struct hv_device *)context; |
1090 |
struct hv_device *device = (struct hv_device *)context; |
| 967 |
netvsc_dev *net_dev; |
1091 |
netvsc_dev *net_dev; |
| 968 |
device_t dev = device->device; |
|
|
| 969 |
uint32_t bytes_rxed; |
1092 |
uint32_t bytes_rxed; |
| 970 |
uint64_t request_id; |
1093 |
uint64_t request_id; |
| 971 |
hv_vm_packet_descriptor *desc; |
1094 |
uint8_t *packet; |
|
|
1095 |
hv_vm_packet_descriptor *desc; |
| 972 |
uint8_t *buffer; |
1096 |
uint8_t *buffer; |
| 973 |
int bufferlen = NETVSC_PACKET_SIZE; |
1097 |
int bufferlen = net_pkt_size; |
| 974 |
int ret = 0; |
1098 |
int ret = 0; |
| 975 |
|
1099 |
|
|
|
1100 |
packet = malloc(net_pkt_size * sizeof(uint8_t), M_DEVBUF, M_NOWAIT); |
| 1101 |
if (!packet) |
| 1102 |
return; |
| 1103 |
|
| 1104 |
buffer = packet; |
| 1105 |
|
| 976 |
net_dev = hv_nv_get_inbound_net_device(device); |
1106 |
net_dev = hv_nv_get_inbound_net_device(device); |
| 977 |
if (net_dev == NULL) |
1107 |
if (net_dev == NULL) |
| 978 |
return; |
1108 |
goto out; |
| 979 |
|
1109 |
|
| 980 |
buffer = net_dev->callback_buf; |
|
|
| 981 |
|
| 982 |
do { |
1110 |
do { |
| 983 |
ret = hv_vmbus_channel_recv_packet_raw(device->channel, |
1111 |
ret = hv_vmbus_channel_recv_packet_raw(device->channel, |
| 984 |
buffer, bufferlen, &bytes_rxed, &request_id); |
1112 |
buffer, bufferlen, &bytes_rxed, &request_id); |
|
Lines 987-1001
Link Here
|
| 987 |
desc = (hv_vm_packet_descriptor *)buffer; |
1115 |
desc = (hv_vm_packet_descriptor *)buffer; |
| 988 |
switch (desc->type) { |
1116 |
switch (desc->type) { |
| 989 |
case HV_VMBUS_PACKET_TYPE_COMPLETION: |
1117 |
case HV_VMBUS_PACKET_TYPE_COMPLETION: |
| 990 |
hv_nv_on_send_completion(net_dev, device, desc); |
1118 |
hv_nv_on_send_completion(device, desc); |
| 991 |
break; |
1119 |
break; |
| 992 |
case HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES: |
1120 |
case HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES: |
| 993 |
hv_nv_on_receive(net_dev, device, desc); |
1121 |
hv_nv_on_receive(device, desc); |
| 994 |
break; |
1122 |
break; |
| 995 |
default: |
1123 |
default: |
| 996 |
device_printf(dev, |
|
|
| 997 |
"hv_cb recv unknow type %d " |
| 998 |
" packet\n", desc->type); |
| 999 |
break; |
1124 |
break; |
| 1000 |
} |
1125 |
} |
| 1001 |
} else { |
1126 |
} else { |
|
Lines 1003-1020
Link Here
|
| 1003 |
} |
1128 |
} |
| 1004 |
} else if (ret == ENOBUFS) { |
1129 |
} else if (ret == ENOBUFS) { |
| 1005 |
/* Handle large packet */ |
1130 |
/* Handle large packet */ |
| 1006 |
if (bufferlen > NETVSC_PACKET_SIZE) { |
1131 |
free(buffer, M_DEVBUF); |
| 1007 |
free(buffer, M_NETVSC); |
1132 |
buffer = malloc(bytes_rxed, M_DEVBUF, M_NOWAIT); |
| 1008 |
buffer = NULL; |
|
|
| 1009 |
} |
| 1010 |
|
| 1011 |
/* alloc new buffer */ |
| 1012 |
buffer = malloc(bytes_rxed, M_NETVSC, M_NOWAIT); |
| 1013 |
if (buffer == NULL) { |
1133 |
if (buffer == NULL) { |
| 1014 |
device_printf(dev, |
|
|
| 1015 |
"hv_cb malloc buffer failed, len=%u\n", |
| 1016 |
bytes_rxed); |
| 1017 |
bufferlen = 0; |
| 1018 |
break; |
1134 |
break; |
| 1019 |
} |
1135 |
} |
| 1020 |
bufferlen = bytes_rxed; |
1136 |
bufferlen = bytes_rxed; |
|
Lines 1021-1026
Link Here
|
| 1021 |
} |
1137 |
} |
| 1022 |
} while (1); |
1138 |
} while (1); |
| 1023 |
|
1139 |
|
| 1024 |
if (bufferlen > NETVSC_PACKET_SIZE) |
1140 |
out: |
| 1025 |
free(buffer, M_NETVSC); |
1141 |
free(buffer, M_DEVBUF); |
| 1026 |
} |
1142 |
} |
|
|
1143 |
|