svn commit: r285236 - in stable/10/sys/dev/hyperv: include netvsc
Wei Hu
whu at FreeBSD.org
Tue Jul 7 04:15:24 UTC 2015
Author: whu
Date: Tue Jul 7 04:15:22 2015
New Revision: 285236
URL: https://svnweb.freebsd.org/changeset/base/285236
Log:
MFC r284746 and r284889 TSO and checksum offloading support for Netvsc
driver on Hyper-V.
Submitted by: whu
Reviewed by: royger
Approved by: re
Relnotes: yes
Sponsored by: Microsoft OSTC
Differential Revision: https://reviews.freebsd.org/D2906
Modified:
stable/10/sys/dev/hyperv/include/hyperv.h
stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
stable/10/sys/dev/hyperv/netvsc/hv_rndis.h
stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.h
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/sys/dev/hyperv/include/hyperv.h
==============================================================================
--- stable/10/sys/dev/hyperv/include/hyperv.h Tue Jul 7 04:09:35 2015 (r285235)
+++ stable/10/sys/dev/hyperv/include/hyperv.h Tue Jul 7 04:15:22 2015 (r285236)
@@ -107,7 +107,7 @@ typedef uint8_t hv_bool_uint8_t;
#define HV_MAX_PIPE_USER_DEFINED_BYTES 116
-#define HV_MAX_PAGE_BUFFER_COUNT 16
+#define HV_MAX_PAGE_BUFFER_COUNT 32
#define HV_MAX_MULTIPAGE_BUFFER_COUNT 32
#define HV_ALIGN_UP(value, align) \
Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c Tue Jul 7 04:09:35 2015 (r285235)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c Tue Jul 7 04:15:22 2015 (r285236)
@@ -48,6 +48,7 @@
#include "hv_rndis.h"
#include "hv_rndis_filter.h"
+MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver");
/*
* Forward declarations
@@ -58,13 +59,10 @@ static int hv_nv_init_rx_buffer_with_ne
static int hv_nv_destroy_send_buffer(netvsc_dev *net_dev);
static int hv_nv_destroy_rx_buffer(netvsc_dev *net_dev);
static int hv_nv_connect_to_vsp(struct hv_device *device);
-static void hv_nv_on_send_completion(struct hv_device *device,
- hv_vm_packet_descriptor *pkt);
-static void hv_nv_on_receive(struct hv_device *device,
- hv_vm_packet_descriptor *pkt);
-static void hv_nv_send_receive_completion(struct hv_device *device,
- uint64_t tid);
-
+static void hv_nv_on_send_completion(netvsc_dev *net_dev,
+ struct hv_device *device, hv_vm_packet_descriptor *pkt);
+static void hv_nv_on_receive(netvsc_dev *net_dev,
+ struct hv_device *device, hv_vm_packet_descriptor *pkt);
/*
*
@@ -75,7 +73,7 @@ hv_nv_alloc_net_device(struct hv_device
netvsc_dev *net_dev;
hn_softc_t *sc = device_get_softc(device->device);
- net_dev = malloc(sizeof(netvsc_dev), M_DEVBUF, M_NOWAIT | M_ZERO);
+ net_dev = malloc(sizeof(netvsc_dev), M_NETVSC, M_NOWAIT | M_ZERO);
if (net_dev == NULL) {
return (NULL);
}
@@ -127,6 +125,34 @@ hv_nv_get_inbound_net_device(struct hv_d
return (net_dev);
}
+int
+hv_nv_get_next_send_section(netvsc_dev *net_dev)
+{
+ unsigned long bitsmap_words = net_dev->bitsmap_words;
+ unsigned long *bitsmap = net_dev->send_section_bitsmap;
+ unsigned long idx;
+ int ret = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
+ int i;
+
+ for (i = 0; i < bitsmap_words; i++) {
+ idx = ffs(~bitsmap[i]);
+ if (0 == idx)
+ continue;
+
+ idx--;
+ if (i * BITS_PER_LONG + idx >= net_dev->send_section_count)
+ return (ret);
+
+ if (synch_test_and_set_bit(idx, &bitsmap[i]))
+ continue;
+
+ ret = i * BITS_PER_LONG + idx;
+ break;
+ }
+
+ return (ret);
+}
+
/*
* Net VSC initialize receive buffer with net VSP
*
@@ -145,12 +171,8 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
return (ENODEV);
}
- net_dev->rx_buf = contigmalloc(net_dev->rx_buf_size, M_DEVBUF,
+ net_dev->rx_buf = contigmalloc(net_dev->rx_buf_size, M_NETVSC,
M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
- if (net_dev->rx_buf == NULL) {
- ret = ENOMEM;
- goto cleanup;
- }
/*
* Establish the GPADL handle for this buffer on this channel.
@@ -201,7 +223,7 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.num_sections;
net_dev->rx_sections = malloc(net_dev->rx_section_count *
- sizeof(nvsp_1_rx_buf_section), M_DEVBUF, M_NOWAIT);
+ sizeof(nvsp_1_rx_buf_section), M_NETVSC, M_NOWAIT);
if (net_dev->rx_sections == NULL) {
ret = EINVAL;
goto cleanup;
@@ -245,7 +267,7 @@ hv_nv_init_send_buffer_with_net_vsp(stru
return (ENODEV);
}
- net_dev->send_buf = contigmalloc(net_dev->send_buf_size, M_DEVBUF,
+ net_dev->send_buf = contigmalloc(net_dev->send_buf_size, M_NETVSC,
M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
if (net_dev->send_buf == NULL) {
ret = ENOMEM;
@@ -258,7 +280,7 @@ hv_nv_init_send_buffer_with_net_vsp(stru
* channel to establish the gpadl handle.
*/
ret = hv_vmbus_channel_establish_gpadl(device->channel,
- net_dev->send_buf, net_dev->send_buf_size,
+ net_dev->send_buf, net_dev->send_buf_size,
&net_dev->send_buf_gpadl_handle);
if (ret != 0) {
goto cleanup;
@@ -279,7 +301,7 @@ hv_nv_init_send_buffer_with_net_vsp(stru
/* Send the gpadl notification request */
ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
- sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
+ sizeof(nvsp_msg), (uint64_t)init_pkt,
HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
@@ -297,6 +319,17 @@ hv_nv_init_send_buffer_with_net_vsp(stru
net_dev->send_section_size =
init_pkt->msgs.vers_1_msgs.send_send_buf_complete.section_size;
+ net_dev->send_section_count =
+ net_dev->send_buf_size / net_dev->send_section_size;
+ net_dev->bitsmap_words = howmany(net_dev->send_section_count,
+ BITS_PER_LONG);
+ net_dev->send_section_bitsmap =
+ malloc(net_dev->bitsmap_words * sizeof(long), M_NETVSC,
+ M_NOWAIT | M_ZERO);
+ if (NULL == net_dev->send_section_bitsmap) {
+ ret = ENOMEM;
+ goto cleanup;
+ }
goto exit;
@@ -361,12 +394,12 @@ hv_nv_destroy_rx_buffer(netvsc_dev *net_
if (net_dev->rx_buf) {
/* Free up the receive buffer */
- contigfree(net_dev->rx_buf, net_dev->rx_buf_size, M_DEVBUF);
+ contigfree(net_dev->rx_buf, net_dev->rx_buf_size, M_NETVSC);
net_dev->rx_buf = NULL;
}
if (net_dev->rx_sections) {
- free(net_dev->rx_sections, M_DEVBUF);
+ free(net_dev->rx_sections, M_NETVSC);
net_dev->rx_sections = NULL;
net_dev->rx_section_count = 0;
}
@@ -429,10 +462,14 @@ hv_nv_destroy_send_buffer(netvsc_dev *ne
if (net_dev->send_buf) {
/* Free up the receive buffer */
- contigfree(net_dev->send_buf, net_dev->send_buf_size, M_DEVBUF);
+ contigfree(net_dev->send_buf, net_dev->send_buf_size, M_NETVSC);
net_dev->send_buf = NULL;
}
+ if (net_dev->send_section_bitsmap) {
+ free(net_dev->send_section_bitsmap, M_NETVSC);
+ }
+
return (ret);
}
@@ -446,7 +483,7 @@ hv_nv_destroy_send_buffer(netvsc_dev *ne
*/
static int
hv_nv_negotiate_nvsp_protocol(struct hv_device *device, netvsc_dev *net_dev,
- uint32_t nvsp_ver)
+ uint32_t nvsp_ver)
{
nvsp_msg *init_pkt;
int ret;
@@ -523,8 +560,13 @@ hv_nv_connect_to_vsp(struct hv_device *d
{
netvsc_dev *net_dev;
nvsp_msg *init_pkt;
- uint32_t nvsp_vers;
uint32_t ndis_version;
+ uint32_t protocol_list[] = { NVSP_PROTOCOL_VERSION_1,
+ NVSP_PROTOCOL_VERSION_2,
+ NVSP_PROTOCOL_VERSION_4,
+ NVSP_PROTOCOL_VERSION_5 };
+ int i;
+ int protocol_number = nitems(protocol_list);
int ret = 0;
device_t dev = device->device;
hn_softc_t *sc = device_get_softc(dev);
@@ -536,26 +578,31 @@ hv_nv_connect_to_vsp(struct hv_device *d
}
/*
- * Negotiate the NVSP version. Try NVSP v2 first.
+ * Negotiate the NVSP version. Try the latest NVSP first.
*/
- nvsp_vers = NVSP_PROTOCOL_VERSION_2;
- ret = hv_nv_negotiate_nvsp_protocol(device, net_dev, nvsp_vers);
- if (ret != 0) {
- /* NVSP v2 failed, try NVSP v1 */
- nvsp_vers = NVSP_PROTOCOL_VERSION_1;
- ret = hv_nv_negotiate_nvsp_protocol(device, net_dev, nvsp_vers);
- if (ret != 0) {
- /* NVSP v1 failed, return bad status */
- return (ret);
+ for (i = protocol_number - 1; i >= 0; i--) {
+ if (hv_nv_negotiate_nvsp_protocol(device, net_dev,
+ protocol_list[i]) == 0) {
+ net_dev->nvsp_version = protocol_list[i];
+ if (bootverbose)
+ device_printf(dev, "Netvsc: got version 0x%x\n",
+ net_dev->nvsp_version);
+ break;
}
}
- net_dev->nvsp_version = nvsp_vers;
+
+ if (i < 0) {
+ if (bootverbose)
+ device_printf(dev, "failed to negotiate a valid "
+ "protocol.\n");
+ return (EPROTO);
+ }
/*
* Set the MTU if supported by this NVSP protocol version
* This needs to be right after the NVSP init message per Haiyang
*/
- if (nvsp_vers >= NVSP_PROTOCOL_VERSION_2)
+ if (net_dev->nvsp_version >= NVSP_PROTOCOL_VERSION_2)
ret = hv_nv_send_ndis_config(device, ifp->if_mtu);
/*
@@ -565,10 +612,11 @@ hv_nv_connect_to_vsp(struct hv_device *d
memset(init_pkt, 0, sizeof(nvsp_msg));
- /*
- * Updated to version 5.1, minimum, for VLAN per Haiyang
- */
- ndis_version = NDIS_VERSION;
+ if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_4) {
+ ndis_version = NDIS_VERSION_6_1;
+ } else {
+ ndis_version = NDIS_VERSION_6_30;
+ }
init_pkt->hdr.msg_type = nvsp_msg_1_type_send_ndis_vers;
init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_major_vers =
@@ -620,9 +668,7 @@ netvsc_dev *
hv_nv_on_device_add(struct hv_device *device, void *additional_info)
{
netvsc_dev *net_dev;
- netvsc_packet *packet;
- netvsc_packet *next_packet;
- int i, ret = 0;
+ int ret = 0;
net_dev = hv_nv_alloc_net_device(device);
if (!net_dev)
@@ -630,29 +676,9 @@ hv_nv_on_device_add(struct hv_device *de
/* Initialize the NetVSC channel extension */
net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
- mtx_init(&net_dev->rx_pkt_list_lock, "HV-RPL", NULL,
- MTX_SPIN | MTX_RECURSE);
net_dev->send_buf_size = NETVSC_SEND_BUFFER_SIZE;
- /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
- STAILQ_INIT(&net_dev->myrx_packet_list);
-
- /*
- * malloc a sufficient number of netvsc_packet buffers to hold
- * a packet list. Add them to the netvsc device packet queue.
- */
- for (i=0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) {
- packet = malloc(sizeof(netvsc_packet) +
- (NETVSC_RECEIVE_SG_COUNT * sizeof(hv_vmbus_page_buffer)),
- M_DEVBUF, M_NOWAIT | M_ZERO);
- if (!packet) {
- break;
- }
- STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, packet,
- mylist_entry);
- }
-
sema_init(&net_dev->channel_init_sema, 0, "netdev_sema");
/*
@@ -685,19 +711,7 @@ cleanup:
*/
if (net_dev) {
sema_destroy(&net_dev->channel_init_sema);
-
- packet = STAILQ_FIRST(&net_dev->myrx_packet_list);
- while (packet != NULL) {
- next_packet = STAILQ_NEXT(packet, mylist_entry);
- free(packet, M_DEVBUF);
- packet = next_packet;
- }
- /* Reset the list to initial state */
- STAILQ_INIT(&net_dev->myrx_packet_list);
-
- mtx_destroy(&net_dev->rx_pkt_list_lock);
-
- free(net_dev, M_DEVBUF);
+ free(net_dev, M_NETVSC);
}
return (NULL);
@@ -709,8 +723,6 @@ cleanup:
int
hv_nv_on_device_remove(struct hv_device *device, boolean_t destroy_channel)
{
- netvsc_packet *net_vsc_pkt;
- netvsc_packet *next_net_vsc_pkt;
hn_softc_t *sc = device_get_softc(device->device);
netvsc_dev *net_dev = sc->net_dev;;
@@ -737,20 +749,8 @@ hv_nv_on_device_remove(struct hv_device
hv_vmbus_channel_close(device->channel);
- /* Release all resources */
- net_vsc_pkt = STAILQ_FIRST(&net_dev->myrx_packet_list);
- while (net_vsc_pkt != NULL) {
- next_net_vsc_pkt = STAILQ_NEXT(net_vsc_pkt, mylist_entry);
- free(net_vsc_pkt, M_DEVBUF);
- net_vsc_pkt = next_net_vsc_pkt;
- }
-
- /* Reset the list to initial state */
- STAILQ_INIT(&net_dev->myrx_packet_list);
-
- mtx_destroy(&net_dev->rx_pkt_list_lock);
sema_destroy(&net_dev->channel_init_sema);
- free(net_dev, M_DEVBUF);
+ free(net_dev, M_NETVSC);
return (0);
}
@@ -758,18 +758,13 @@ hv_nv_on_device_remove(struct hv_device
/*
* Net VSC on send completion
*/
-static void
-hv_nv_on_send_completion(struct hv_device *device, hv_vm_packet_descriptor *pkt)
+static void
+hv_nv_on_send_completion(netvsc_dev *net_dev,
+ struct hv_device *device, hv_vm_packet_descriptor *pkt)
{
- netvsc_dev *net_dev;
nvsp_msg *nvsp_msg_pkt;
netvsc_packet *net_vsc_pkt;
- net_dev = hv_nv_get_inbound_net_device(device);
- if (!net_dev) {
- return;
- }
-
nvsp_msg_pkt =
(nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3));
@@ -780,17 +775,25 @@ hv_nv_on_send_completion(struct hv_devic
== nvsp_msg_1_type_send_send_buf_complete) {
/* Copy the response back */
memcpy(&net_dev->channel_init_packet, nvsp_msg_pkt,
- sizeof(nvsp_msg));
+ sizeof(nvsp_msg));
sema_post(&net_dev->channel_init_sema);
} else if (nvsp_msg_pkt->hdr.msg_type ==
- nvsp_msg_1_type_send_rndis_pkt_complete) {
+ nvsp_msg_1_type_send_rndis_pkt_complete) {
/* Get the send context */
net_vsc_pkt =
(netvsc_packet *)(unsigned long)pkt->transaction_id;
+ if (NULL != net_vsc_pkt) {
+ if (net_vsc_pkt->send_buf_section_idx !=
+ NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) {
+ synch_change_bit(net_vsc_pkt->send_buf_section_idx,
+ net_dev->send_section_bitsmap);
+ }
+
+ /* Notify the layer above us */
+ net_vsc_pkt->compl.send.on_send_completion(
+ net_vsc_pkt->compl.send.send_completion_context);
- /* Notify the layer above us */
- net_vsc_pkt->compl.send.on_send_completion(
- net_vsc_pkt->compl.send.send_completion_context);
+ }
atomic_subtract_int(&net_dev->num_outstanding_sends, 1);
}
@@ -821,10 +824,10 @@ hv_nv_on_send(struct hv_device *device,
send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 1;
}
- /* Not using send buffer section */
send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx =
- 0xFFFFFFFF;
- send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size = 0;
+ pkt->send_buf_section_idx;
+ send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size =
+ pkt->send_buf_section_size;
if (pkt->page_buf_count) {
ret = hv_vmbus_channel_send_packet_pagebuffer(device->channel,
@@ -850,157 +853,81 @@ hv_nv_on_send(struct hv_device *device,
* In the FreeBSD Hyper-V virtual world, this function deals exclusively
* with virtual addresses.
*/
-static void
-hv_nv_on_receive(struct hv_device *device, hv_vm_packet_descriptor *pkt)
+static void
+hv_nv_on_receive(netvsc_dev *net_dev, struct hv_device *device,
+ hv_vm_packet_descriptor *pkt)
{
- netvsc_dev *net_dev;
hv_vm_transfer_page_packet_header *vm_xfer_page_pkt;
nvsp_msg *nvsp_msg_pkt;
- netvsc_packet *net_vsc_pkt = NULL;
- unsigned long start;
- xfer_page_packet *xfer_page_pkt = NULL;
- STAILQ_HEAD(PKT_LIST, netvsc_packet_) mylist_head =
- STAILQ_HEAD_INITIALIZER(mylist_head);
+ netvsc_packet vsc_pkt;
+ netvsc_packet *net_vsc_pkt = &vsc_pkt;
+ device_t dev = device->device;
int count = 0;
int i = 0;
-
- net_dev = hv_nv_get_inbound_net_device(device);
- if (!net_dev)
- return;
+ int status = nvsp_status_success;
/*
* All inbound packets other than send completion should be
* xfer page packet.
*/
- if (pkt->type != HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES)
+ if (pkt->type != HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES) {
+ device_printf(dev, "packet type %d is invalid!\n", pkt->type);
return;
+ }
nvsp_msg_pkt = (nvsp_msg *)((unsigned long)pkt
+ (pkt->data_offset8 << 3));
/* Make sure this is a valid nvsp packet */
- if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt)
+ if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt) {
+ device_printf(dev, "packet hdr type %d is invalid!\n",
+ pkt->type);
return;
+ }
vm_xfer_page_pkt = (hv_vm_transfer_page_packet_header *)pkt;
- if (vm_xfer_page_pkt->transfer_page_set_id
- != NETVSC_RECEIVE_BUFFER_ID) {
+ if (vm_xfer_page_pkt->transfer_page_set_id !=
+ NETVSC_RECEIVE_BUFFER_ID) {
+ device_printf(dev, "transfer_page_set_id %d is invalid!\n",
+ vm_xfer_page_pkt->transfer_page_set_id);
return;
}
- STAILQ_INIT(&mylist_head);
-
- /*
- * Grab free packets (range count + 1) to represent this xfer page
- * packet. +1 to represent the xfer page packet itself. We grab it
- * here so that we know exactly how many we can fulfill.
- */
- mtx_lock_spin(&net_dev->rx_pkt_list_lock);
- while (!STAILQ_EMPTY(&net_dev->myrx_packet_list)) {
- net_vsc_pkt = STAILQ_FIRST(&net_dev->myrx_packet_list);
- STAILQ_REMOVE_HEAD(&net_dev->myrx_packet_list, mylist_entry);
-
- STAILQ_INSERT_TAIL(&mylist_head, net_vsc_pkt, mylist_entry);
-
- if (++count == vm_xfer_page_pkt->range_count + 1)
- break;
- }
-
- mtx_unlock_spin(&net_dev->rx_pkt_list_lock);
-
- /*
- * We need at least 2 netvsc pkts (1 to represent the xfer page
- * and at least 1 for the range) i.e. we can handle some of the
- * xfer page packet ranges...
- */
- if (count < 2) {
- /* Return netvsc packet to the freelist */
- mtx_lock_spin(&net_dev->rx_pkt_list_lock);
- for (i=count; i != 0; i--) {
- net_vsc_pkt = STAILQ_FIRST(&mylist_head);
- STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry);
-
- STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list,
- net_vsc_pkt, mylist_entry);
- }
- mtx_unlock_spin(&net_dev->rx_pkt_list_lock);
-
- hv_nv_send_receive_completion(device,
- vm_xfer_page_pkt->d.transaction_id);
-
- return;
- }
-
- /* Take the first packet in the list */
- xfer_page_pkt = (xfer_page_packet *)STAILQ_FIRST(&mylist_head);
- STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry);
-
- /* This is how many data packets we can supply */
- xfer_page_pkt->count = count - 1;
+ count = vm_xfer_page_pkt->range_count;
+ net_vsc_pkt->device = device;
/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
- for (i=0; i < (count - 1); i++) {
- net_vsc_pkt = STAILQ_FIRST(&mylist_head);
- STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry);
-
- /*
- * Initialize the netvsc packet
- */
- net_vsc_pkt->xfer_page_pkt = xfer_page_pkt;
- net_vsc_pkt->compl.rx.rx_completion_context = net_vsc_pkt;
- net_vsc_pkt->device = device;
- /* Save this so that we can send it back */
- net_vsc_pkt->compl.rx.rx_completion_tid =
- vm_xfer_page_pkt->d.transaction_id;
-
- net_vsc_pkt->tot_data_buf_len =
- vm_xfer_page_pkt->ranges[i].byte_count;
- net_vsc_pkt->page_buf_count = 1;
-
- net_vsc_pkt->page_buffers[0].length =
- vm_xfer_page_pkt->ranges[i].byte_count;
-
- /* The virtual address of the packet in the receive buffer */
- start = ((unsigned long)net_dev->rx_buf +
+ for (i = 0; i < count; i++) {
+ net_vsc_pkt->status = nvsp_status_success;
+ net_vsc_pkt->data = (void *)((unsigned long)net_dev->rx_buf +
vm_xfer_page_pkt->ranges[i].byte_offset);
- start = ((unsigned long)start) & ~(PAGE_SIZE - 1);
-
- /* Page number of the virtual page containing packet start */
- net_vsc_pkt->page_buffers[0].pfn = start >> PAGE_SHIFT;
-
- /* Calculate the page relative offset */
- net_vsc_pkt->page_buffers[0].offset =
- vm_xfer_page_pkt->ranges[i].byte_offset & (PAGE_SIZE - 1);
-
- /*
- * In this implementation, we are dealing with virtual
- * addresses exclusively. Since we aren't using physical
- * addresses at all, we don't care if a packet crosses a
- * page boundary. For this reason, the original code to
- * check for and handle page crossings has been removed.
- */
-
- /*
- * Pass it to the upper layer. The receive completion call
- * has been moved into this function.
- */
- hv_rf_on_receive(device, net_vsc_pkt);
+ net_vsc_pkt->tot_data_buf_len =
+ vm_xfer_page_pkt->ranges[i].byte_count;
- /*
- * Moved completion call back here so that all received
- * messages (not just data messages) will trigger a response
- * message back to the host.
- */
- hv_nv_on_receive_completion(net_vsc_pkt);
+ hv_rf_on_receive(net_dev, device, net_vsc_pkt);
+ if (net_vsc_pkt->status != nvsp_status_success) {
+ status = nvsp_status_failure;
+ }
}
+
+ /*
+ * Moved completion call back here so that all received
+ * messages (not just data messages) will trigger a response
+ * message back to the host.
+ */
+ hv_nv_on_receive_completion(device, vm_xfer_page_pkt->d.transaction_id,
+ status);
}
/*
- * Net VSC send receive completion
+ * Net VSC on receive completion
+ *
+ * Send a receive completion packet to RNDIS device (ie NetVsp)
*/
-static void
-hv_nv_send_receive_completion(struct hv_device *device, uint64_t tid)
+void
+hv_nv_on_receive_completion(struct hv_device *device, uint64_t tid,
+ uint32_t status)
{
nvsp_msg rx_comp_msg;
int retries = 0;
@@ -1010,7 +937,7 @@ hv_nv_send_receive_completion(struct hv_
/* Pass in the status */
rx_comp_msg.msgs.vers_1_msgs.send_rndis_pkt_complete.status =
- nvsp_status_success;
+ status;
retry_send_cmplt:
/* Send the completion */
@@ -1031,81 +958,26 @@ retry_send_cmplt:
}
/*
- * Net VSC on receive completion
- *
- * Send a receive completion packet to RNDIS device (ie NetVsp)
- */
-void
-hv_nv_on_receive_completion(void *context)
-{
- netvsc_packet *packet = (netvsc_packet *)context;
- struct hv_device *device = (struct hv_device *)packet->device;
- netvsc_dev *net_dev;
- uint64_t tid = 0;
- boolean_t send_rx_completion = FALSE;
-
- /*
- * Even though it seems logical to do a hv_nv_get_outbound_net_device()
- * here to send out receive completion, we are using
- * hv_nv_get_inbound_net_device() since we may have disabled
- * outbound traffic already.
- */
- net_dev = hv_nv_get_inbound_net_device(device);
- if (net_dev == NULL)
- return;
-
- /* Overloading use of the lock. */
- mtx_lock_spin(&net_dev->rx_pkt_list_lock);
-
- packet->xfer_page_pkt->count--;
-
- /*
- * Last one in the line that represent 1 xfer page packet.
- * Return the xfer page packet itself to the free list.
- */
- if (packet->xfer_page_pkt->count == 0) {
- send_rx_completion = TRUE;
- tid = packet->compl.rx.rx_completion_tid;
- STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list,
- (netvsc_packet *)(packet->xfer_page_pkt), mylist_entry);
- }
-
- /* Put the packet back on the free list */
- STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, packet, mylist_entry);
- mtx_unlock_spin(&net_dev->rx_pkt_list_lock);
-
- /* Send a receive completion for the xfer page packet */
- if (send_rx_completion)
- hv_nv_send_receive_completion(device, tid);
-}
-
-/*
* Net VSC on channel callback
*/
static void
hv_nv_on_channel_callback(void *context)
{
- /* Fixme: Magic number */
- const int net_pkt_size = 2048;
struct hv_device *device = (struct hv_device *)context;
netvsc_dev *net_dev;
+ device_t dev = device->device;
uint32_t bytes_rxed;
uint64_t request_id;
- uint8_t *packet;
- hv_vm_packet_descriptor *desc;
+ hv_vm_packet_descriptor *desc;
uint8_t *buffer;
- int bufferlen = net_pkt_size;
- int ret = 0;
-
- packet = malloc(net_pkt_size * sizeof(uint8_t), M_DEVBUF, M_NOWAIT);
- if (!packet)
- return;
-
- buffer = packet;
+ int bufferlen = NETVSC_PACKET_SIZE;
+ int ret = 0;
net_dev = hv_nv_get_inbound_net_device(device);
if (net_dev == NULL)
- goto out;
+ return;
+
+ buffer = net_dev->callback_buf;
do {
ret = hv_vmbus_channel_recv_packet_raw(device->channel,
@@ -1115,12 +987,15 @@ hv_nv_on_channel_callback(void *context)
desc = (hv_vm_packet_descriptor *)buffer;
switch (desc->type) {
case HV_VMBUS_PACKET_TYPE_COMPLETION:
- hv_nv_on_send_completion(device, desc);
+ hv_nv_on_send_completion(net_dev, device, desc);
break;
case HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES:
- hv_nv_on_receive(device, desc);
+ hv_nv_on_receive(net_dev, device, desc);
break;
default:
+ device_printf(dev,
+ "hv_cb recv unknow type %d "
+ " packet\n", desc->type);
break;
}
} else {
@@ -1128,16 +1003,24 @@ hv_nv_on_channel_callback(void *context)
}
} else if (ret == ENOBUFS) {
/* Handle large packet */
- free(buffer, M_DEVBUF);
- buffer = malloc(bytes_rxed, M_DEVBUF, M_NOWAIT);
+ if (bufferlen > NETVSC_PACKET_SIZE) {
+ free(buffer, M_NETVSC);
+ buffer = NULL;
+ }
+
+ /* alloc new buffer */
+ buffer = malloc(bytes_rxed, M_NETVSC, M_NOWAIT);
if (buffer == NULL) {
+ device_printf(dev,
+ "hv_cb malloc buffer failed, len=%u\n",
+ bytes_rxed);
+ bufferlen = 0;
break;
}
bufferlen = bytes_rxed;
}
} while (1);
-out:
- free(buffer, M_DEVBUF);
+ if (bufferlen > NETVSC_PACKET_SIZE)
+ free(buffer, M_NETVSC);
}
-
Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h Tue Jul 7 04:09:35 2015 (r285235)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h Tue Jul 7 04:15:22 2015 (r285236)
@@ -41,20 +41,26 @@
#include <sys/types.h>
#include <sys/param.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/sx.h>
#include <dev/hyperv/include/hyperv.h>
+MALLOC_DECLARE(M_NETVSC);
#define NVSP_INVALID_PROTOCOL_VERSION (0xFFFFFFFF)
#define NVSP_PROTOCOL_VERSION_1 2
#define NVSP_PROTOCOL_VERSION_2 0x30002
+#define NVSP_PROTOCOL_VERSION_4 0x40000
+#define NVSP_PROTOCOL_VERSION_5 0x50000
#define NVSP_MIN_PROTOCOL_VERSION (NVSP_PROTOCOL_VERSION_1)
#define NVSP_MAX_PROTOCOL_VERSION (NVSP_PROTOCOL_VERSION_2)
#define NVSP_PROTOCOL_VERSION_CURRENT NVSP_PROTOCOL_VERSION_2
+#define VERSION_4_OFFLOAD_SIZE 22
+
#define NVSP_OPERATIONAL_STATUS_OK (0x00000000)
#define NVSP_OPERATIONAL_STATUS_DEGRADED (0x00000001)
#define NVSP_OPERATIONAL_STATUS_NONRECOVERABLE (0x00000002)
@@ -544,7 +550,7 @@ typedef struct nvsp_2_msg_indicate_chimn
#define NVSP_1_CHIMNEY_SEND_INVALID_OOB_INDEX 0xffffu
-#define NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX 0xffffu
+#define NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX 0xffffffff
/*
* NvspMessage2TypeSendChimneyPacket
@@ -842,11 +848,11 @@ typedef struct nvsp_msg_ {
* Defines
*/
-#define NETVSC_SEND_BUFFER_SIZE (64*1024) /* 64K */
+#define NETVSC_SEND_BUFFER_SIZE (1024*1024*15) /* 15M */
#define NETVSC_SEND_BUFFER_ID 0xface
-#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024) /* 1MB */
+#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */
#define NETVSC_RECEIVE_BUFFER_ID 0xcafe
@@ -862,6 +868,8 @@ typedef struct nvsp_msg_ {
*/
#define NETVSC_MAX_CONFIGURABLE_MTU (9 * 1024)
+#define NETVSC_PACKET_SIZE PAGE_SIZE
+
/*
* Data types
*/
@@ -873,15 +881,14 @@ typedef struct netvsc_dev_ {
struct hv_device *dev;
int num_outstanding_sends;
- /* List of free preallocated NETVSC_PACKET to represent RX packet */
- STAILQ_HEAD(PQ, netvsc_packet_) myrx_packet_list;
- struct mtx rx_pkt_list_lock;
-
/* Send buffer allocated by us but manages by NetVSP */
void *send_buf;
uint32_t send_buf_size;
uint32_t send_buf_gpadl_handle;
uint32_t send_section_size;
+ uint32_t send_section_count;
+ unsigned long bitsmap_words;
+ unsigned long *send_section_bitsmap;
/* Receive buffer allocated by us but managed by NetVSP */
void *rx_buf;
@@ -903,35 +910,43 @@ typedef struct netvsc_dev_ {
hv_bool_uint8_t destroy;
/* Negotiated NVSP version */
uint32_t nvsp_version;
+
+ uint8_t callback_buf[NETVSC_PACKET_SIZE];
} netvsc_dev;
typedef void (*pfn_on_send_rx_completion)(void *);
-#define NETVSC_DEVICE_RING_BUFFER_SIZE (64 * PAGE_SIZE)
-#define NETVSC_PACKET_MAXPAGE 16
-
+#define NETVSC_DEVICE_RING_BUFFER_SIZE (128 * PAGE_SIZE)
+#define NETVSC_PACKET_MAXPAGE 32
-typedef struct xfer_page_packet_ {
- /*
- * This needs to be here because the network RX code casts
- * an instantiation of this structure to a netvsc_packet.
- */
- STAILQ_ENTRY(netvsc_packet_) mylist_entry;
- uint32_t count;
-} xfer_page_packet;
+#define NETVSC_VLAN_PRIO_MASK 0xe000
+#define NETVSC_VLAN_PRIO_SHIFT 13
+#define NETVSC_VLAN_VID_MASK 0x0fff
+
+#define TYPE_IPV4 2
+#define TYPE_IPV6 4
+#define TYPE_TCP 2
+#define TYPE_UDP 4
+
+#define TRANSPORT_TYPE_NOT_IP 0
+#define TRANSPORT_TYPE_IPV4_TCP ((TYPE_IPV4 << 16) | TYPE_TCP)
+#define TRANSPORT_TYPE_IPV4_UDP ((TYPE_IPV4 << 16) | TYPE_UDP)
+#define TRANSPORT_TYPE_IPV6_TCP ((TYPE_IPV6 << 16) | TYPE_TCP)
+#define TRANSPORT_TYPE_IPV6_UDP ((TYPE_IPV6 << 16) | TYPE_UDP)
+
+#ifdef __LP64__
+#define BITS_PER_LONG 64
+#else
+#define BITS_PER_LONG 32
+#endif
typedef struct netvsc_packet_ {
- /*
- * List used when enqueued on &net_dev->rx_packet_list,
- * and when enqueued within the netvsc code
- */
- STAILQ_ENTRY(netvsc_packet_) mylist_entry;
struct hv_device *device;
hv_bool_uint8_t is_data_pkt; /* One byte */
uint16_t vlan_tci;
- xfer_page_packet *xfer_page_pkt;
+ uint32_t status;
/* Completion */
union {
@@ -948,9 +963,12 @@ typedef struct netvsc_packet_ {
pfn_on_send_rx_completion on_send_completion;
} send;
} compl;
+ uint32_t send_buf_section_idx;
+ uint32_t send_buf_section_size;
- void *extension;
+ void *rndis_mesg;
uint32_t tot_data_buf_len;
+ void *data;
uint32_t page_buf_count;
hv_vmbus_page_buffer page_buffers[NETVSC_PACKET_MAXPAGE];
} netvsc_packet;
@@ -984,16 +1002,16 @@ typedef struct hn_softc {
*/
extern int hv_promisc_mode;
-extern void netvsc_linkstatus_callback(struct hv_device *device_obj,
- uint32_t status);
-extern int netvsc_recv(struct hv_device *device_obj, netvsc_packet *packet);
-extern void netvsc_xmit_completion(void *context);
-
-extern void hv_nv_on_receive_completion(void *context);
-extern netvsc_dev *hv_nv_on_device_add(struct hv_device *device, void *additional_info);
-extern int hv_nv_on_device_remove(struct hv_device *device,
- boolean_t destroy_channel);
-extern int hv_nv_on_send(struct hv_device *device, netvsc_packet *pkt);
+void netvsc_linkstatus_callback(struct hv_device *device_obj, uint32_t status);
+void netvsc_xmit_completion(void *context);
+void hv_nv_on_receive_completion(struct hv_device *device,
+ uint64_t tid, uint32_t status);
+netvsc_dev *hv_nv_on_device_add(struct hv_device *device,
+ void *additional_info);
+int hv_nv_on_device_remove(struct hv_device *device,
+ boolean_t destroy_channel);
+int hv_nv_on_send(struct hv_device *device, netvsc_packet *pkt);
+int hv_nv_get_next_send_section(netvsc_dev *net_dev);
#endif /* __HV_NET_VSC_H__ */
Modified: stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c Tue Jul 7 04:09:35 2015 (r285235)
+++ stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c Tue Jul 7 04:15:22 2015 (r285236)
@@ -55,6 +55,9 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_inet6.h"
+#include "opt_inet.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sockio.h>
@@ -83,6 +86,9 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip6.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@@ -103,6 +109,8 @@ __FBSDID("$FreeBSD$");
#include <machine/intr_machdep.h>
+#include <machine/in_cksum.h>
+
#include <dev/hyperv/include/hyperv.h>
#include "hv_net_vsc.h"
#include "hv_rndis.h"
@@ -165,6 +173,61 @@ static int hn_ioctl(struct ifnet *ifp,
static int hn_start_locked(struct ifnet *ifp);
static void hn_start(struct ifnet *ifp);
+/*
+ * NetVsc get message transport protocol type
+ */
+static uint32_t get_transport_proto_type(struct mbuf *m_head)
+{
+ uint32_t ret_val = TRANSPORT_TYPE_NOT_IP;
+ uint16_t ether_type = 0;
+ int ether_len = 0;
+ struct ether_vlan_header *eh;
+#ifdef INET
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-stable-10
mailing list