Author: sephe
Date: Mon Oct 17 02:12:49 2016
New Revision: 307451
URL: https://svnweb.freebsd.org/changeset/base/307451

Log:
  MFC 302864
  
      hyperv/vmbus: Merge hv_channel_mgmt.c into hv_channel.c
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D7126

Deleted:
  stable/11/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
Modified:
  stable/11/sys/conf/files.amd64
  stable/11/sys/conf/files.i386
  stable/11/sys/dev/hyperv/include/hyperv.h
  stable/11/sys/dev/hyperv/vmbus/hv_channel.c
  stable/11/sys/dev/hyperv/vmbus/vmbus.c
  stable/11/sys/dev/hyperv/vmbus/vmbus_var.h
  stable/11/sys/modules/hyperv/vmbus/Makefile
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/conf/files.amd64
==============================================================================
--- stable/11/sys/conf/files.amd64      Mon Oct 17 02:02:44 2016        
(r307450)
+++ stable/11/sys/conf/files.amd64      Mon Oct 17 02:12:49 2016        
(r307451)
@@ -302,7 +302,6 @@ dev/hyperv/utilities/hv_shutdown.c                  opt
 dev/hyperv/utilities/hv_timesync.c                     optional        hyperv
 dev/hyperv/utilities/hv_util.c                         optional        hyperv
 dev/hyperv/vmbus/hv_channel.c                          optional        hyperv
-dev/hyperv/vmbus/hv_channel_mgmt.c                     optional        hyperv
 dev/hyperv/vmbus/hv_ring_buffer.c                      optional        hyperv
 dev/hyperv/vmbus/hyperv.c                              optional        hyperv
 dev/hyperv/vmbus/hyperv_busdma.c                       optional        hyperv

Modified: stable/11/sys/conf/files.i386
==============================================================================
--- stable/11/sys/conf/files.i386       Mon Oct 17 02:02:44 2016        
(r307450)
+++ stable/11/sys/conf/files.i386       Mon Oct 17 02:12:49 2016        
(r307451)
@@ -259,7 +259,6 @@ dev/hyperv/utilities/hv_shutdown.c                  opt
 dev/hyperv/utilities/hv_timesync.c                     optional        hyperv
 dev/hyperv/utilities/hv_util.c                         optional        hyperv
 dev/hyperv/vmbus/hv_channel.c                          optional        hyperv
-dev/hyperv/vmbus/hv_channel_mgmt.c                     optional        hyperv
 dev/hyperv/vmbus/hv_ring_buffer.c                      optional        hyperv
 dev/hyperv/vmbus/hyperv.c                              optional        hyperv
 dev/hyperv/vmbus/hyperv_busdma.c                       optional        hyperv

Modified: stable/11/sys/dev/hyperv/include/hyperv.h
==============================================================================
--- stable/11/sys/dev/hyperv/include/hyperv.h   Mon Oct 17 02:02:44 2016        
(r307450)
+++ stable/11/sys/dev/hyperv/include/hyperv.h   Mon Oct 17 02:12:49 2016        
(r307451)
@@ -293,30 +293,17 @@ typedef struct hv_vmbus_channel {
        uint32_t                        target_cpu;
 
        /*
-        * Support for multi-channels.
-        * The initial offer is considered the primary channel and this
-        * offer message will indicate if the host supports multi-channels.
-        * The guest is free to ask for multi-channels to be offerred and can
-        * open these multi-channels as a normal "primary" channel. However,
-        * all multi-channels will have the same type and instance guids as the
-        * primary channel. Requests sent on a given channel will result in a
-        * response on the same channel.
+        * If this is a primary channel, ch_subchan* fields
+        * contain sub-channels belonging to this primary
+        * channel.
         */
-
-       struct mtx                      sc_lock;
-
-       /*
-        * Link list of all the multi-channels if this is a primary channel
-        */
-       TAILQ_HEAD(, hv_vmbus_channel)  sc_list_anchor;
-       TAILQ_ENTRY(hv_vmbus_channel)   sc_list_entry;
-       int                             subchan_cnt;
-
-       /*
-        * The primary channel this sub-channle belongs to.
-        * This will be NULL for the primary channel.
-        */
-       struct hv_vmbus_channel         *primary_channel;
+       struct mtx                      ch_subchan_lock;
+       TAILQ_HEAD(, hv_vmbus_channel)  ch_subchans;
+       int                             ch_subchan_cnt;
+
+       /* If this is a sub-channel */
+       TAILQ_ENTRY(hv_vmbus_channel)   ch_sublink;     /* sub-channel link */
+       struct hv_vmbus_channel         *ch_prichan;    /* owner primary chan */
 
        /*
         * Driver private data

Modified: stable/11/sys/dev/hyperv/vmbus/hv_channel.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/hv_channel.c Mon Oct 17 02:02:44 2016        
(r307450)
+++ stable/11/sys/dev/hyperv/vmbus/hv_channel.c Mon Oct 17 02:12:49 2016        
(r307451)
@@ -53,8 +53,28 @@ __FBSDID("$FreeBSD$");
 static void    vmbus_chan_send_event(hv_vmbus_channel* channel);
 static void    vmbus_chan_update_evtflagcnt(struct vmbus_softc *,
                    const struct hv_vmbus_channel *);
+
 static void    vmbus_chan_task(void *, int);
 static void    vmbus_chan_task_nobatch(void *, int);
+static void    vmbus_chan_detach_task(void *, int);
+
+static void    vmbus_chan_msgproc_choffer(struct vmbus_softc *,
+                   const struct vmbus_message *);
+static void    vmbus_chan_msgproc_chrescind(struct vmbus_softc *,
+                   const struct vmbus_message *);
+
+/*
+ * Vmbus channel message processing.
+ */
+static const vmbus_chanmsg_proc_t
+vmbus_chan_msgprocs[VMBUS_CHANMSG_TYPE_MAX] = {
+       VMBUS_CHANMSG_PROC(CHOFFER,     vmbus_chan_msgproc_choffer),
+       VMBUS_CHANMSG_PROC(CHRESCIND,   vmbus_chan_msgproc_chrescind),
+
+       VMBUS_CHANMSG_PROC_WAKEUP(CHOPEN_RESP),
+       VMBUS_CHANMSG_PROC_WAKEUP(GPADL_CONNRESP),
+       VMBUS_CHANMSG_PROC_WAKEUP(GPADL_DISCONNRESP)
+};
 
 /**
  *  @brief Trigger an event notification on the specified channel
@@ -100,7 +120,7 @@ vmbus_channel_sysctl_create(hv_vmbus_cha
        uint16_t sub_ch_id;
        char name[16];
        
-       hv_vmbus_channel* primary_ch = channel->primary_channel;
+       hv_vmbus_channel* primary_ch = channel->ch_prichan;
 
        if (primary_ch == NULL) {
                dev = channel->ch_dev;
@@ -563,7 +583,7 @@ hv_vmbus_channel_close(struct hv_vmbus_c
        /*
         * Close all sub-channels, if any.
         */
-       subchan_cnt = chan->subchan_cnt;
+       subchan_cnt = chan->ch_subchan_cnt;
        if (subchan_cnt > 0) {
                struct hv_vmbus_channel **subchan;
                int i;
@@ -984,3 +1004,463 @@ vmbus_chan_update_evtflagcnt(struct vmbu
                }
        }
 }
+
+static struct hv_vmbus_channel *
+vmbus_chan_alloc(struct vmbus_softc *sc)
+{
+       struct hv_vmbus_channel *chan;
+
+       chan = malloc(sizeof(*chan), M_DEVBUF, M_WAITOK | M_ZERO);
+
+       chan->ch_monprm = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev),
+           HYPERCALL_PARAM_ALIGN, 0, sizeof(struct hyperv_mon_param),
+           &chan->ch_monprm_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
+       if (chan->ch_monprm == NULL) {
+               device_printf(sc->vmbus_dev, "monprm alloc failed\n");
+               free(chan, M_DEVBUF);
+               return NULL;
+       }
+
+       chan->vmbus_sc = sc;
+       mtx_init(&chan->ch_subchan_lock, "vmbus subchan", NULL, MTX_DEF);
+       TAILQ_INIT(&chan->ch_subchans);
+       TASK_INIT(&chan->ch_detach_task, 0, vmbus_chan_detach_task, chan);
+
+       return chan;
+}
+
+static void
+vmbus_chan_free(struct hv_vmbus_channel *chan)
+{
+       /* TODO: assert sub-channel list is empty */
+       /* TODO: asset no longer on the primary channel's sub-channel list */
+       /* TODO: asset no longer on the vmbus channel list */
+       hyperv_dmamem_free(&chan->ch_monprm_dma, chan->ch_monprm);
+       mtx_destroy(&chan->ch_subchan_lock);
+       free(chan, M_DEVBUF);
+}
+
+static int
+vmbus_chan_add(struct hv_vmbus_channel *newchan)
+{
+       struct vmbus_softc *sc = newchan->vmbus_sc;
+       struct hv_vmbus_channel *prichan;
+
+       if (newchan->ch_id == 0) {
+               /*
+                * XXX
+                * Chan0 will neither be processed nor should be offered;
+                * skip it.
+                */
+               device_printf(sc->vmbus_dev, "got chan0 offer, discard\n");
+               return EINVAL;
+       } else if (newchan->ch_id >= VMBUS_CHAN_MAX) {
+               device_printf(sc->vmbus_dev, "invalid chan%u offer\n",
+                   newchan->ch_id);
+               return EINVAL;
+       }
+       sc->vmbus_chmap[newchan->ch_id] = newchan;
+
+       if (bootverbose) {
+               device_printf(sc->vmbus_dev, "chan%u subidx%u offer\n",
+                   newchan->ch_id, newchan->ch_subidx);
+       }
+
+       mtx_lock(&sc->vmbus_prichan_lock);
+       TAILQ_FOREACH(prichan, &sc->vmbus_prichans, ch_prilink) {
+               /*
+                * Sub-channel will have the same type GUID and instance
+                * GUID as its primary channel.
+                */
+               if (memcmp(&prichan->ch_guid_type, &newchan->ch_guid_type,
+                   sizeof(struct hyperv_guid)) == 0 &&
+                   memcmp(&prichan->ch_guid_inst, &newchan->ch_guid_inst,
+                   sizeof(struct hyperv_guid)) == 0)
+                       break;
+       }
+       if (VMBUS_CHAN_ISPRIMARY(newchan)) {
+               if (prichan == NULL) {
+                       /* Install the new primary channel */
+                       TAILQ_INSERT_TAIL(&sc->vmbus_prichans, newchan,
+                           ch_prilink);
+                       mtx_unlock(&sc->vmbus_prichan_lock);
+                       return 0;
+               } else {
+                       mtx_unlock(&sc->vmbus_prichan_lock);
+                       device_printf(sc->vmbus_dev, "duplicated primary "
+                           "chan%u\n", newchan->ch_id);
+                       return EINVAL;
+               }
+       } else { /* Sub-channel */
+               if (prichan == NULL) {
+                       mtx_unlock(&sc->vmbus_prichan_lock);
+                       device_printf(sc->vmbus_dev, "no primary chan for "
+                           "chan%u\n", newchan->ch_id);
+                       return EINVAL;
+               }
+               /*
+                * Found the primary channel for this sub-channel and
+                * move on.
+                *
+                * XXX refcnt prichan
+                */
+       }
+       mtx_unlock(&sc->vmbus_prichan_lock);
+
+       /*
+        * This is a sub-channel; link it with the primary channel.
+        */
+       KASSERT(!VMBUS_CHAN_ISPRIMARY(newchan),
+           ("new channel is not sub-channel"));
+       KASSERT(prichan != NULL, ("no primary channel"));
+
+       newchan->ch_prichan = prichan;
+       newchan->ch_dev = prichan->ch_dev;
+
+       mtx_lock(&prichan->ch_subchan_lock);
+       TAILQ_INSERT_TAIL(&prichan->ch_subchans, newchan, ch_sublink);
+       /*
+        * Bump up sub-channel count and notify anyone that is
+        * interested in this sub-channel, after this sub-channel
+        * is setup.
+        */
+       prichan->ch_subchan_cnt++;
+       mtx_unlock(&prichan->ch_subchan_lock);
+       wakeup(prichan);
+
+       return 0;
+}
+
+void
+vmbus_channel_cpu_set(struct hv_vmbus_channel *chan, int cpu)
+{
+       KASSERT(cpu >= 0 && cpu < mp_ncpus, ("invalid cpu %d", cpu));
+
+       if (chan->vmbus_sc->vmbus_version == VMBUS_VERSION_WS2008 ||
+           chan->vmbus_sc->vmbus_version == VMBUS_VERSION_WIN7) {
+               /* Only cpu0 is supported */
+               cpu = 0;
+       }
+
+       chan->target_cpu = 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",
+                   chan->ch_id,
+                   chan->target_cpu, chan->target_vcpu);
+       }
+}
+
+void
+vmbus_channel_cpu_rr(struct hv_vmbus_channel *chan)
+{
+       static uint32_t vmbus_chan_nextcpu;
+       int cpu;
+
+       cpu = atomic_fetchadd_int(&vmbus_chan_nextcpu, 1) % mp_ncpus;
+       vmbus_channel_cpu_set(chan, cpu);
+}
+
+static void
+vmbus_chan_cpu_default(struct hv_vmbus_channel *chan)
+{
+       /*
+        * By default, pin the channel to cpu0.  Devices having
+        * special channel-cpu mapping requirement should call
+        * vmbus_channel_cpu_{set,rr}().
+        */
+       vmbus_channel_cpu_set(chan, 0);
+}
+
+static void
+vmbus_chan_msgproc_choffer(struct vmbus_softc *sc,
+    const struct vmbus_message *msg)
+{
+       const struct vmbus_chanmsg_choffer *offer;
+       struct hv_vmbus_channel *chan;
+       int error;
+
+       offer = (const struct vmbus_chanmsg_choffer *)msg->msg_data;
+
+       chan = vmbus_chan_alloc(sc);
+       if (chan == NULL) {
+               device_printf(sc->vmbus_dev, "allocate chan%u failed\n",
+                   offer->chm_chanid);
+               return;
+       }
+
+       chan->ch_id = offer->chm_chanid;
+       chan->ch_subidx = offer->chm_subidx;
+       chan->ch_guid_type = offer->chm_chtype;
+       chan->ch_guid_inst = offer->chm_chinst;
+
+       /* Batch reading is on by default */
+       chan->ch_flags |= VMBUS_CHAN_FLAG_BATCHREAD;
+
+       chan->ch_monprm->mp_connid = VMBUS_CONNID_EVENT;
+       if (sc->vmbus_version != VMBUS_VERSION_WS2008)
+               chan->ch_monprm->mp_connid = offer->chm_connid;
+
+       if (offer->chm_flags1 & VMBUS_CHOFFER_FLAG1_HASMNF) {
+               /*
+                * Setup MNF stuffs.
+                */
+               chan->ch_flags |= VMBUS_CHAN_FLAG_HASMNF;
+               chan->ch_montrig_idx = offer->chm_montrig / VMBUS_MONTRIG_LEN;
+               if (chan->ch_montrig_idx >= VMBUS_MONTRIGS_MAX)
+                       panic("invalid monitor trigger %u", offer->chm_montrig);
+               chan->ch_montrig_mask =
+                   1 << (offer->chm_montrig % VMBUS_MONTRIG_LEN);
+       }
+
+       /* Select default cpu for this channel. */
+       vmbus_chan_cpu_default(chan);
+
+       error = vmbus_chan_add(chan);
+       if (error) {
+               device_printf(sc->vmbus_dev, "add chan%u failed: %d\n",
+                   chan->ch_id, error);
+               vmbus_chan_free(chan);
+               return;
+       }
+
+       if (VMBUS_CHAN_ISPRIMARY(chan)) {
+               /*
+                * Add device for this primary channel.
+                *
+                * NOTE:
+                * Error is ignored here; don't have much to do if error
+                * really happens.
+                */
+               hv_vmbus_child_device_register(chan);
+       }
+}
+
+/*
+ * XXX pretty broken; need rework.
+ */
+static void
+vmbus_chan_msgproc_chrescind(struct vmbus_softc *sc,
+    const struct vmbus_message *msg)
+{
+       const struct vmbus_chanmsg_chrescind *note;
+       struct hv_vmbus_channel *chan;
+
+       note = (const struct vmbus_chanmsg_chrescind *)msg->msg_data;
+       if (note->chm_chanid > VMBUS_CHAN_MAX) {
+               device_printf(sc->vmbus_dev, "invalid rescinded chan%u\n",
+                   note->chm_chanid);
+               return;
+       }
+
+       if (bootverbose) {
+               device_printf(sc->vmbus_dev, "chan%u rescinded\n",
+                   note->chm_chanid);
+       }
+
+       chan = sc->vmbus_chmap[note->chm_chanid];
+       if (chan == NULL)
+               return;
+       sc->vmbus_chmap[note->chm_chanid] = NULL;
+
+       taskqueue_enqueue(taskqueue_thread, &chan->ch_detach_task);
+}
+
+static void
+vmbus_chan_detach_task(void *xchan, int pending __unused)
+{
+       struct hv_vmbus_channel *chan = xchan;
+
+       if (VMBUS_CHAN_ISPRIMARY(chan)) {
+               /* Only primary channel owns the device */
+               hv_vmbus_child_device_unregister(chan);
+               /* NOTE: DO NOT free primary channel for now */
+       } else {
+               struct vmbus_softc *sc = chan->vmbus_sc;
+               struct hv_vmbus_channel *pri_chan = chan->ch_prichan;
+               struct vmbus_chanmsg_chfree *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 chfree(chan%u)\n",
+                           chan->ch_id);
+                       goto remove;
+               }
+
+               req = vmbus_msghc_dataptr(mh);
+               req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHFREE;
+               req->chm_chanid = chan->ch_id;
+
+               error = vmbus_msghc_exec_noresult(mh);
+               vmbus_msghc_put(sc, mh);
+
+               if (error) {
+                       device_printf(sc->vmbus_dev,
+                           "chfree(chan%u) failed: %d",
+                           chan->ch_id, error);
+                       /* NOTE: Move on! */
+               } else {
+                       if (bootverbose) {
+                               device_printf(sc->vmbus_dev, "chan%u freed\n",
+                                   chan->ch_id);
+                       }
+               }
+remove:
+               mtx_lock(&pri_chan->ch_subchan_lock);
+               TAILQ_REMOVE(&pri_chan->ch_subchans, chan, ch_sublink);
+               KASSERT(pri_chan->ch_subchan_cnt > 0,
+                   ("invalid subchan_cnt %d", pri_chan->ch_subchan_cnt));
+               pri_chan->ch_subchan_cnt--;
+               mtx_unlock(&pri_chan->ch_subchan_lock);
+               wakeup(pri_chan);
+
+               vmbus_chan_free(chan);
+       }
+}
+
+/*
+ * Detach all devices and destroy the corresponding primary channels.
+ */
+void
+vmbus_chan_destroy_all(struct vmbus_softc *sc)
+{
+       struct hv_vmbus_channel *chan;
+
+       mtx_lock(&sc->vmbus_prichan_lock);
+       while ((chan = TAILQ_FIRST(&sc->vmbus_prichans)) != NULL) {
+               KASSERT(VMBUS_CHAN_ISPRIMARY(chan), ("not primary channel"));
+               TAILQ_REMOVE(&sc->vmbus_prichans, chan, ch_prilink);
+               mtx_unlock(&sc->vmbus_prichan_lock);
+
+               hv_vmbus_child_device_unregister(chan);
+               vmbus_chan_free(chan);
+
+               mtx_lock(&sc->vmbus_prichan_lock);
+       }
+       bzero(sc->vmbus_chmap,
+           sizeof(struct hv_vmbus_channel *) * VMBUS_CHAN_MAX);
+       mtx_unlock(&sc->vmbus_prichan_lock);
+}
+
+/**
+ * @brief Select the best outgoing channel
+ * 
+ * The channel whose vcpu binding is closest to the currect vcpu will
+ * be selected.
+ * If no multi-channel, always select primary channel
+ * 
+ * @param primary - primary channel
+ */
+struct hv_vmbus_channel *
+vmbus_select_outgoing_channel(struct hv_vmbus_channel *primary)
+{
+       hv_vmbus_channel *new_channel = NULL;
+       hv_vmbus_channel *outgoing_channel = primary;
+       int old_cpu_distance = 0;
+       int new_cpu_distance = 0;
+       int cur_vcpu = 0;
+       int smp_pro_id = PCPU_GET(cpuid);
+
+       if (TAILQ_EMPTY(&primary->ch_subchans)) {
+               return outgoing_channel;
+       }
+
+       if (smp_pro_id >= MAXCPU) {
+               return outgoing_channel;
+       }
+
+       cur_vcpu = VMBUS_PCPU_GET(primary->vmbus_sc, vcpuid, smp_pro_id);
+       
+       /* XXX need lock */
+       TAILQ_FOREACH(new_channel, &primary->ch_subchans, ch_sublink) {
+               if ((new_channel->ch_stflags & VMBUS_CHAN_ST_OPENED) == 0) {
+                       continue;
+               }
+
+               if (new_channel->target_vcpu == cur_vcpu){
+                       return new_channel;
+               }
+
+               old_cpu_distance = ((outgoing_channel->target_vcpu > cur_vcpu) ?
+                   (outgoing_channel->target_vcpu - cur_vcpu) :
+                   (cur_vcpu - outgoing_channel->target_vcpu));
+
+               new_cpu_distance = ((new_channel->target_vcpu > cur_vcpu) ?
+                   (new_channel->target_vcpu - cur_vcpu) :
+                   (cur_vcpu - new_channel->target_vcpu));
+
+               if (old_cpu_distance < new_cpu_distance) {
+                       continue;
+               }
+
+               outgoing_channel = new_channel;
+       }
+
+       return(outgoing_channel);
+}
+
+struct hv_vmbus_channel **
+vmbus_get_subchan(struct hv_vmbus_channel *pri_chan, int subchan_cnt)
+{
+       struct hv_vmbus_channel **ret, *chan;
+       int i;
+
+       ret = malloc(subchan_cnt * sizeof(struct hv_vmbus_channel *), M_TEMP,
+           M_WAITOK);
+
+       mtx_lock(&pri_chan->ch_subchan_lock);
+
+       while (pri_chan->ch_subchan_cnt < subchan_cnt)
+               mtx_sleep(pri_chan, &pri_chan->ch_subchan_lock, 0, "subch", 0);
+
+       i = 0;
+       TAILQ_FOREACH(chan, &pri_chan->ch_subchans, ch_sublink) {
+               /* TODO: refcnt chan */
+               ret[i] = chan;
+
+               ++i;
+               if (i == subchan_cnt)
+                       break;
+       }
+       KASSERT(i == subchan_cnt, ("invalid subchan count %d, should be %d",
+           pri_chan->ch_subchan_cnt, subchan_cnt));
+
+       mtx_unlock(&pri_chan->ch_subchan_lock);
+
+       return ret;
+}
+
+void
+vmbus_rel_subchan(struct hv_vmbus_channel **subchan, int subchan_cnt __unused)
+{
+
+       free(subchan, M_TEMP);
+}
+
+void
+vmbus_drain_subchan(struct hv_vmbus_channel *pri_chan)
+{
+       mtx_lock(&pri_chan->ch_subchan_lock);
+       while (pri_chan->ch_subchan_cnt > 0)
+               mtx_sleep(pri_chan, &pri_chan->ch_subchan_lock, 0, "dsubch", 0);
+       mtx_unlock(&pri_chan->ch_subchan_lock);
+}
+
+void
+vmbus_chan_msgproc(struct vmbus_softc *sc, const struct vmbus_message *msg)
+{
+       vmbus_chanmsg_proc_t msg_proc;
+       uint32_t msg_type;
+
+       msg_type = ((const struct vmbus_chanmsg_hdr *)msg->msg_data)->chm_type;
+       KASSERT(msg_type < VMBUS_CHANMSG_TYPE_MAX,
+           ("invalid message type %u", msg_type));
+
+       msg_proc = vmbus_chan_msgprocs[msg_type];
+       if (msg_proc != NULL)
+               msg_proc(sc, msg);
+}

Modified: stable/11/sys/dev/hyperv/vmbus/vmbus.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus.c      Mon Oct 17 02:02:44 2016        
(r307450)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus.c      Mon Oct 17 02:12:49 2016        
(r307451)
@@ -98,7 +98,12 @@ static int                   vmbus_req_channels(struct v
 static void                    vmbus_disconnect(struct vmbus_softc *);
 static int                     vmbus_scan(struct vmbus_softc *);
 static void                    vmbus_scan_wait(struct vmbus_softc *);
+static void                    vmbus_scan_newchan(struct vmbus_softc *);
 static void                    vmbus_scan_newdev(struct vmbus_softc *);
+static void                    vmbus_scan_done(struct vmbus_softc *,
+                                   const struct vmbus_message *);
+static void                    vmbus_chanmsg_handle(struct vmbus_softc *,
+                                   const struct vmbus_message *);
 
 static int                     vmbus_sysctl_version(SYSCTL_HANDLER_ARGS);
 
@@ -122,6 +127,12 @@ static const uint32_t              vmbus_version[] =
        VMBUS_VERSION_WS2008
 };
 
+static const vmbus_chanmsg_proc_t
+vmbus_chanmsg_handlers[VMBUS_CHANMSG_TYPE_MAX] = {
+       VMBUS_CHANMSG_PROC(CHOFFER_DONE, vmbus_scan_done),
+       VMBUS_CHANMSG_PROC_WAKEUP(CONNECT_RESP)
+};
+
 static struct vmbus_msghc *
 vmbus_msghc_alloc(bus_dma_tag_t parent_dtag)
 {
@@ -480,7 +491,7 @@ vmbus_req_channels(struct vmbus_softc *s
        return error;
 }
 
-void
+static void
 vmbus_scan_newchan(struct vmbus_softc *sc)
 {
        mtx_lock(&sc->vmbus_scan_lock);
@@ -489,8 +500,9 @@ vmbus_scan_newchan(struct vmbus_softc *s
        mtx_unlock(&sc->vmbus_scan_lock);
 }
 
-void
-vmbus_scan_done(struct vmbus_softc *sc)
+static void
+vmbus_scan_done(struct vmbus_softc *sc,
+    const struct vmbus_message *msg __unused)
 {
        mtx_lock(&sc->vmbus_scan_lock);
        sc->vmbus_scan_chcnt |= VMBUS_SCAN_CHCNT_DONE;
@@ -560,6 +572,27 @@ vmbus_scan(struct vmbus_softc *sc)
 }
 
 static void
+vmbus_chanmsg_handle(struct vmbus_softc *sc, const struct vmbus_message *msg)
+{
+       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 >= VMBUS_CHANMSG_TYPE_MAX) {
+               device_printf(sc->vmbus_dev, "unknown message type 0x%x\n",
+                   msg_type);
+               return;
+       }
+
+       msg_proc = vmbus_chanmsg_handlers[msg_type];
+       if (msg_proc != NULL)
+               msg_proc(sc, msg);
+
+       /* Channel specific processing */
+       vmbus_chan_msgproc(sc, msg);
+}
+
+static void
 vmbus_msg_task(void *xsc, int pending __unused)
 {
        struct vmbus_softc *sc = xsc;
@@ -572,7 +605,7 @@ vmbus_msg_task(void *xsc, int pending __
                        break;
                } else if (msg->msg_type == HYPERV_MSGTYPE_CHANNEL) {
                        /* Channel message */
-                       vmbus_chan_msgproc(sc,
+                       vmbus_chanmsg_handle(sc,
                            __DEVOLATILE(const struct vmbus_message *, msg));
                }
 

Modified: stable/11/sys/dev/hyperv/vmbus/vmbus_var.h
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus_var.h  Mon Oct 17 02:02:44 2016        
(r307450)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus_var.h  Mon Oct 17 02:12:49 2016        
(r307451)
@@ -52,6 +52,17 @@
 #define VMBUS_CONNID_MESSAGE           1
 #define VMBUS_CONNID_EVENT             2
 
+struct vmbus_message;
+struct vmbus_softc;
+
+typedef void           (*vmbus_chanmsg_proc_t)(struct vmbus_softc *,
+                           const struct vmbus_message *);
+
+#define VMBUS_CHANMSG_PROC(name, func) \
+       [VMBUS_CHANMSG_TYPE_##name] = func
+#define VMBUS_CHANMSG_PROC_WAKEUP(name)        \
+       VMBUS_CHANMSG_PROC(name, vmbus_msghc_wakeup)
+
 struct vmbus_pcpu_data {
        u_long                  *intr_cnt;      /* Hyper-V interrupt counter */
        struct vmbus_message    *message;       /* shared messages */
@@ -151,9 +162,6 @@ const struct vmbus_message *vmbus_msghc_
 void   vmbus_msghc_wakeup(struct vmbus_softc *, const struct vmbus_message *);
 void   vmbus_msghc_reset(struct vmbus_msghc *, size_t);
 
-void   vmbus_scan_done(struct vmbus_softc *);
-void   vmbus_scan_newchan(struct vmbus_softc *);
-
 uint32_t vmbus_gpadl_alloc(struct vmbus_softc *);
 
 #endif /* !_VMBUS_VAR_H_ */

Modified: stable/11/sys/modules/hyperv/vmbus/Makefile
==============================================================================
--- stable/11/sys/modules/hyperv/vmbus/Makefile Mon Oct 17 02:02:44 2016        
(r307450)
+++ stable/11/sys/modules/hyperv/vmbus/Makefile Mon Oct 17 02:12:49 2016        
(r307451)
@@ -5,7 +5,6 @@
 
 KMOD=  hv_vmbus
 SRCS=  hv_channel.c \
-       hv_channel_mgmt.c \
        hv_ring_buffer.c \
        hyperv.c \
        hyperv_busdma.c \
_______________________________________________
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