2 * Copyright (c) 2009-2012,2016 Microsoft Corp.
3 * Copyright (c) 2012 NetApp Inc.
4 * Copyright (c) 2012 Citrix Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/kernel.h>
36 #include <sys/mutex.h>
38 #include <dev/hyperv/include/hyperv_busdma.h>
39 #include <dev/hyperv/vmbus/hv_vmbus_priv.h>
40 #include <dev/hyperv/vmbus/vmbus_reg.h>
41 #include <dev/hyperv/vmbus/vmbus_var.h>
43 typedef void (*vmbus_chanmsg_proc_t)
44 (struct vmbus_softc *, const struct vmbus_message *);
46 static struct hv_vmbus_channel *hv_vmbus_allocate_channel(struct vmbus_softc *);
47 static void vmbus_channel_on_offer_internal(struct vmbus_softc *,
48 const struct vmbus_chanmsg_choffer *);
49 static void vmbus_chan_detach_task(void *, int);
51 static void vmbus_channel_on_offer(struct vmbus_softc *,
52 const struct vmbus_message *);
53 static void vmbus_channel_on_offers_delivered(struct vmbus_softc *,
54 const struct vmbus_message *);
55 static void vmbus_chan_msgproc_chrescind(struct vmbus_softc *,
56 const struct vmbus_message *);
59 * Vmbus channel message processing.
62 #define VMBUS_CHANMSG_PROC(name, func) \
63 [VMBUS_CHANMSG_TYPE_##name] = func
64 #define VMBUS_CHANMSG_PROC_WAKEUP(name) \
65 VMBUS_CHANMSG_PROC(name, vmbus_msghc_wakeup)
67 static const vmbus_chanmsg_proc_t
68 vmbus_chanmsg_process[VMBUS_CHANMSG_TYPE_MAX] = {
69 VMBUS_CHANMSG_PROC(CHOFFER, vmbus_channel_on_offer),
70 VMBUS_CHANMSG_PROC(CHRESCIND, vmbus_chan_msgproc_chrescind),
71 VMBUS_CHANMSG_PROC(CHOFFER_DONE,vmbus_channel_on_offers_delivered),
73 VMBUS_CHANMSG_PROC_WAKEUP(CHOPEN_RESP),
74 VMBUS_CHANMSG_PROC_WAKEUP(GPADL_CONNRESP),
75 VMBUS_CHANMSG_PROC_WAKEUP(GPADL_DISCONNRESP),
76 VMBUS_CHANMSG_PROC_WAKEUP(CONNECT_RESP)
79 #undef VMBUS_CHANMSG_PROC_WAKEUP
80 #undef VMBUS_CHANMSG_PROC
83 * @brief Allocate and initialize a vmbus channel object
85 static struct hv_vmbus_channel *
86 hv_vmbus_allocate_channel(struct vmbus_softc *sc)
88 struct hv_vmbus_channel *channel;
90 channel = malloc(sizeof(*channel), M_DEVBUF, M_WAITOK | M_ZERO);
91 channel->vmbus_sc = sc;
93 mtx_init(&channel->sc_lock, "vmbus multi channel", NULL, MTX_DEF);
94 TAILQ_INIT(&channel->sc_list_anchor);
95 TASK_INIT(&channel->ch_detach_task, 0, vmbus_chan_detach_task, channel);
101 * @brief Release the resources used by the vmbus channel object
104 hv_vmbus_free_vmbus_channel(hv_vmbus_channel* channel)
106 mtx_destroy(&channel->sc_lock);
107 free(channel, M_DEVBUF);
111 * @brief Process the offer by creating a channel/device
112 * associated with this offer
115 vmbus_channel_process_offer(hv_vmbus_channel *new_channel)
117 struct vmbus_softc *sc = new_channel->vmbus_sc;
118 hv_vmbus_channel* channel;
121 * Make sure this is a new offer
123 mtx_lock(&sc->vmbus_chlist_lock);
124 if (new_channel->ch_id == 0) {
126 * XXX channel0 will not be processed; skip it.
128 printf("VMBUS: got channel0 offer\n");
130 sc->vmbus_chmap[new_channel->ch_id] = new_channel;
133 TAILQ_FOREACH(channel, &sc->vmbus_chlist, ch_link) {
134 if (memcmp(&channel->ch_guid_type, &new_channel->ch_guid_type,
135 sizeof(struct hyperv_guid)) == 0 &&
136 memcmp(&channel->ch_guid_inst, &new_channel->ch_guid_inst,
137 sizeof(struct hyperv_guid)) == 0)
141 if (channel == NULL) {
142 /* Install the new primary channel */
143 TAILQ_INSERT_TAIL(&sc->vmbus_chlist, new_channel, ch_link);
145 mtx_unlock(&sc->vmbus_chlist_lock);
151 if (channel != NULL) {
152 snprintf(logstr, sizeof(logstr), ", primary chan%u",
155 device_printf(sc->vmbus_dev, "chan%u subchanid%u offer%s\n",
157 new_channel->ch_subidx, logstr);
160 if (channel != NULL) {
162 * Check if this is a sub channel.
164 if (new_channel->ch_subidx != 0) {
166 * It is a sub channel offer, process it.
168 new_channel->primary_channel = channel;
169 new_channel->ch_dev = channel->ch_dev;
170 mtx_lock(&channel->sc_lock);
171 TAILQ_INSERT_TAIL(&channel->sc_list_anchor,
172 new_channel, sc_list_entry);
173 mtx_unlock(&channel->sc_lock);
176 * Insert the new channel to the end of the global
180 * The new sub-channel MUST be inserted AFTER it's
181 * primary channel, so that the primary channel will
182 * be found in the above loop for its baby siblings.
184 mtx_lock(&sc->vmbus_chlist_lock);
185 TAILQ_INSERT_TAIL(&sc->vmbus_chlist, new_channel,
187 mtx_unlock(&sc->vmbus_chlist_lock);
189 new_channel->state = HV_CHANNEL_OPEN_STATE;
192 * Bump up sub-channel count and notify anyone that is
193 * interested in this sub-channel, after this sub-channel
196 mtx_lock(&channel->sc_lock);
197 channel->subchan_cnt++;
198 mtx_unlock(&channel->sc_lock);
204 printf("VMBUS: duplicated primary channel%u\n",
206 hv_vmbus_free_vmbus_channel(new_channel);
210 new_channel->state = HV_CHANNEL_OPEN_STATE;
213 * Add the new device to the bus. This will kick off device-driver
214 * binding which eventually invokes the device driver's AddDevice()
218 * Error is ignored here; don't have much to do if error really
221 hv_vmbus_child_device_register(new_channel);
225 vmbus_channel_cpu_set(struct hv_vmbus_channel *chan, int cpu)
227 KASSERT(cpu >= 0 && cpu < mp_ncpus, ("invalid cpu %d", cpu));
229 if (chan->vmbus_sc->vmbus_version == VMBUS_VERSION_WS2008 ||
230 chan->vmbus_sc->vmbus_version == VMBUS_VERSION_WIN7) {
231 /* Only cpu0 is supported */
235 chan->target_cpu = cpu;
236 chan->target_vcpu = VMBUS_PCPU_GET(chan->vmbus_sc, vcpuid, cpu);
239 printf("vmbus_chan%u: assigned to cpu%u [vcpu%u]\n",
241 chan->target_cpu, chan->target_vcpu);
246 vmbus_channel_cpu_rr(struct hv_vmbus_channel *chan)
248 static uint32_t vmbus_chan_nextcpu;
251 cpu = atomic_fetchadd_int(&vmbus_chan_nextcpu, 1) % mp_ncpus;
252 vmbus_channel_cpu_set(chan, cpu);
256 vmbus_channel_select_defcpu(struct hv_vmbus_channel *chan)
259 * By default, pin the channel to cpu0. Devices having
260 * special channel-cpu mapping requirement should call
261 * vmbus_channel_cpu_{set,rr}().
263 vmbus_channel_cpu_set(chan, 0);
267 * @brief Handler for channel offers from Hyper-V/Azure
269 * Handler for channel offers from vmbus in parent partition.
272 vmbus_channel_on_offer(struct vmbus_softc *sc, const struct vmbus_message *msg)
274 /* New channel is offered by vmbus */
275 vmbus_scan_newchan(sc);
277 vmbus_channel_on_offer_internal(sc,
278 (const struct vmbus_chanmsg_choffer *)msg->msg_data);
282 vmbus_channel_on_offer_internal(struct vmbus_softc *sc,
283 const struct vmbus_chanmsg_choffer *offer)
285 hv_vmbus_channel* new_channel;
288 * Allocate the channel object and save this offer
290 new_channel = hv_vmbus_allocate_channel(sc);
291 new_channel->ch_id = offer->chm_chanid;
292 new_channel->ch_subidx = offer->chm_subidx;
293 new_channel->ch_guid_type = offer->chm_chtype;
294 new_channel->ch_guid_inst = offer->chm_chinst;
296 /* Batch reading is on by default */
297 new_channel->ch_flags |= VMBUS_CHAN_FLAG_BATCHREAD;
298 if (offer->chm_flags1 & VMBUS_CHOFFER_FLAG1_HASMNF)
299 new_channel->ch_flags |= VMBUS_CHAN_FLAG_HASMNF;
301 new_channel->ch_monprm = hyperv_dmamem_alloc(
302 bus_get_dma_tag(sc->vmbus_dev),
303 HYPERCALL_PARAM_ALIGN, 0, sizeof(struct hyperv_mon_param),
304 &new_channel->ch_monprm_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
305 if (new_channel->ch_monprm == NULL) {
306 device_printf(sc->vmbus_dev, "monprm alloc failed\n");
308 mtx_destroy(&new_channel->sc_lock);
309 free(new_channel, M_DEVBUF);
312 new_channel->ch_monprm->mp_connid = VMBUS_CONNID_EVENT;
313 if (sc->vmbus_version != VMBUS_VERSION_WS2008)
314 new_channel->ch_monprm->mp_connid = offer->chm_connid;
316 if (new_channel->ch_flags & VMBUS_CHAN_FLAG_HASMNF) {
317 new_channel->ch_montrig_idx =
318 offer->chm_montrig / VMBUS_MONTRIG_LEN;
319 if (new_channel->ch_montrig_idx >= VMBUS_MONTRIGS_MAX)
320 panic("invalid monitor trigger %u", offer->chm_montrig);
321 new_channel->ch_montrig_mask =
322 1 << (offer->chm_montrig % VMBUS_MONTRIG_LEN);
325 /* Select default cpu for this channel. */
326 vmbus_channel_select_defcpu(new_channel);
328 vmbus_channel_process_offer(new_channel);
332 * XXX pretty broken; need rework.
335 vmbus_chan_msgproc_chrescind(struct vmbus_softc *sc,
336 const struct vmbus_message *msg)
338 const struct vmbus_chanmsg_chrescind *note;
339 struct hv_vmbus_channel *chan;
341 note = (const struct vmbus_chanmsg_chrescind *)msg->msg_data;
342 if (note->chm_chanid > VMBUS_CHAN_MAX) {
343 device_printf(sc->vmbus_dev, "invalid rescinded chan%u\n",
349 device_printf(sc->vmbus_dev, "chan%u rescinded\n",
353 chan = sc->vmbus_chmap[note->chm_chanid];
356 sc->vmbus_chmap[note->chm_chanid] = NULL;
358 taskqueue_enqueue(taskqueue_thread, &chan->ch_detach_task);
362 vmbus_chan_detach_task(void *xchan, int pending __unused)
364 struct hv_vmbus_channel *chan = xchan;
366 if (HV_VMBUS_CHAN_ISPRIMARY(chan)) {
367 /* Only primary channel owns the device */
368 hv_vmbus_child_device_unregister(chan);
369 /* NOTE: DO NOT free primary channel for now */
371 struct vmbus_softc *sc = chan->vmbus_sc;
372 struct hv_vmbus_channel *pri_chan = chan->primary_channel;
373 struct vmbus_chanmsg_chfree *req;
374 struct vmbus_msghc *mh;
377 mh = vmbus_msghc_get(sc, sizeof(*req));
379 device_printf(sc->vmbus_dev,
380 "can not get msg hypercall for chfree(chan%u)\n",
385 req = vmbus_msghc_dataptr(mh);
386 req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHFREE;
387 req->chm_chanid = chan->ch_id;
389 error = vmbus_msghc_exec_noresult(mh);
390 vmbus_msghc_put(sc, mh);
393 device_printf(sc->vmbus_dev,
394 "chfree(chan%u) failed: %d",
399 device_printf(sc->vmbus_dev, "chan%u freed\n",
404 mtx_lock(&sc->vmbus_chlist_lock);
405 TAILQ_REMOVE(&sc->vmbus_chlist, chan, ch_link);
406 mtx_unlock(&sc->vmbus_chlist_lock);
408 mtx_lock(&pri_chan->sc_lock);
409 TAILQ_REMOVE(&pri_chan->sc_list_anchor, chan, sc_list_entry);
410 KASSERT(pri_chan->subchan_cnt > 0,
411 ("invalid subchan_cnt %d", pri_chan->subchan_cnt));
412 pri_chan->subchan_cnt--;
413 mtx_unlock(&pri_chan->sc_lock);
416 hv_vmbus_free_vmbus_channel(chan);
422 * @brief Invoked when all offers have been delivered.
425 vmbus_channel_on_offers_delivered(struct vmbus_softc *sc,
426 const struct vmbus_message *msg __unused)
429 /* No more new channels for the channel request. */
434 * @brief Release channels that are unattached/unconnected (i.e., no drivers associated)
437 hv_vmbus_release_unattached_channels(struct vmbus_softc *sc)
439 hv_vmbus_channel *channel;
441 mtx_lock(&sc->vmbus_chlist_lock);
443 while (!TAILQ_EMPTY(&sc->vmbus_chlist)) {
444 channel = TAILQ_FIRST(&sc->vmbus_chlist);
445 TAILQ_REMOVE(&sc->vmbus_chlist, channel, ch_link);
447 if (HV_VMBUS_CHAN_ISPRIMARY(channel)) {
448 /* Only primary channel owns the device */
449 hv_vmbus_child_device_unregister(channel);
451 hv_vmbus_free_vmbus_channel(channel);
453 bzero(sc->vmbus_chmap,
454 sizeof(struct hv_vmbus_channel *) * VMBUS_CHAN_MAX);
456 mtx_unlock(&sc->vmbus_chlist_lock);
460 * @brief Select the best outgoing channel
462 * The channel whose vcpu binding is closest to the currect vcpu will
464 * If no multi-channel, always select primary channel
466 * @param primary - primary channel
468 struct hv_vmbus_channel *
469 vmbus_select_outgoing_channel(struct hv_vmbus_channel *primary)
471 hv_vmbus_channel *new_channel = NULL;
472 hv_vmbus_channel *outgoing_channel = primary;
473 int old_cpu_distance = 0;
474 int new_cpu_distance = 0;
476 int smp_pro_id = PCPU_GET(cpuid);
478 if (TAILQ_EMPTY(&primary->sc_list_anchor)) {
479 return outgoing_channel;
482 if (smp_pro_id >= MAXCPU) {
483 return outgoing_channel;
486 cur_vcpu = VMBUS_PCPU_GET(primary->vmbus_sc, vcpuid, smp_pro_id);
488 TAILQ_FOREACH(new_channel, &primary->sc_list_anchor, sc_list_entry) {
489 if (new_channel->state != HV_CHANNEL_OPENED_STATE){
493 if (new_channel->target_vcpu == cur_vcpu){
497 old_cpu_distance = ((outgoing_channel->target_vcpu > cur_vcpu) ?
498 (outgoing_channel->target_vcpu - cur_vcpu) :
499 (cur_vcpu - outgoing_channel->target_vcpu));
501 new_cpu_distance = ((new_channel->target_vcpu > cur_vcpu) ?
502 (new_channel->target_vcpu - cur_vcpu) :
503 (cur_vcpu - new_channel->target_vcpu));
505 if (old_cpu_distance < new_cpu_distance) {
509 outgoing_channel = new_channel;
512 return(outgoing_channel);
515 struct hv_vmbus_channel **
516 vmbus_get_subchan(struct hv_vmbus_channel *pri_chan, int subchan_cnt)
518 struct hv_vmbus_channel **ret, *chan;
521 ret = malloc(subchan_cnt * sizeof(struct hv_vmbus_channel *), M_TEMP,
524 mtx_lock(&pri_chan->sc_lock);
526 while (pri_chan->subchan_cnt < subchan_cnt)
527 mtx_sleep(pri_chan, &pri_chan->sc_lock, 0, "subch", 0);
530 TAILQ_FOREACH(chan, &pri_chan->sc_list_anchor, sc_list_entry) {
531 /* TODO: refcnt chan */
535 if (i == subchan_cnt)
538 KASSERT(i == subchan_cnt, ("invalid subchan count %d, should be %d",
539 pri_chan->subchan_cnt, subchan_cnt));
541 mtx_unlock(&pri_chan->sc_lock);
547 vmbus_rel_subchan(struct hv_vmbus_channel **subchan, int subchan_cnt __unused)
550 free(subchan, M_TEMP);
554 vmbus_drain_subchan(struct hv_vmbus_channel *pri_chan)
556 mtx_lock(&pri_chan->sc_lock);
557 while (pri_chan->subchan_cnt > 0)
558 mtx_sleep(pri_chan, &pri_chan->sc_lock, 0, "dsubch", 0);
559 mtx_unlock(&pri_chan->sc_lock);
563 vmbus_chan_msgproc(struct vmbus_softc *sc, const struct vmbus_message *msg)
565 vmbus_chanmsg_proc_t msg_proc;
568 msg_type = ((const struct vmbus_chanmsg_hdr *)msg->msg_data)->chm_type;
569 if (msg_type >= VMBUS_CHANMSG_TYPE_MAX) {
570 device_printf(sc->vmbus_dev, "unknown message type 0x%x\n",
575 msg_proc = vmbus_chanmsg_process[msg_type];
576 if (msg_proc != NULL)