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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to