aboutsummaryrefslogtreecommitdiff
path: root/tools/hv/vmbus_bufring.h
blob: 6e7caacfff57449d3ec37c7db33661e3b0e2008f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* SPDX-License-Identifier: BSD-3-Clause */

#ifndef _VMBUS_BUF_H_
#define _VMBUS_BUF_H_

#include <stdbool.h>
#include <stdint.h>

#define __packed   __attribute__((__packed__))
#define unlikely(x)	__builtin_expect(!!(x), 0)

#define ICMSGHDRFLAG_TRANSACTION	1
#define ICMSGHDRFLAG_REQUEST		2
#define ICMSGHDRFLAG_RESPONSE		4

#define IC_VERSION_NEGOTIATION_MAX_VER_COUNT 100
#define ICMSG_HDR (sizeof(struct vmbuspipe_hdr) + sizeof(struct icmsg_hdr))
#define ICMSG_NEGOTIATE_PKT_SIZE(icframe_vercnt, icmsg_vercnt) \
	(ICMSG_HDR + sizeof(struct icmsg_negotiate) + \
	 (((icframe_vercnt) + (icmsg_vercnt)) * sizeof(struct ic_version)))

/*
 * Channel packets
 */

/* Channel packet flags */
#define VMBUS_CHANPKT_TYPE_INBAND	0x0006
#define VMBUS_CHANPKT_TYPE_RXBUF	0x0007
#define VMBUS_CHANPKT_TYPE_GPA		0x0009
#define VMBUS_CHANPKT_TYPE_COMP		0x000b

#define VMBUS_CHANPKT_FLAG_NONE		0
#define VMBUS_CHANPKT_FLAG_RC		0x0001  /* report completion */

#define VMBUS_CHANPKT_SIZE_SHIFT	3
#define VMBUS_CHANPKT_SIZE_ALIGN	BIT(VMBUS_CHANPKT_SIZE_SHIFT)
#define VMBUS_CHANPKT_HLEN_MIN		\
	(sizeof(struct vmbus_chanpkt_hdr) >> VMBUS_CHANPKT_SIZE_SHIFT)

/*
 * Buffer ring
 */
struct vmbus_bufring {
	volatile uint32_t windex;
	volatile uint32_t rindex;

	/*
	 * Interrupt mask {0,1}
	 *
	 * For TX bufring, host set this to 1, when it is processing
	 * the TX bufring, so that we can safely skip the TX event
	 * notification to host.
	 *
	 * For RX bufring, once this is set to 1 by us, host will not
	 * further dispatch interrupts to us, even if there are data
	 * pending on the RX bufring.  This effectively disables the
	 * interrupt of the channel to which this RX bufring is attached.
	 */
	volatile uint32_t imask;

	/*
	 * 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".
	 *
	 * Add necessary state for this enhancement.
	 */
	volatile uint32_t pending_send;
	uint32_t reserved1[12];

	union {
		struct {
			uint32_t feat_pending_send_sz:1;
		};
		uint32_t value;
	} feature_bits;

	/* Pad it to rte_mem_page_size() so that data starts on page boundary */
	uint8_t	reserved2[4028];

	/*
	 * Ring data starts here + RingDataStartOffset
	 * !!! DO NOT place any fields below this !!!
	 */
	uint8_t data[];
} __packed;

struct vmbus_br {
	struct vmbus_bufring *vbr;
	uint32_t	dsize;
	uint32_t	windex; /* next available location */
};

struct vmbus_chanpkt_hdr {
	uint16_t	type;	/* VMBUS_CHANPKT_TYPE_ */
	uint16_t	hlen;	/* header len, in 8 bytes */
	uint16_t	tlen;	/* total len, in 8 bytes */
	uint16_t	flags;	/* VMBUS_CHANPKT_FLAG_ */
	uint64_t	xactid;
} __packed;

struct vmbus_chanpkt {
	struct vmbus_chanpkt_hdr hdr;
} __packed;

struct vmbuspipe_hdr {
	unsigned int flags;
	unsigned int msgsize;
} __packed;

struct ic_version {
	unsigned short major;
	unsigned short minor;
} __packed;

struct icmsg_negotiate {
	unsigned short icframe_vercnt;
	unsigned short icmsg_vercnt;
	unsigned int reserved;
	struct ic_version icversion_data[]; /* any size array */
} __packed;

struct icmsg_hdr {
	struct ic_version icverframe;
	unsigned short icmsgtype;
	struct ic_version icvermsg;
	unsigned short icmsgsize;
	unsigned int status;
	unsigned char ictransaction_id;
	unsigned char icflags;
	unsigned char reserved[2];
} __packed;

int rte_vmbus_chan_recv_raw(struct vmbus_br *rxbr, void *data, uint32_t *len);
int rte_vmbus_chan_send(struct vmbus_br *txbr, uint16_t type, void *data,
			uint32_t dlen, uint32_t flags);
void vmbus_br_setup(struct vmbus_br *br, void *buf, unsigned int blen);
void *vmbus_uio_map(int *fd, int size);

/* Amount of space available for write */
static inline uint32_t vmbus_br_availwrite(const struct vmbus_br *br, uint32_t windex)
{
	uint32_t rindex = br->vbr->rindex;

	if (windex >= rindex)
		return br->dsize - (windex - rindex);
	else
		return rindex - windex;
}

static inline uint32_t vmbus_br_availread(const struct vmbus_br *br)
{
	return br->dsize - vmbus_br_availwrite(br, br->vbr->windex);
}

#endif	/* !_VMBUS_BUF_H_ */