Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F106100492
D7126.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
29 KB
Referenced Files
None
Subscribers
None
D7126.diff
View Options
Index: head/sys/conf/files.amd64
===================================================================
--- head/sys/conf/files.amd64
+++ head/sys/conf/files.amd64
@@ -271,7 +271,6 @@
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
Index: head/sys/conf/files.i386
===================================================================
--- head/sys/conf/files.i386
+++ head/sys/conf/files.i386
@@ -247,7 +247,6 @@
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
Index: head/sys/dev/hyperv/vmbus/hv_channel.c
===================================================================
--- head/sys/dev/hyperv/vmbus/hv_channel.c
+++ head/sys/dev/hyperv/vmbus/hv_channel.c
@@ -53,8 +53,28 @@
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
@@ -984,3 +1004,463 @@
}
}
}
+
+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);
+}
Index: head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
===================================================================
--- head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
+++ head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
@@ -1,518 +0,0 @@
-/*-
- * Copyright (c) 2009-2012,2016 Microsoft Corp.
- * Copyright (c) 2012 NetApp Inc.
- * Copyright (c) 2012 Citrix Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice unmodified, this list of conditions, and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/mbuf.h>
-#include <sys/mutex.h>
-
-#include <dev/hyperv/include/hyperv_busdma.h>
-#include <dev/hyperv/vmbus/hv_vmbus_priv.h>
-#include <dev/hyperv/vmbus/vmbus_reg.h>
-#include <dev/hyperv/vmbus/vmbus_var.h>
-
-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)
-};
-
-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);
-}
Index: head/sys/modules/hyperv/vmbus/Makefile
===================================================================
--- head/sys/modules/hyperv/vmbus/Makefile
+++ head/sys/modules/hyperv/vmbus/Makefile
@@ -5,7 +5,6 @@
KMOD= hv_vmbus
SRCS= hv_channel.c \
- hv_channel_mgmt.c \
hv_ring_buffer.c \
hyperv.c \
hyperv_busdma.c \
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Dec 26, 10:02 AM (11 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15603630
Default Alt Text
D7126.diff (29 KB)
Attached To
Mode
D7126: hyperv/vmbus: Merge hv_channel_mgmt.c into hv_channel.c
Attached
Detach File
Event Timeline
Log In to Comment