Author: sephe
Date: Fri Oct 14 07:40:04 2016
New Revision: 307291
URL: https://svnweb.freebsd.org/changeset/base/307291

Log:
  MFC 302543-302545,302547,302549,302554,302556,302557,302559,302606
  
  302543
      hyperv/vmbus: Use post message Hypercall APIs for channel request
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6831
  
  302544
      hyperv/hn: Add tunable to allow tcp_lro_queue_mbuf()
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6841
  
  302545
      hyperv/vmbus: Function renaming.
  
      And pass vmbus_softc to vmbus_doattach()
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6842
  
  302547
      hyperv/vmbus: Explicitly assign channel message process array.
  
      While I'm here, remove the useless message type from message process
      array, which is not used and serves no purposes at all.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6858
  
  302549
      hyperv/vmbus: Add sysctl to expose vmbus version.
  
      Requested by:   Hongxiong Xian <v-hoxian microsoft com>
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6860
  
  302554
      hyperv/vmbus: Use post message Hypercall APIs for unload
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6861
  
  302556
      hyperv/vmbus: Create channel synchronously.
  
      The device probe/attach has been move to a different thread, so the
      reasons to create the channel asynchronously are no longer valid.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6862
  
  302557
      hyperv/vmbus: Save vmbus softc to channels.
  
      So that we don't need to access the global vmbus softc.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6863
  
  302559
      hyperv/vmbus: Embed channel detach task in channel itself.
  
      GC work queue stuffs.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6864
  
  302606
      hyperv/vmbus: Reorganize vmbus scan process.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6875

Modified:
  stable/11/sys/dev/hyperv/include/hyperv.h
  stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
  stable/11/sys/dev/hyperv/vmbus/hv_channel.c
  stable/11/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
  stable/11/sys/dev/hyperv/vmbus/hv_connection.c
  stable/11/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
  stable/11/sys/dev/hyperv/vmbus/vmbus.c
  stable/11/sys/dev/hyperv/vmbus/vmbus_reg.h
  stable/11/sys/dev/hyperv/vmbus/vmbus_var.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/hyperv/include/hyperv.h
==============================================================================
--- stable/11/sys/dev/hyperv/include/hyperv.h   Fri Oct 14 07:39:34 2016        
(r307290)
+++ stable/11/sys/dev/hyperv/include/hyperv.h   Fri Oct 14 07:40:04 2016        
(r307291)
@@ -713,6 +713,7 @@ typedef struct {
 typedef struct hv_vmbus_channel {
        TAILQ_ENTRY(hv_vmbus_channel)   list_entry;
        struct hv_device*               device;
+       struct vmbus_softc              *vmbus_sc;
        hv_vmbus_channel_state          state;
        hv_vmbus_channel_offer_channel  offer_msg;
        /*
@@ -808,6 +809,8 @@ typedef struct hv_vmbus_channel {
        void                            *hv_chan_priv1;
        void                            *hv_chan_priv2;
        void                            *hv_chan_priv3;
+
+       struct task                     ch_detach_task;
 } hv_vmbus_channel;
 
 #define HV_VMBUS_CHAN_ISPRIMARY(chan)  ((chan)->primary_channel == NULL)

Modified: stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c     Fri Oct 14 
07:39:34 2016        (r307290)
+++ stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c     Fri Oct 14 
07:40:04 2016        (r307291)
@@ -299,6 +299,12 @@ static int hn_tx_swq_depth = 0;
 SYSCTL_INT(_hw_hn, OID_AUTO, tx_swq_depth, CTLFLAG_RDTUN,
     &hn_tx_swq_depth, 0, "Depth of IFQ or BUFRING");
 
+#if __FreeBSD_version >= 1100095
+static u_int hn_lro_mbufq_depth = 0;
+SYSCTL_UINT(_hw_hn, OID_AUTO, lro_mbufq_depth, CTLFLAG_RDTUN,
+    &hn_lro_mbufq_depth, 0, "Depth of LRO mbuf queue");
+#endif
+
 static u_int hn_cpu_index;
 
 /*
@@ -1283,6 +1289,19 @@ hv_m_append(struct mbuf *m0, int len, c_
        return (remainder == 0);
 }
 
+#if defined(INET) || defined(INET6)
+static __inline int
+hn_lro_rx(struct lro_ctrl *lc, struct mbuf *m)
+{
+#if __FreeBSD_version >= 1100095
+       if (hn_lro_mbufq_depth) {
+               tcp_lro_queue_mbuf(lc, m);
+               return 0;
+       }
+#endif
+       return tcp_lro_rx(lc, m, 0);
+}
+#endif
 
 /*
  * Called when we receive a data packet from the "wire" on the
@@ -1488,7 +1507,7 @@ skip:
 
                if (lro->lro_cnt) {
                        rxr->hn_lro_tried++;
-                       if (tcp_lro_rx(lro, m_new, 0) == 0) {
+                       if (hn_lro_rx(lro, m_new) == 0) {
                                /* DONE! */
                                return 0;
                        }
@@ -2223,7 +2242,8 @@ hn_create_rx_data(struct hn_softc *sc, i
                 */
 #if defined(INET) || defined(INET6)
 #if __FreeBSD_version >= 1100095
-               tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt, 0);
+               tcp_lro_init_args(&rxr->hn_lro, sc->hn_ifp, lroent_cnt,
+                   hn_lro_mbufq_depth);
 #else
                tcp_lro_init(&rxr->hn_lro);
                rxr->hn_lro.ifp = sc->hn_ifp;

Modified: stable/11/sys/dev/hyperv/vmbus/hv_channel.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/hv_channel.c Fri Oct 14 07:39:34 2016        
(r307290)
+++ stable/11/sys/dev/hyperv/vmbus/hv_channel.c Fri Oct 14 07:40:04 2016        
(r307291)
@@ -67,7 +67,7 @@ static void
 vmbus_channel_set_event(hv_vmbus_channel *channel)
 {
        if (channel->offer_msg.monitor_allocated) {
-               struct vmbus_softc *sc = vmbus_get_softc();
+               struct vmbus_softc *sc = channel->vmbus_sc;
                hv_vmbus_monitor_page *monitor_page;
                uint32_t chanid = channel->offer_msg.child_rel_id;
 
@@ -205,7 +205,7 @@ hv_vmbus_channel_open(
 
        vmbus_on_channel_open(new_channel);
 
-       new_channel->rxq = VMBUS_PCPU_GET(vmbus_get_softc(), event_tq,
+       new_channel->rxq = VMBUS_PCPU_GET(new_channel->vmbus_sc, event_tq,
            new_channel->target_cpu);
        TASK_INIT(&new_channel->channel_task, 0, VmbusProcessChannelEvent, 
new_channel);
 

Modified: stable/11/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/hv_channel_mgmt.c    Fri Oct 14 07:39:34 
2016        (r307290)
+++ stable/11/sys/dev/hyperv/vmbus/hv_channel_mgmt.c    Fri Oct 14 07:40:04 
2016        (r307291)
@@ -36,19 +36,13 @@
 #include <dev/hyperv/vmbus/vmbus_reg.h>
 #include <dev/hyperv/vmbus/vmbus_var.h>
 
-/*
- * Internal functions
- */
+typedef void   (*vmbus_chanmsg_proc_t)
+               (struct vmbus_softc *, const struct vmbus_message *);
 
-typedef struct hv_vmbus_channel_msg_table_entry {
-       hv_vmbus_channel_msg_type    messageType;
-       void            (*messageHandler)
-                       (struct vmbus_softc *sc,
-                        const struct vmbus_message *msg);
-} hv_vmbus_channel_msg_table_entry;
-
-static void    vmbus_channel_on_offer_internal(void *context);
-static void    vmbus_channel_on_offer_rescind_internal(void *context);
+static struct hv_vmbus_channel *hv_vmbus_allocate_channel(struct vmbus_softc 
*);
+static void    vmbus_channel_on_offer_internal(struct vmbus_softc *,
+                   const hv_vmbus_channel_offer_channel *offer);
+static void    vmbus_chan_detach_task(void *, int);
 
 static void    vmbus_channel_on_offer(struct vmbus_softc *,
                    const struct vmbus_message *);
@@ -68,108 +62,38 @@ static void        vmbus_channel_on_version_res
 /**
  * Channel message dispatch table
  */
-static const hv_vmbus_channel_msg_table_entry
-    g_channel_message_table[HV_CHANNEL_MESSAGE_COUNT] = {
-       { HV_CHANNEL_MESSAGE_INVALID,
-               NULL },
-       { HV_CHANNEL_MESSAGE_OFFER_CHANNEL,
-               vmbus_channel_on_offer },
-       { HV_CHANNEL_MESSAGE_RESCIND_CHANNEL_OFFER,
-               vmbus_channel_on_offer_rescind },
-       { HV_CHANNEL_MESSAGE_REQUEST_OFFERS,
-               NULL },
-       { HV_CHANNEL_MESSAGE_ALL_OFFERS_DELIVERED,
-               vmbus_channel_on_offers_delivered },
-       { HV_CHANNEL_MESSAGE_OPEN_CHANNEL,
-               NULL },
-       { HV_CHANNEL_MESSAGE_OPEN_CHANNEL_RESULT,
-               vmbus_channel_on_open_result },
-       { HV_CHANNEL_MESSAGE_CLOSE_CHANNEL,
-               NULL },
-       { HV_CHANNEL_MESSAGEL_GPADL_HEADER,
-               NULL },
-       { HV_CHANNEL_MESSAGE_GPADL_BODY,
-               NULL },
-       { HV_CHANNEL_MESSAGE_GPADL_CREATED,
-               vmbus_channel_on_gpadl_created },
-       { HV_CHANNEL_MESSAGE_GPADL_TEARDOWN,
-               NULL },
-       { HV_CHANNEL_MESSAGE_GPADL_TORNDOWN,
-               vmbus_channel_on_gpadl_torndown },
-       { HV_CHANNEL_MESSAGE_REL_ID_RELEASED,
-               NULL },
-       { HV_CHANNEL_MESSAGE_INITIATED_CONTACT,
-               NULL },
-       { HV_CHANNEL_MESSAGE_VERSION_RESPONSE,
-               vmbus_channel_on_version_response },
-       { HV_CHANNEL_MESSAGE_UNLOAD,
-               NULL }
+static const vmbus_chanmsg_proc_t
+vmbus_chanmsg_process[HV_CHANNEL_MESSAGE_COUNT] = {
+       [HV_CHANNEL_MESSAGE_OFFER_CHANNEL] =
+               vmbus_channel_on_offer,
+       [HV_CHANNEL_MESSAGE_RESCIND_CHANNEL_OFFER] =
+               vmbus_channel_on_offer_rescind,
+       [HV_CHANNEL_MESSAGE_ALL_OFFERS_DELIVERED] =
+               vmbus_channel_on_offers_delivered,
+       [HV_CHANNEL_MESSAGE_OPEN_CHANNEL_RESULT] =
+               vmbus_channel_on_open_result,
+       [HV_CHANNEL_MESSAGE_GPADL_CREATED] =
+               vmbus_channel_on_gpadl_created,
+       [HV_CHANNEL_MESSAGE_GPADL_TORNDOWN] =
+               vmbus_channel_on_gpadl_torndown,
+       [HV_CHANNEL_MESSAGE_VERSION_RESPONSE] =
+               vmbus_channel_on_version_response
 };
 
-typedef struct hv_work_item {
-       struct task     work;
-       void            (*callback)(void *);
-       void*           context;
-} hv_work_item;
-
-static struct mtx      vmbus_chwait_lock;
-MTX_SYSINIT(vmbus_chwait_lk, &vmbus_chwait_lock, "vmbus primarych wait lock",
-    MTX_DEF);
-static uint32_t                vmbus_chancnt;
-static uint32_t                vmbus_devcnt;
-
-#define VMBUS_CHANCNT_DONE     0x80000000
-
-/**
- * Implementation of the work abstraction.
- */
-static void
-work_item_callback(void *work, int pending)
-{
-       struct hv_work_item *w = (struct hv_work_item *)work;
-
-       w->callback(w->context);
-
-       free(w, M_DEVBUF);
-}
-
-/**
- * @brief Create work item
- */
-static int
-hv_queue_work_item(
-       void (*callback)(void *), void *context)
-{
-       struct hv_work_item *w = malloc(sizeof(struct hv_work_item),
-                                       M_DEVBUF, M_NOWAIT);
-       KASSERT(w != NULL, ("Error VMBUS: Failed to allocate WorkItem\n"));
-       if (w == NULL)
-           return (ENOMEM);
-
-       w->callback = callback;
-       w->context = context;
-
-       TASK_INIT(&w->work, 0, work_item_callback, w);
-
-       return (taskqueue_enqueue(taskqueue_thread, &w->work));
-}
-
-
 /**
  * @brief Allocate and initialize a vmbus channel object
  */
-hv_vmbus_channel*
-hv_vmbus_allocate_channel(void)
+static struct hv_vmbus_channel *
+hv_vmbus_allocate_channel(struct vmbus_softc *sc)
 {
-       hv_vmbus_channel* channel;
+       struct hv_vmbus_channel *channel;
 
-       channel = (hv_vmbus_channel*) malloc(
-                                       sizeof(hv_vmbus_channel),
-                                       M_DEVBUF,
-                                       M_WAITOK | M_ZERO);
+       channel = malloc(sizeof(*channel), M_DEVBUF, M_WAITOK | M_ZERO);
+       channel->vmbus_sc = sc;
 
        mtx_init(&channel->sc_lock, "vmbus multi channel", NULL, MTX_DEF);
        TAILQ_INIT(&channel->sc_list_anchor);
+       TASK_INIT(&channel->ch_detach_task, 0, vmbus_chan_detach_task, channel);
 
        return (channel);
 }
@@ -192,7 +116,6 @@ static void
 vmbus_channel_process_offer(hv_vmbus_channel *new_channel)
 {
        hv_vmbus_channel*       channel;
-       int                     ret;
        uint32_t                relid;
 
        relid = new_channel->offer_msg.child_rel_id;
@@ -297,19 +220,8 @@ vmbus_channel_process_offer(hv_vmbus_cha
         * binding which eventually invokes the device driver's AddDevice()
         * method.
         */
-       ret = hv_vmbus_child_device_register(new_channel->device);
-       if (ret != 0) {
-               mtx_lock(&hv_vmbus_g_connection.channel_lock);
-               TAILQ_REMOVE(&hv_vmbus_g_connection.channel_anchor,
-                   new_channel, list_entry);
-               mtx_unlock(&hv_vmbus_g_connection.channel_lock);
-               hv_vmbus_free_vmbus_channel(new_channel);
-       }
-
-       mtx_lock(&vmbus_chwait_lock);
-       vmbus_devcnt++;
-       mtx_unlock(&vmbus_chwait_lock);
-       wakeup(&vmbus_devcnt);
+       hv_vmbus_child_device_register(new_channel->vmbus_sc,
+           new_channel->device);
 }
 
 void
@@ -324,7 +236,7 @@ vmbus_channel_cpu_set(struct hv_vmbus_ch
        }
 
        chan->target_cpu = cpu;
-       chan->target_vcpu = VMBUS_PCPU_GET(vmbus_get_softc(), vcpuid, cpu);
+       chan->target_vcpu = VMBUS_PCPU_GET(chan->vmbus_sc, vcpuid, cpu);
 
        if (bootverbose) {
                printf("vmbus_chan%u: assigned to cpu%u [vcpu%u]\n",
@@ -393,46 +305,28 @@ vmbus_channel_select_defcpu(struct hv_vm
 /**
  * @brief Handler for channel offers from Hyper-V/Azure
  *
- * Handler for channel offers from vmbus in parent partition. We ignore
- * all offers except network and storage offers. For each network and storage
- * offers, we create a channel object and queue a work item to the channel
- * object to process the offer synchronously
+ * Handler for channel offers from vmbus in parent partition.
  */
 static void
 vmbus_channel_on_offer(struct vmbus_softc *sc, const struct vmbus_message *msg)
 {
-       const hv_vmbus_channel_msg_header *hdr =
-           (const hv_vmbus_channel_msg_header *)msg->msg_data;
-
        const hv_vmbus_channel_offer_channel *offer;
-       hv_vmbus_channel_offer_channel *copied;
 
-       offer = (const hv_vmbus_channel_offer_channel *)hdr;
+       /* New channel is offered by vmbus */
+       vmbus_scan_newchan(sc);
 
-       // copy offer data
-       copied = malloc(sizeof(*copied), M_DEVBUF, M_NOWAIT);
-       if (copied == NULL) {
-               printf("fail to allocate memory\n");
-               return;
-       }
-
-       memcpy(copied, hdr, sizeof(*copied));
-       hv_queue_work_item(vmbus_channel_on_offer_internal, copied);
-
-       mtx_lock(&vmbus_chwait_lock);
-       if ((vmbus_chancnt & VMBUS_CHANCNT_DONE) == 0)
-               vmbus_chancnt++;
-       mtx_unlock(&vmbus_chwait_lock);
+       offer = (const hv_vmbus_channel_offer_channel *)msg->msg_data;
+       vmbus_channel_on_offer_internal(sc, offer);
 }
 
 static void
-vmbus_channel_on_offer_internal(void* context)
+vmbus_channel_on_offer_internal(struct vmbus_softc *sc,
+    const hv_vmbus_channel_offer_channel *offer)
 {
        hv_vmbus_channel* new_channel;
 
-       hv_vmbus_channel_offer_channel* offer = 
(hv_vmbus_channel_offer_channel*)context;
        /* Allocate the channel object and save this offer */
-       new_channel = hv_vmbus_allocate_channel();
+       new_channel = hv_vmbus_allocate_channel(sc);
 
        /*
         * By default we setup state to enable batched
@@ -469,45 +363,41 @@ vmbus_channel_on_offer_internal(void* co
        vmbus_channel_select_defcpu(new_channel);
 
        vmbus_channel_process_offer(new_channel);
-
-       free(offer, M_DEVBUF);
 }
 
 /**
  * @brief Rescind offer handler.
  *
  * We queue a work item to process this offer
- * synchronously
+ * synchronously.
+ *
+ * XXX pretty broken; need rework.
  */
 static void
 vmbus_channel_on_offer_rescind(struct vmbus_softc *sc,
     const struct vmbus_message *msg)
 {
-       const hv_vmbus_channel_msg_header *hdr =
-           (const hv_vmbus_channel_msg_header *)msg->msg_data;
-
        const hv_vmbus_channel_rescind_offer *rescind;
        hv_vmbus_channel*               channel;
 
-       rescind = (const hv_vmbus_channel_rescind_offer *)hdr;
+       rescind = (const hv_vmbus_channel_rescind_offer *)msg->msg_data;
 
        channel = hv_vmbus_g_connection.channels[rescind->child_rel_id];
        if (channel == NULL)
            return;
-
-       hv_queue_work_item(vmbus_channel_on_offer_rescind_internal, channel);
        hv_vmbus_g_connection.channels[rescind->child_rel_id] = NULL;
+
+       taskqueue_enqueue(taskqueue_thread, &channel->ch_detach_task);
 }
 
 static void
-vmbus_channel_on_offer_rescind_internal(void *context)
+vmbus_chan_detach_task(void *xchan, int pending __unused)
 {
-       hv_vmbus_channel*               channel;
+       struct hv_vmbus_channel *chan = xchan;
 
-       channel = (hv_vmbus_channel*)context;
-       if (HV_VMBUS_CHAN_ISPRIMARY(channel)) {
+       if (HV_VMBUS_CHAN_ISPRIMARY(chan)) {
                /* Only primary channel owns the hv_device */
-               hv_vmbus_child_device_unregister(channel->device);
+               hv_vmbus_child_device_unregister(chan->device);
        }
 }
 
@@ -516,14 +406,12 @@ vmbus_channel_on_offer_rescind_internal(
  * @brief Invoked when all offers have been delivered.
  */
 static void
-vmbus_channel_on_offers_delivered(struct vmbus_softc *sc __unused,
+vmbus_channel_on_offers_delivered(struct vmbus_softc *sc,
     const struct vmbus_message *msg __unused)
 {
 
-       mtx_lock(&vmbus_chwait_lock);
-       vmbus_chancnt |= VMBUS_CHANCNT_DONE;
-       mtx_unlock(&vmbus_chwait_lock);
-       wakeup(&vmbus_chancnt);
+       /* No more new channels for the channel request. */
+       vmbus_scan_done(sc);
 }
 
 /**
@@ -675,36 +563,6 @@ vmbus_channel_on_version_response(struct
 }
 
 /**
- *  @brief Send a request to get all our pending offers.
- */
-int
-hv_vmbus_request_channel_offers(void)
-{
-       int                             ret;
-       hv_vmbus_channel_msg_header*    msg;
-       hv_vmbus_channel_msg_info*      msg_info;
-
-       msg_info = (hv_vmbus_channel_msg_info *)
-           malloc(sizeof(hv_vmbus_channel_msg_info)
-                   + sizeof(hv_vmbus_channel_msg_header), M_DEVBUF, M_NOWAIT);
-
-       if (msg_info == NULL) {
-           if(bootverbose)
-               printf("Error VMBUS: malloc failed for Request Offers\n");
-           return (ENOMEM);
-       }
-
-       msg = (hv_vmbus_channel_msg_header*) msg_info->msg;
-       msg->message_type = HV_CHANNEL_MESSAGE_REQUEST_OFFERS;
-
-       ret = hv_vmbus_post_message(msg, sizeof(hv_vmbus_channel_msg_header));
-
-       free(msg_info, M_DEVBUF);
-
-       return (ret);
-}
-
-/**
  * @brief Release channels that are unattached/unconnected (i.e., no drivers 
associated)
  */
 void
@@ -757,7 +615,7 @@ vmbus_select_outgoing_channel(struct hv_
                return outgoing_channel;
        }
 
-       cur_vcpu = VMBUS_PCPU_GET(vmbus_get_softc(), vcpuid, smp_pro_id);
+       cur_vcpu = VMBUS_PCPU_GET(primary->vmbus_sc, vcpuid, smp_pro_id);
        
        TAILQ_FOREACH(new_channel, &primary->sc_list_anchor, sc_list_entry) {
                if (new_channel->state != HV_CHANNEL_OPENED_STATE){
@@ -786,21 +644,6 @@ vmbus_select_outgoing_channel(struct hv_
        return(outgoing_channel);
 }
 
-void
-vmbus_scan(void)
-{
-       uint32_t chancnt;
-
-       mtx_lock(&vmbus_chwait_lock);
-       while ((vmbus_chancnt & VMBUS_CHANCNT_DONE) == 0)
-               mtx_sleep(&vmbus_chancnt, &vmbus_chwait_lock, 0, "waitch", 0);
-       chancnt = vmbus_chancnt & ~VMBUS_CHANCNT_DONE;
-
-       while (vmbus_devcnt != chancnt)
-               mtx_sleep(&vmbus_devcnt, &vmbus_chwait_lock, 0, "waitdev", 0);
-       mtx_unlock(&vmbus_chwait_lock);
-}
-
 struct hv_vmbus_channel **
 vmbus_get_subchan(struct hv_vmbus_channel *pri_chan, int subchan_cnt)
 {
@@ -842,20 +685,17 @@ vmbus_rel_subchan(struct hv_vmbus_channe
 void
 vmbus_chan_msgproc(struct vmbus_softc *sc, const struct vmbus_message *msg)
 {
-       const hv_vmbus_channel_msg_table_entry *entry;
-       const hv_vmbus_channel_msg_header *hdr;
-       hv_vmbus_channel_msg_type msg_type;
-
-       hdr = (const hv_vmbus_channel_msg_header *)msg->msg_data;
-       msg_type = hdr->message_type;
+       vmbus_chanmsg_proc_t msg_proc;
+       uint32_t msg_type;
 
+       msg_type = ((const struct vmbus_chanmsg_hdr *)msg->msg_data)->chm_type;
        if (msg_type >= HV_CHANNEL_MESSAGE_COUNT) {
                device_printf(sc->vmbus_dev, "unknown message type 0x%x\n",
                    msg_type);
                return;
        }
 
-       entry = &g_channel_message_table[msg_type];
-       if (entry->messageHandler)
-               entry->messageHandler(sc, msg);
+       msg_proc = vmbus_chanmsg_process[msg_type];
+       if (msg_proc != NULL)
+               msg_proc(sc, msg);
 }

Modified: stable/11/sys/dev/hyperv/vmbus/hv_connection.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/hv_connection.c      Fri Oct 14 07:39:34 
2016        (r307290)
+++ stable/11/sys/dev/hyperv/vmbus/hv_connection.c      Fri Oct 14 07:40:04 
2016        (r307291)
@@ -92,19 +92,13 @@ hv_vmbus_connect(struct vmbus_softc *sc)
 int
 hv_vmbus_disconnect(void)
 {
-       int                      ret = 0;
-       hv_vmbus_channel_unload  msg;
-
-       msg.message_type = HV_CHANNEL_MESSAGE_UNLOAD;
-
-       ret = hv_vmbus_post_message(&msg, sizeof(hv_vmbus_channel_unload));
 
        mtx_destroy(&hv_vmbus_g_connection.channel_msg_lock);
 
        free(hv_vmbus_g_connection.channels, M_DEVBUF);
        hv_vmbus_g_connection.connect_state = HV_DISCONNECTED;
 
-       return (ret);
+       return (0);
 }
 
 static __inline void
@@ -210,7 +204,7 @@ int hv_vmbus_post_message(void *buffer, 
 int
 hv_vmbus_set_event(hv_vmbus_channel *channel)
 {
-       struct vmbus_softc *sc = vmbus_get_softc();
+       struct vmbus_softc *sc = channel->vmbus_sc;
        int ret = 0;
        uint32_t chanid = channel->offer_msg.child_rel_id;
 
@@ -228,7 +222,7 @@ vmbus_on_channel_open(const struct hv_vm
        int flag_cnt;
 
        flag_cnt = (chan->offer_msg.child_rel_id / VMBUS_EVTFLAG_LEN) + 1;
-       flag_cnt_ptr = VMBUS_PCPU_PTR(vmbus_get_softc(), event_flags_cnt,
+       flag_cnt_ptr = VMBUS_PCPU_PTR(chan->vmbus_sc, event_flags_cnt,
            chan->target_cpu);
 
        for (;;) {

Modified: stable/11/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/hv_vmbus_priv.h      Fri Oct 14 07:39:34 
2016        (r307290)
+++ stable/11/sys/dev/hyperv/vmbus/hv_vmbus_priv.h      Fri Oct 14 07:40:04 
2016        (r307291)
@@ -395,9 +395,7 @@ void                        hv_ring_buffer_read_begin(
 uint32_t               hv_ring_buffer_read_end(
                                hv_vmbus_ring_buffer_info       *ring_info);
 
-hv_vmbus_channel*      hv_vmbus_allocate_channel(void);
 void                   hv_vmbus_free_vmbus_channel(hv_vmbus_channel *channel);
-int                    hv_vmbus_request_channel_offers(void);
 void                   hv_vmbus_release_unattached_channels(void);
 
 uint16_t               hv_vmbus_post_msg_via_msg_ipc(
@@ -413,7 +411,9 @@ struct hv_device*   hv_vmbus_child_device_
                                hv_guid                 device_instance,
                                hv_vmbus_channel        *channel);
 
-int                    hv_vmbus_child_device_register(
+struct vmbus_softc;
+
+void                   hv_vmbus_child_device_register(struct vmbus_softc *,
                                        struct hv_device *child_dev);
 int                    hv_vmbus_child_device_unregister(
                                        struct hv_device *child_dev);
@@ -421,13 +421,9 @@ int                        
hv_vmbus_child_device_unregister(
 /**
  * Connection interfaces
  */
-struct vmbus_softc;
 int                    hv_vmbus_connect(struct vmbus_softc *);
 int                    hv_vmbus_disconnect(void);
 int                    hv_vmbus_post_message(void *buffer, size_t buf_size);
 int                    hv_vmbus_set_event(hv_vmbus_channel *channel);
 
-/* Wait for device creation */
-void                   vmbus_scan(void);
-
 #endif  /* __HYPERV_PRIV_H__ */

Modified: stable/11/sys/dev/hyperv/vmbus/vmbus.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus.c      Fri Oct 14 07:39:34 2016        
(r307290)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus.c      Fri Oct 14 07:40:04 2016        
(r307291)
@@ -98,6 +98,13 @@ struct vmbus_msghc_ctx {
 static int                     vmbus_init(struct vmbus_softc *);
 static int                     vmbus_init_contact(struct vmbus_softc *,
                                    uint32_t);
+static int                     vmbus_req_channels(struct vmbus_softc *sc);
+static void                    vmbus_uninit(struct vmbus_softc *);
+static int                     vmbus_scan(struct vmbus_softc *);
+static void                    vmbus_scan_wait(struct vmbus_softc *);
+static void                    vmbus_scan_newdev(struct vmbus_softc *);
+
+static int                     vmbus_sysctl_version(SYSCTL_HANDLER_ARGS);
 
 static struct vmbus_msghc_ctx  *vmbus_msghc_ctx_create(bus_dma_tag_t);
 static void                    vmbus_msghc_ctx_destroy(
@@ -418,6 +425,131 @@ vmbus_init(struct vmbus_softc *sc)
 }
 
 static void
+vmbus_uninit(struct vmbus_softc *sc)
+{
+       struct vmbus_chanmsg_unload *req;
+       struct vmbus_msghc *mh;
+       int error;
+
+       mh = vmbus_msghc_get(sc, sizeof(*req));
+       if (mh == NULL) {
+               device_printf(sc->vmbus_dev,
+                   "can not get msg hypercall for unload\n");
+               return;
+       }
+
+       req = vmbus_msghc_dataptr(mh);
+       req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_UNLOAD;
+
+       error = vmbus_msghc_exec_noresult(mh);
+       vmbus_msghc_put(sc, mh);
+
+       if (error) {
+               device_printf(sc->vmbus_dev,
+                   "unload msg hypercall failed\n");
+       }
+}
+
+static int
+vmbus_req_channels(struct vmbus_softc *sc)
+{
+       struct vmbus_chanmsg_channel_req *req;
+       struct vmbus_msghc *mh;
+       int error;
+
+       mh = vmbus_msghc_get(sc, sizeof(*req));
+       if (mh == NULL)
+               return ENXIO;
+
+       req = vmbus_msghc_dataptr(mh);
+       req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHANNEL_REQ;
+
+       error = vmbus_msghc_exec_noresult(mh);
+       vmbus_msghc_put(sc, mh);
+
+       return error;
+}
+
+void
+vmbus_scan_newchan(struct vmbus_softc *sc)
+{
+       mtx_lock(&sc->vmbus_scan_lock);
+       if ((sc->vmbus_scan_chcnt & VMBUS_SCAN_CHCNT_DONE) == 0)
+               sc->vmbus_scan_chcnt++;
+       mtx_unlock(&sc->vmbus_scan_lock);
+}
+
+void
+vmbus_scan_done(struct vmbus_softc *sc)
+{
+       mtx_lock(&sc->vmbus_scan_lock);
+       sc->vmbus_scan_chcnt |= VMBUS_SCAN_CHCNT_DONE;
+       mtx_unlock(&sc->vmbus_scan_lock);
+       wakeup(&sc->vmbus_scan_chcnt);
+}
+
+static void
+vmbus_scan_newdev(struct vmbus_softc *sc)
+{
+       mtx_lock(&sc->vmbus_scan_lock);
+       sc->vmbus_scan_devcnt++;
+       mtx_unlock(&sc->vmbus_scan_lock);
+       wakeup(&sc->vmbus_scan_devcnt);
+}
+
+static void
+vmbus_scan_wait(struct vmbus_softc *sc)
+{
+       uint32_t chancnt;
+
+       mtx_lock(&sc->vmbus_scan_lock);
+       while ((sc->vmbus_scan_chcnt & VMBUS_SCAN_CHCNT_DONE) == 0) {
+               mtx_sleep(&sc->vmbus_scan_chcnt, &sc->vmbus_scan_lock, 0,
+                   "waitch", 0);
+       }
+       chancnt = sc->vmbus_scan_chcnt & ~VMBUS_SCAN_CHCNT_DONE;
+
+       while (sc->vmbus_scan_devcnt != chancnt) {
+               mtx_sleep(&sc->vmbus_scan_devcnt, &sc->vmbus_scan_lock, 0,
+                   "waitdev", 0);
+       }
+       mtx_unlock(&sc->vmbus_scan_lock);
+}
+
+static int
+vmbus_scan(struct vmbus_softc *sc)
+{
+       int error;
+
+       /*
+        * Start vmbus scanning.
+        */
+       error = vmbus_req_channels(sc);
+       if (error) {
+               device_printf(sc->vmbus_dev, "channel request failed: %d\n",
+                   error);
+               return error;
+       }
+
+       /*
+        * Wait for all devices are added to vmbus.
+        */
+       vmbus_scan_wait(sc);
+
+       /*
+        * Identify, probe and attach.
+        */
+       bus_generic_probe(sc->vmbus_dev);
+       bus_generic_attach(sc->vmbus_dev);
+
+       if (bootverbose) {
+               device_printf(sc->vmbus_dev, "device scan, probe and attach "
+                   "done\n");
+       }
+       return 0;
+}
+
+static void
 vmbus_msg_task(void *xsc, int pending __unused)
 {
        struct vmbus_softc *sc = xsc;
@@ -892,12 +1024,13 @@ hv_vmbus_child_device_create(hv_guid typ
        return (child_dev);
 }
 
-int
-hv_vmbus_child_device_register(struct hv_device *child_dev)
+void
+hv_vmbus_child_device_register(struct vmbus_softc *sc,
+    struct hv_device *child_dev)
 {
        device_t child, parent;
 
-       parent = vmbus_get_device();
+       parent = sc->vmbus_dev;
        if (bootverbose) {
                char name[HYPERV_GUID_STRLEN];
 
@@ -909,7 +1042,8 @@ hv_vmbus_child_device_register(struct hv
        child_dev->device = child;
        device_set_ivars(child, child_dev);
 
-       return (0);
+       /* New device was added to vmbus */
+       vmbus_scan_newdev(sc);
 }
 
 int
@@ -927,6 +1061,17 @@ hv_vmbus_child_device_unregister(struct 
 }
 
 static int
+vmbus_sysctl_version(SYSCTL_HANDLER_ARGS)
+{
+       char verstr[16];
+
+       snprintf(verstr, sizeof(verstr), "%u.%u",
+           hv_vmbus_protocal_version >> 16,
+           hv_vmbus_protocal_version & 0xffff);
+       return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
+}
+
+static int
 vmbus_probe(device_t dev)
 {
        char *id[] = { "VMBUS", NULL };
@@ -954,15 +1099,18 @@ vmbus_probe(device_t dev)
  * - retrieve the channel offers
  */
 static int
-vmbus_bus_init(void)
+vmbus_doattach(struct vmbus_softc *sc)
 {
-       struct vmbus_softc *sc = vmbus_get_softc();
+       struct sysctl_oid_list *child;
+       struct sysctl_ctx_list *ctx;
        int ret;
 
        if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED)
                return (0);
        sc->vmbus_flags |= VMBUS_FLAG_ATTACHED;
 
+       mtx_init(&sc->vmbus_scan_lock, "vmbus scan", NULL, MTX_DEF);
+
        /*
         * Create context for "post message" Hypercalls
         */
@@ -1012,11 +1160,15 @@ vmbus_bus_init(void)
        else
                sc->vmbus_event_proc = vmbus_event_proc;
 
-       hv_vmbus_request_channel_offers();
+       ret = vmbus_scan(sc);
+       if (ret != 0)
+               goto cleanup;
 
-       vmbus_scan();
-       bus_generic_attach(sc->vmbus_dev);
-       device_printf(sc->vmbus_dev, "device scan, probe and attach done\n");
+       ctx = device_get_sysctl_ctx(sc->vmbus_dev);
+       child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->vmbus_dev));
+       SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "version",
+           CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
+           vmbus_sysctl_version, "A", "vmbus version");
 
        return (ret);
 
@@ -1027,6 +1179,7 @@ cleanup:
                vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc);
                sc->vmbus_msg_hc = NULL;
        }
+       mtx_destroy(&sc->vmbus_scan_lock);
 
        return (ret);
 }
@@ -1059,16 +1212,17 @@ vmbus_attach(device_t dev)
         */
        if (!cold)
 #endif
-               vmbus_bus_init();
+               vmbus_doattach(vmbus_sc);
 
-       bus_generic_probe(dev);
        return (0);
 }
 
 static void
 vmbus_sysinit(void *arg __unused)
 {
-       if (vm_guest != VM_GUEST_HV || vmbus_get_softc() == NULL)
+       struct vmbus_softc *sc = vmbus_get_softc();
+
+       if (vm_guest != VM_GUEST_HV || sc == NULL)
                return;
 
 #ifndef EARLY_AP_STARTUP
@@ -1080,7 +1234,7 @@ vmbus_sysinit(void *arg __unused)
         */
        if (!cold) 
 #endif
-               vmbus_bus_init();
+               vmbus_doattach(sc);
 }
 
 static int
@@ -1089,6 +1243,8 @@ vmbus_detach(device_t dev)
        struct vmbus_softc *sc = device_get_softc(dev);
 
        hv_vmbus_release_unattached_channels();
+
+       vmbus_uninit(sc);
        hv_vmbus_disconnect();
 
        if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) {
@@ -1104,6 +1260,7 @@ vmbus_detach(device_t dev)
                sc->vmbus_msg_hc = NULL;
        }
 
+       mtx_destroy(&sc->vmbus_scan_lock);
        return (0);
 }
 

Modified: stable/11/sys/dev/hyperv/vmbus/vmbus_reg.h
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus_reg.h  Fri Oct 14 07:39:34 2016        
(r307290)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus_reg.h  Fri Oct 14 07:40:04 2016        
(r307291)
@@ -83,8 +83,10 @@ CTASSERT(sizeof(struct vmbus_evtflags) =
  * - Embedded in hypercall_postmsg_in.hc_data, e.g. request.
  */
 
+#define VMBUS_CHANMSG_TYPE_CHANNEL_REQ         3       /* REQ */
 #define VMBUS_CHANMSG_TYPE_INIT_CONTACT                14      /* REQ */
 #define VMBUS_CHANMSG_TYPE_VERSION_RESP                15      /* RESP */
+#define VMBUS_CHANMSG_TYPE_UNLOAD              16      /* REQ */
 
 struct vmbus_chanmsg_hdr {
        uint32_t        chm_type;       /* VMBUS_CHANMSG_TYPE_ */
@@ -107,4 +109,14 @@ struct vmbus_chanmsg_version_resp {
        uint8_t         chm_supp;
 } __packed;
 
+/* VMBUS_CHANMSG_TYPE_CHANNEL_REQ */
+struct vmbus_chanmsg_channel_req {
+       struct vmbus_chanmsg_hdr chm_hdr;
+} __packed;
+
+/* VMBUS_CHANMSG_TYPE_UNLOAD */
+struct vmbus_chanmsg_unload {
+       struct vmbus_chanmsg_hdr chm_hdr;
+} __packed;
+
 #endif /* !_VMBUS_REG_H_ */

Modified: stable/11/sys/dev/hyperv/vmbus/vmbus_var.h
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus_var.h  Fri Oct 14 07:39:34 2016        
(r307290)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus_var.h  Fri Oct 14 07:40:04 2016        
(r307291)
@@ -84,6 +84,11 @@ struct vmbus_softc {
        void                    *vmbus_mnf1;    /* monitored by VM, unused */
        struct hyperv_dma       vmbus_mnf1_dma;
        struct hyperv_dma       vmbus_mnf2_dma;
+
+       struct mtx              vmbus_scan_lock;
+       uint32_t                vmbus_scan_chcnt;
+#define VMBUS_SCAN_CHCNT_DONE  0x80000000
+       uint32_t                vmbus_scan_devcnt;
 };
 
 #define VMBUS_FLAG_ATTACHED    0x0001  /* vmbus was attached */
@@ -129,4 +134,7 @@ const struct vmbus_message *vmbus_msghc_
            struct vmbus_msghc *);
 void   vmbus_msghc_wakeup(struct vmbus_softc *, const struct vmbus_message *);
 
+void   vmbus_scan_done(struct vmbus_softc *);
+void   vmbus_scan_newchan(struct vmbus_softc *);
+
 #endif /* !_VMBUS_VAR_H_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to