mirror of
https://github.com/torvalds/linux.git
synced 2024-12-04 18:13:04 +00:00
45bab4d746
Common userspace interface for read/write from VMBus ringbuffer. This implementation is open for use by any userspace driver or application seeking direct control over VMBus ring buffers. A significant part of this code is borrowed from DPDK. Link: https://github.com/DPDK/dpdk/ Currently this library is not supported for ARM64. Signed-off-by: Mary Hardy <maryhardy@microsoft.com> Signed-off-by: Saurabh Sengar <ssengar@linux.microsoft.com> Reviewed-by: Long Li <longli@microsoft.com> Link: https://lore.kernel.org/r/1711788723-8593-5-git-send-email-ssengar@linux.microsoft.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
159 lines
4.1 KiB
C
159 lines
4.1 KiB
C
/* 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_ */
|