/* SPDX-License-Identifier: BSD-3-Clause */ #ifndef _VMBUS_BUF_H_ #define _VMBUS_BUF_H_ #include #include #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_ */