Page MenuHomeFreeBSD

D7126.diff
No OneTemporary

D7126.diff

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

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)

Event Timeline