summaryrefslogtreecommitdiff
path: root/include/linux/hyperv.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/hyperv.h')
-rw-r--r--include/linux/hyperv.h247
1 files changed, 114 insertions, 133 deletions
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 183efde54269..e09fc8290c2f 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -32,11 +32,10 @@
#include <linux/scatterlist.h>
#include <linux/list.h>
#include <linux/timer.h>
-#include <linux/workqueue.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/mod_devicetable.h>
-
+#include <linux/interrupt.h>
#define MAX_PAGE_BUFFER_COUNT 32
#define MAX_MULTIPAGE_BUFFER_COUNT 32 /* 128K */
@@ -139,8 +138,8 @@ struct hv_ring_buffer_info {
* for the specified ring buffer
*/
static inline void
-hv_get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi,
- u32 *read, u32 *write)
+hv_get_ringbuffer_availbytes(const struct hv_ring_buffer_info *rbi,
+ u32 *read, u32 *write)
{
u32 read_loc, write_loc, dsize;
@@ -154,7 +153,7 @@ hv_get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi,
*read = dsize - *write;
}
-static inline u32 hv_get_bytes_to_read(struct hv_ring_buffer_info *rbi)
+static inline u32 hv_get_bytes_to_read(const struct hv_ring_buffer_info *rbi)
{
u32 read_loc, write_loc, dsize, read;
@@ -168,7 +167,7 @@ static inline u32 hv_get_bytes_to_read(struct hv_ring_buffer_info *rbi)
return read;
}
-static inline u32 hv_get_bytes_to_write(struct hv_ring_buffer_info *rbi)
+static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi)
{
u32 read_loc, write_loc, dsize, write;
@@ -492,6 +491,12 @@ struct vmbus_channel_rescind_offer {
u32 child_relid;
} __packed;
+static inline u32
+hv_ringbuffer_pending_size(const struct hv_ring_buffer_info *rbi)
+{
+ return rbi->ring_buffer->pending_send_sz;
+}
+
/*
* Request Offer -- no parameters, SynIC message contains the partition ID
* Set Snoop -- no parameters, SynIC message contains the partition ID
@@ -525,10 +530,10 @@ struct vmbus_channel_open_channel {
u32 target_vp;
/*
- * The upstream ring buffer begins at offset zero in the memory
- * described by RingBufferGpadlHandle. The downstream ring buffer
- * follows it at this offset (in pages).
- */
+ * The upstream ring buffer begins at offset zero in the memory
+ * described by RingBufferGpadlHandle. The downstream ring buffer
+ * follows it at this offset (in pages).
+ */
u32 downstream_ringbuffer_pageoffset;
/* User-specific data to be passed along to the server endpoint. */
@@ -641,6 +646,7 @@ struct vmbus_channel_msginfo {
/* Synchronize the request/response if needed */
struct completion waitevent;
+ struct vmbus_channel *waiting_channel;
union {
struct vmbus_channel_version_supported version_supported;
struct vmbus_channel_open_result open_result;
@@ -683,11 +689,6 @@ struct hv_input_signal_event_buffer {
struct hv_input_signal_event event;
};
-enum hv_signal_policy {
- HV_SIGNAL_POLICY_DEFAULT = 0,
- HV_SIGNAL_POLICY_EXPLICIT,
-};
-
enum hv_numa_policy {
HV_BALANCED = 0,
HV_LOCALIZED,
@@ -747,26 +748,27 @@ struct vmbus_channel {
struct vmbus_close_msg close_msg;
- /* Channel callback are invoked in this workqueue context */
- /* HANDLE dataWorkQueue; */
-
+ /* Channel callback's invoked in softirq context */
+ struct tasklet_struct callback_event;
void (*onchannel_callback)(void *context);
void *channel_callback_context;
/*
- * A channel can be marked for efficient (batched)
- * reading:
- * If batched_reading is set to "true", we read until the
- * channel is empty and hold off interrupts from the host
- * during the entire read process.
- * If batched_reading is set to "false", the client is not
- * going to perform batched reading.
- *
- * By default we will enable batched reading; specific
- * drivers that don't want this behavior can turn it off.
+ * A channel can be marked for one of three modes of reading:
+ * BATCHED - callback called from taslket and should read
+ * channel until empty. Interrupts from the host
+ * are masked while read is in process (default).
+ * DIRECT - callback called from tasklet (softirq).
+ * ISR - callback called in interrupt context and must
+ * invoke its own deferred processing.
+ * Host interrupts are disabled and must be re-enabled
+ * when ring is empty.
*/
-
- bool batched_reading;
+ enum hv_callback_mode {
+ HV_CALL_BATCHED,
+ HV_CALL_DIRECT,
+ HV_CALL_ISR
+ } callback_mode;
bool is_dedicated_interrupt;
struct hv_input_signal_event_buffer sig_buf;
@@ -849,23 +851,13 @@ struct vmbus_channel {
* link up channels based on their CPU affinity.
*/
struct list_head percpu_list;
+
/*
- * Host signaling policy: The default policy will be
- * based on the ring buffer state. We will also support
- * a policy where the client driver can have explicit
- * signaling control.
- */
- enum hv_signal_policy signal_policy;
- /*
- * On the channel send side, many of the VMBUS
- * device drivers explicity serialize access to the
- * outgoing ring buffer. Give more control to the
- * VMBUS device drivers in terms how to serialize
- * accesss to the outgoing ring buffer.
- * The default behavior will be to aquire the
- * ring lock to preserve the current behavior.
+ * Defer freeing channel until after all cpu's have
+ * gone through grace period.
*/
- bool acquire_ring_lock;
+ struct rcu_head rcu;
+
/*
* For performance critical channels (storage, networking
* etc,), Hyper-V has a mechanism to enhance the throughput
@@ -906,32 +898,22 @@ struct vmbus_channel {
};
-static inline void set_channel_lock_state(struct vmbus_channel *c, bool state)
-{
- c->acquire_ring_lock = state;
-}
-
static inline bool is_hvsock_channel(const struct vmbus_channel *c)
{
return !!(c->offermsg.offer.chn_flags &
VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER);
}
-static inline void set_channel_signal_state(struct vmbus_channel *c,
- enum hv_signal_policy policy)
-{
- c->signal_policy = policy;
-}
-
static inline void set_channel_affinity_state(struct vmbus_channel *c,
enum hv_numa_policy policy)
{
c->affinity_policy = policy;
}
-static inline void set_channel_read_state(struct vmbus_channel *c, bool state)
+static inline void set_channel_read_mode(struct vmbus_channel *c,
+ enum hv_callback_mode mode)
{
- c->batched_reading = state;
+ c->callback_mode = mode;
}
static inline void set_per_channel_state(struct vmbus_channel *c, void *s)
@@ -1037,7 +1019,7 @@ extern int vmbus_open(struct vmbus_channel *channel,
u32 recv_ringbuffersize,
void *userdata,
u32 userdatalen,
- void(*onchannel_callback)(void *context),
+ void (*onchannel_callback)(void *context),
void *context);
extern void vmbus_close(struct vmbus_channel *channel);
@@ -1054,8 +1036,7 @@ extern int vmbus_sendpacket_ctl(struct vmbus_channel *channel,
u32 bufferLen,
u64 requestid,
enum vmbus_packet_type type,
- u32 flags,
- bool kick_q);
+ u32 flags);
extern int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
struct hv_page_buffer pagebuffers[],
@@ -1070,8 +1051,7 @@ extern int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel,
void *buffer,
u32 bufferlen,
u64 requestid,
- u32 flags,
- bool kick_q);
+ u32 flags);
extern int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
struct hv_multipage_buffer *mpb,
@@ -1181,6 +1161,17 @@ static inline void *hv_get_drvdata(struct hv_device *dev)
return dev_get_drvdata(&dev->device);
}
+struct hv_ring_buffer_debug_info {
+ u32 current_interrupt_mask;
+ u32 current_read_index;
+ u32 current_write_index;
+ u32 bytes_avail_toread;
+ u32 bytes_avail_towrite;
+};
+
+void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info,
+ struct hv_ring_buffer_debug_info *debug_info);
+
/* Vmbus interface */
#define vmbus_driver_register(driver) \
__vmbus_driver_register(driver, THIS_MODULE, KBUILD_MODNAME)
@@ -1454,16 +1445,14 @@ struct hyperv_service_callback {
char *log_msg;
uuid_le data;
struct vmbus_channel *channel;
- void (*callback) (void *context);
+ void (*callback)(void *context);
};
#define MAX_SRV_VER 0x7ffffff
-extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *,
- struct icmsg_negotiate *, u8 *, int,
- int);
-
-void hv_event_tasklet_disable(struct vmbus_channel *channel);
-void hv_event_tasklet_enable(struct vmbus_channel *channel);
+extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, u8 *buf,
+ const int *fw_version, int fw_vercnt,
+ const int *srv_version, int srv_vercnt,
+ int *nego_fw_version, int *nego_srv_version);
void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid);
@@ -1480,9 +1469,9 @@ void vmbus_set_event(struct vmbus_channel *channel);
/* Get the start of the ring buffer. */
static inline void *
-hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info)
+hv_get_ring_buffer(const struct hv_ring_buffer_info *ring_info)
{
- return (void *)ring_info->ring_buffer->buffer;
+ return ring_info->ring_buffer->buffer;
}
/*
@@ -1532,91 +1521,83 @@ static inline void hv_signal_on_read(struct vmbus_channel *channel)
cached_write_sz = hv_get_cached_bytes_to_write(rbi);
if (cached_write_sz < pending_sz)
vmbus_setevent(channel);
-
- return;
}
-static inline void
-init_cached_read_index(struct vmbus_channel *channel)
+/*
+ * Mask off host interrupt callback notifications
+ */
+static inline void hv_begin_read(struct hv_ring_buffer_info *rbi)
{
- struct hv_ring_buffer_info *rbi = &channel->inbound;
+ rbi->ring_buffer->interrupt_mask = 1;
- rbi->cached_read_index = rbi->ring_buffer->read_index;
+ /* make sure mask update is not reordered */
+ virt_mb();
}
/*
- * An API to support in-place processing of incoming VMBUS packets.
+ * Re-enable host callback and return number of outstanding bytes
*/
-#define VMBUS_PKT_TRAILER 8
-
-static inline struct vmpacket_descriptor *
-get_next_pkt_raw(struct vmbus_channel *channel)
+static inline u32 hv_end_read(struct hv_ring_buffer_info *rbi)
{
- struct hv_ring_buffer_info *ring_info = &channel->inbound;
- u32 priv_read_loc = ring_info->priv_read_index;
- void *ring_buffer = hv_get_ring_buffer(ring_info);
- u32 dsize = ring_info->ring_datasize;
- /*
- * delta is the difference between what is available to read and
- * what was already consumed in place. We commit read index after
- * the whole batch is processed.
- */
- u32 delta = priv_read_loc >= ring_info->ring_buffer->read_index ?
- priv_read_loc - ring_info->ring_buffer->read_index :
- (dsize - ring_info->ring_buffer->read_index) + priv_read_loc;
- u32 bytes_avail_toread = (hv_get_bytes_to_read(ring_info) - delta);
- if (bytes_avail_toread < sizeof(struct vmpacket_descriptor))
- return NULL;
+ rbi->ring_buffer->interrupt_mask = 0;
+
+ /* make sure mask update is not reordered */
+ virt_mb();
- return ring_buffer + priv_read_loc;
+ /*
+ * Now check to see if the ring buffer is still empty.
+ * If it is not, we raced and we need to process new
+ * incoming messages.
+ */
+ return hv_get_bytes_to_read(rbi);
}
/*
- * A helper function to step through packets "in-place"
- * This API is to be called after each successful call
- * get_next_pkt_raw().
+ * An API to support in-place processing of incoming VMBUS packets.
*/
-static inline void put_pkt_raw(struct vmbus_channel *channel,
- struct vmpacket_descriptor *desc)
+
+/* Get data payload associated with descriptor */
+static inline void *hv_pkt_data(const struct vmpacket_descriptor *desc)
{
- struct hv_ring_buffer_info *ring_info = &channel->inbound;
- u32 packetlen = desc->len8 << 3;
- u32 dsize = ring_info->ring_datasize;
+ return (void *)((unsigned long)desc + (desc->offset8 << 3));
+}
- /*
- * Include the packet trailer.
- */
- ring_info->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
- ring_info->priv_read_index %= dsize;
+/* Get data size associated with descriptor */
+static inline u32 hv_pkt_datalen(const struct vmpacket_descriptor *desc)
+{
+ return (desc->len8 << 3) - (desc->offset8 << 3);
}
+
+struct vmpacket_descriptor *
+hv_pkt_iter_first(struct vmbus_channel *channel);
+
+struct vmpacket_descriptor *
+__hv_pkt_iter_next(struct vmbus_channel *channel,
+ const struct vmpacket_descriptor *pkt);
+
+void hv_pkt_iter_close(struct vmbus_channel *channel);
+
/*
- * This call commits the read index and potentially signals the host.
- * Here is the pattern for using the "in-place" consumption APIs:
- *
- * init_cached_read_index();
- *
- * while (get_next_pkt_raw() {
- * process the packet "in-place";
- * put_pkt_raw();
- * }
- * if (packets processed in place)
- * commit_rd_index();
+ * Get next packet descriptor from iterator
+ * If at end of list, return NULL and update host.
*/
-static inline void commit_rd_index(struct vmbus_channel *channel)
+static inline struct vmpacket_descriptor *
+hv_pkt_iter_next(struct vmbus_channel *channel,
+ const struct vmpacket_descriptor *pkt)
{
- struct hv_ring_buffer_info *ring_info = &channel->inbound;
- /*
- * Make sure all reads are done before we update the read index since
- * the writer may start writing to the read area once the read index
- * is updated.
- */
- virt_rmb();
- ring_info->ring_buffer->read_index = ring_info->priv_read_index;
+ struct vmpacket_descriptor *nxt;
+
+ nxt = __hv_pkt_iter_next(channel, pkt);
+ if (!nxt)
+ hv_pkt_iter_close(channel);
- hv_signal_on_read(channel);
+ return nxt;
}
+#define foreach_vmbus_pkt(pkt, channel) \
+ for (pkt = hv_pkt_iter_first(channel); pkt; \
+ pkt = hv_pkt_iter_next(channel, pkt))
#endif /* _HYPERV_H */