Page MenuHomeFreeBSD

D8738.diff
No OneTemporary

D8738.diff

Index: head/sys/dev/hyperv/include/vmbus.h
===================================================================
--- head/sys/dev/hyperv/include/vmbus.h
+++ head/sys/dev/hyperv/include/vmbus.h
@@ -49,6 +49,9 @@
#define VMBUS_VERSION_MAJOR(ver) (((uint32_t)(ver)) >> 16)
#define VMBUS_VERSION_MINOR(ver) (((uint32_t)(ver)) & 0xffff)
+#define VMBUS_CHAN_POLLHZ_MIN 100 /* 10ms interval */
+#define VMBUS_CHAN_POLLHZ_MAX 1000000 /* 1us interval */
+
/*
* GPA stuffs.
*/
@@ -220,4 +223,8 @@
struct taskqueue *
vmbus_chan_mgmt_tq(const struct vmbus_channel *chan);
+void vmbus_chan_poll_enable(struct vmbus_channel *chan,
+ u_int pollhz);
+void vmbus_chan_poll_disable(struct vmbus_channel *chan);
+
#endif /* !_VMBUS_H_ */
Index: head/sys/dev/hyperv/vmbus/vmbus_chan.c
===================================================================
--- head/sys/dev/hyperv/vmbus/vmbus_chan.c
+++ head/sys/dev/hyperv/vmbus/vmbus_chan.c
@@ -31,6 +31,7 @@
#include <sys/param.h>
#include <sys/bus.h>
+#include <sys/callout.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
@@ -50,6 +51,11 @@
#include <dev/hyperv/vmbus/vmbus_brvar.h>
#include <dev/hyperv/vmbus/vmbus_chanvar.h>
+struct vmbus_chan_pollarg {
+ struct vmbus_channel *poll_chan;
+ u_int poll_hz;
+};
+
static void vmbus_chan_update_evtflagcnt(
struct vmbus_softc *,
const struct vmbus_channel *);
@@ -68,6 +74,10 @@
static void vmbus_chan_detach(struct vmbus_channel *);
static bool vmbus_chan_wait_revoke(
const struct vmbus_channel *, bool);
+static void vmbus_chan_poll_timeout(void *);
+static bool vmbus_chan_poll_cancel_intq(
+ struct vmbus_channel *);
+static void vmbus_chan_poll_cancel(struct vmbus_channel *);
static void vmbus_chan_ins_prilist(struct vmbus_softc *,
struct vmbus_channel *);
@@ -84,7 +94,11 @@
static void vmbus_chan_task(void *, int);
static void vmbus_chan_task_nobatch(void *, int);
+static void vmbus_chan_poll_task(void *, int);
static void vmbus_chan_clrchmap_task(void *, int);
+static void vmbus_chan_pollcfg_task(void *, int);
+static void vmbus_chan_polldis_task(void *, int);
+static void vmbus_chan_poll_cancel_task(void *, int);
static void vmbus_prichan_attach_task(void *, int);
static void vmbus_subchan_attach_task(void *, int);
static void vmbus_prichan_detach_task(void *, int);
@@ -782,6 +796,22 @@
chan->ch_vmbus->vmbus_chmap[chan->ch_id] = chan;
}
+static void
+vmbus_chan_poll_cancel_task(void *xchan, int pending __unused)
+{
+
+ vmbus_chan_poll_cancel_intq(xchan);
+}
+
+static void
+vmbus_chan_poll_cancel(struct vmbus_channel *chan)
+{
+ struct task poll_cancel;
+
+ TASK_INIT(&poll_cancel, 0, vmbus_chan_poll_cancel_task, chan);
+ vmbus_chan_run_task(chan, &poll_cancel);
+}
+
static int
vmbus_chan_close_internal(struct vmbus_channel *chan)
{
@@ -818,6 +848,11 @@
sysctl_ctx_free(&chan->ch_sysctl_ctx);
/*
+ * Cancel polling, if it is enabled.
+ */
+ vmbus_chan_poll_cancel(chan);
+
+ /*
* NOTE:
* Order is critical. This channel _must_ be uninstalled first,
* else the channel task may be enqueued by the IDT after it has
@@ -1185,6 +1220,9 @@
vmbus_chan_callback_t cb = chan->ch_cb;
void *cbarg = chan->ch_cbarg;
+ KASSERT(chan->ch_poll_intvl == 0,
+ ("chan%u: interrupted in polling mode", chan->ch_id));
+
/*
* Optimize host to guest signaling by ensuring:
* 1. While reading the channel, we disable interrupts from
@@ -1216,9 +1254,145 @@
{
struct vmbus_channel *chan = xchan;
+ KASSERT(chan->ch_poll_intvl == 0,
+ ("chan%u: interrupted in polling mode", chan->ch_id));
+ chan->ch_cb(chan, chan->ch_cbarg);
+}
+
+static void
+vmbus_chan_poll_timeout(void *xchan)
+{
+ struct vmbus_channel *chan = xchan;
+
+ KASSERT(chan->ch_poll_intvl != 0,
+ ("chan%u: polling timeout in interrupt mode", chan->ch_id));
+ taskqueue_enqueue(chan->ch_tq, &chan->ch_poll_task);
+}
+
+static void
+vmbus_chan_poll_task(void *xchan, int pending __unused)
+{
+ struct vmbus_channel *chan = xchan;
+
+ KASSERT(chan->ch_poll_intvl != 0,
+ ("chan%u: polling in interrupt mode", chan->ch_id));
+ callout_reset_sbt_curcpu(&chan->ch_poll_timeo, chan->ch_poll_intvl, 0,
+ vmbus_chan_poll_timeout, chan, chan->ch_poll_flags);
chan->ch_cb(chan, chan->ch_cbarg);
}
+static void
+vmbus_chan_pollcfg_task(void *xarg, int pending __unused)
+{
+ const struct vmbus_chan_pollarg *arg = xarg;
+ struct vmbus_channel *chan = arg->poll_chan;
+ sbintime_t intvl;
+ int poll_flags;
+
+ /*
+ * Save polling interval.
+ */
+ intvl = SBT_1S / arg->poll_hz;
+ if (intvl == 0)
+ intvl = 1;
+ if (intvl == chan->ch_poll_intvl) {
+ /* Nothing changes; done */
+ return;
+ }
+ chan->ch_poll_intvl = intvl;
+
+ /* Adjust callout flags. */
+ poll_flags = C_DIRECT_EXEC;
+ if (arg->poll_hz <= hz)
+ poll_flags |= C_HARDCLOCK;
+ chan->ch_poll_flags = poll_flags;
+
+ /*
+ * Disable interrupt from the RX bufring (TX bufring does not
+ * generate interrupt to VM), and disconnect this channel from
+ * the channel map to make sure that ISR can not enqueue this
+ * channel task anymore.
+ */
+ critical_enter();
+ vmbus_rxbr_intr_mask(&chan->ch_rxbr);
+ chan->ch_vmbus->vmbus_chmap[chan->ch_id] = NULL;
+ critical_exit();
+
+ /*
+ * NOTE:
+ * At this point, this channel task will not be enqueued by
+ * the ISR anymore, time to cancel the pending one.
+ */
+ taskqueue_cancel(chan->ch_tq, &chan->ch_task, NULL);
+
+ /* Kick start! */
+ taskqueue_enqueue(chan->ch_tq, &chan->ch_poll_task);
+}
+
+static bool
+vmbus_chan_poll_cancel_intq(struct vmbus_channel *chan)
+{
+
+ if (chan->ch_poll_intvl == 0) {
+ /* Not enabled. */
+ return (false);
+ }
+
+ /*
+ * Stop polling callout, so that channel polling task
+ * will not be enqueued anymore.
+ */
+ callout_drain(&chan->ch_poll_timeo);
+
+ /*
+ * Disable polling by resetting polling interval.
+ *
+ * NOTE:
+ * The polling interval resetting MUST be conducted
+ * after the callout is drained; mainly to keep the
+ * proper assertion in place.
+ */
+ chan->ch_poll_intvl = 0;
+
+ /*
+ * NOTE:
+ * At this point, this channel polling task will not be
+ * enqueued by the callout anymore, time to cancel the
+ * pending one.
+ */
+ taskqueue_cancel(chan->ch_tq, &chan->ch_poll_task, NULL);
+
+ /* Polling was enabled. */
+ return (true);
+}
+
+static void
+vmbus_chan_polldis_task(void *xchan, int pending __unused)
+{
+ struct vmbus_channel *chan = xchan;
+
+ if (!vmbus_chan_poll_cancel_intq(chan)) {
+ /* Already disabled; done. */
+ return;
+ }
+
+ /*
+ * Plug this channel back to the channel map and unmask
+ * the RX bufring interrupt.
+ */
+ critical_enter();
+ chan->ch_vmbus->vmbus_chmap[chan->ch_id] = chan;
+ __compiler_membar();
+ vmbus_rxbr_intr_unmask(&chan->ch_rxbr);
+ critical_exit();
+
+ /*
+ * Kick start the interrupt task, just in case unmasking
+ * interrupt races ISR.
+ */
+ taskqueue_enqueue(chan->ch_tq, &chan->ch_task);
+}
+
static __inline void
vmbus_event_flags_proc(struct vmbus_softc *sc, volatile u_long *event_flags,
int flag_cnt)
@@ -1333,6 +1507,9 @@
vmbus_rxbr_init(&chan->ch_rxbr);
vmbus_txbr_init(&chan->ch_txbr);
+ TASK_INIT(&chan->ch_poll_task, 0, vmbus_chan_poll_task, chan);
+ callout_init(&chan->ch_poll_timeo, 1);
+
return chan;
}
@@ -1351,6 +1528,8 @@
("still has orphan xact installed"));
KASSERT(chan->ch_refs == 0, ("chan%u: invalid refcnt %d",
chan->ch_id, chan->ch_refs));
+ KASSERT(chan->ch_poll_intvl == 0, ("chan%u: polling is activated",
+ chan->ch_id));
hyperv_dmamem_free(&chan->ch_monprm_dma, chan->ch_monprm);
mtx_destroy(&chan->ch_subchan_lock);
@@ -1998,3 +2177,32 @@
}
return (ret);
}
+
+void
+vmbus_chan_poll_enable(struct vmbus_channel *chan, u_int pollhz)
+{
+ struct vmbus_chan_pollarg arg;
+ struct task poll_cfg;
+
+ KASSERT(chan->ch_flags & VMBUS_CHAN_FLAG_BATCHREAD,
+ ("enable polling on non-batch chan%u", chan->ch_id));
+ KASSERT(pollhz >= VMBUS_CHAN_POLLHZ_MIN &&
+ pollhz <= VMBUS_CHAN_POLLHZ_MAX, ("invalid pollhz %u", pollhz));
+
+ arg.poll_chan = chan;
+ arg.poll_hz = pollhz;
+ TASK_INIT(&poll_cfg, 0, vmbus_chan_pollcfg_task, &arg);
+ vmbus_chan_run_task(chan, &poll_cfg);
+}
+
+void
+vmbus_chan_poll_disable(struct vmbus_channel *chan)
+{
+ struct task poll_dis;
+
+ KASSERT(chan->ch_flags & VMBUS_CHAN_FLAG_BATCHREAD,
+ ("disable polling on non-batch chan%u", chan->ch_id));
+
+ TASK_INIT(&poll_dis, 0, vmbus_chan_polldis_task, chan);
+ vmbus_chan_run_task(chan, &poll_dis);
+}
Index: head/sys/dev/hyperv/vmbus/vmbus_chanvar.h
===================================================================
--- head/sys/dev/hyperv/vmbus/vmbus_chanvar.h
+++ head/sys/dev/hyperv/vmbus/vmbus_chanvar.h
@@ -30,6 +30,7 @@
#define _VMBUS_CHANVAR_H_
#include <sys/param.h>
+#include <sys/callout.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/queue.h>
@@ -49,6 +50,7 @@
* target CPU.
*/
uint32_t ch_flags; /* VMBUS_CHAN_FLAG_ */
+ int ch_poll_flags; /* callout flags */
/*
* RX bufring; immediately following ch_txbr.
@@ -57,6 +59,9 @@
struct taskqueue *ch_tq;
struct task ch_task;
+ struct task ch_poll_task;
+ sbintime_t ch_poll_intvl;
+ struct callout ch_poll_timeo;
vmbus_chan_callback_t ch_cb;
void *ch_cbarg;

File Metadata

Mime Type
text/plain
Expires
Thu, Dec 26, 11:18 AM (12 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15604185
Default Alt Text
D8738.diff (9 KB)

Event Timeline