aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/hyperv.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/hyperv.h')
-rw-r--r--include/linux/hyperv.h71
1 files changed, 61 insertions, 10 deletions
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 192ed8fbc403..efda23cf32c7 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -35,6 +35,7 @@
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/interrupt.h>
+#include <linux/reciprocal_div.h>
#define MAX_PAGE_BUFFER_COUNT 32
#define MAX_MULTIPAGE_BUFFER_COUNT 32 /* 128K */
@@ -88,18 +89,33 @@ struct hv_ring_buffer {
u32 interrupt_mask;
/*
- * Win8 uses some of the reserved bits to implement
- * interrupt driven flow management. On the send side
- * we can request that the receiver interrupt the sender
- * when the ring transitions from being full to being able
- * to handle a message of size "pending_send_sz".
+ * WS2012/Win8 and later versions of Hyper-V implement interrupt
+ * driven flow management. The feature bit feat_pending_send_sz
+ * is set by the host on the host->guest ring buffer, and by the
+ * guest on the guest->host ring buffer.
*
- * Add necessary state for this enhancement.
+ * The meaning of the feature bit is a bit complex in that it has
+ * semantics that apply to both ring buffers. If the guest sets
+ * the feature bit in the guest->host ring buffer, the guest is
+ * telling the host that:
+ * 1) It will set the pending_send_sz field in the guest->host ring
+ * buffer when it is waiting for space to become available, and
+ * 2) It will read the pending_send_sz field in the host->guest
+ * ring buffer and interrupt the host when it frees enough space
+ *
+ * Similarly, if the host sets the feature bit in the host->guest
+ * ring buffer, the host is telling the guest that:
+ * 1) It will set the pending_send_sz field in the host->guest ring
+ * buffer when it is waiting for space to become available, and
+ * 2) It will read the pending_send_sz field in the guest->host
+ * ring buffer and interrupt the guest when it frees enough space
+ *
+ * If either the guest or host does not set the feature bit that it
+ * owns, that guest or host must do polling if it encounters a full
+ * ring buffer, and not signal the other end with an interrupt.
*/
u32 pending_send_sz;
-
u32 reserved1[12];
-
union {
struct {
u32 feat_pending_send_sz:1;
@@ -120,6 +136,7 @@ struct hv_ring_buffer {
struct hv_ring_buffer_info {
struct hv_ring_buffer *ring_buffer;
u32 ring_size; /* Include the shared header */
+ struct reciprocal_value ring_size_div10_reciprocal;
spinlock_t ring_lock;
u32 ring_datasize; /* < ring_size */
@@ -154,6 +171,16 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi)
return write;
}
+static inline u32 hv_get_avail_to_write_percent(
+ const struct hv_ring_buffer_info *rbi)
+{
+ u32 avail_write = hv_get_bytes_to_write(rbi);
+
+ return reciprocal_divide(
+ (avail_write << 3) + (avail_write << 1),
+ rbi->ring_size_div10_reciprocal);
+}
+
/*
* VMBUS version is 32 bit entity broken up into
* two 16 bit quantities: major_number. minor_number.
@@ -163,6 +190,7 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi)
* 2 . 4 (Windows 8)
* 3 . 0 (Windows 8 R2)
* 4 . 0 (Windows 10)
+ * 5 . 0 (Newer Windows 10)
*/
#define VERSION_WS2008 ((0 << 16) | (13))
@@ -170,10 +198,11 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi)
#define VERSION_WIN8 ((2 << 16) | (4))
#define VERSION_WIN8_1 ((3 << 16) | (0))
#define VERSION_WIN10 ((4 << 16) | (0))
+#define VERSION_WIN10_V5 ((5 << 16) | (0))
#define VERSION_INVAL -1
-#define VERSION_CURRENT VERSION_WIN10
+#define VERSION_CURRENT VERSION_WIN10_V5
/* Make maximum size of pipe payload of 16K */
#define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384)
@@ -570,7 +599,14 @@ struct vmbus_channel_initiate_contact {
struct vmbus_channel_message_header header;
u32 vmbus_version_requested;
u32 target_vcpu; /* The VCPU the host should respond to */
- u64 interrupt_page;
+ union {
+ u64 interrupt_page;
+ struct {
+ u8 msg_sint;
+ u8 padding1[3];
+ u32 padding2;
+ };
+ };
u64 monitor_page1;
u64 monitor_page2;
} __packed;
@@ -585,6 +621,19 @@ struct vmbus_channel_tl_connect_request {
struct vmbus_channel_version_response {
struct vmbus_channel_message_header header;
u8 version_supported;
+
+ u8 connection_state;
+ u16 padding;
+
+ /*
+ * On new hosts that support VMBus protocol 5.0, we must use
+ * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
+ * and for subsequent messages, we must use the Message Connection ID
+ * field in the host-returned Version Response Message.
+ *
+ * On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1).
+ */
+ u32 msg_conn_id;
} __packed;
enum vmbus_channel_state {
@@ -1012,6 +1061,8 @@ extern int vmbus_establish_gpadl(struct vmbus_channel *channel,
extern int vmbus_teardown_gpadl(struct vmbus_channel *channel,
u32 gpadl_handle);
+void vmbus_reset_channel_cb(struct vmbus_channel *channel);
+
extern int vmbus_recvpacket(struct vmbus_channel *channel,
void *buffer,
u32 bufferlen,