blob: 93192357fe16f3dbb4f9bdc562144ca25fd50d18 [file] [log] [blame]
#ifndef _NETVSC_H
#define _NETVSC_H
/** @file
*
* Hyper-V network virtual service client
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Maximum supported NetVSC message length */
#define NETVSC_MTU 512
/** Maximum time to wait for a transaction to complete
*
* This is a policy decision.
*/
#define NETVSC_MAX_WAIT_MS 1000
/** Number of transmit ring entries
*
* Must be a power of two. This is a policy decision. This value
* must be sufficiently small to guarantee that we never run out of
* space in the VMBus outbound ring buffer.
*/
#define NETVSC_TX_NUM_DESC 32
/** RX data buffer page set ID
*
* This is a policy decision.
*/
#define NETVSC_RX_BUF_PAGESET 0xbead
/** RX data buffer length
*
* This is a policy decision.
*/
#define NETVSC_RX_BUF_LEN ( 16 * PAGE_SIZE )
/** Base transaction ID
*
* This is a policy decision.
*/
#define NETVSC_BASE_XID 0x18ae0000UL
/** Relative transaction IDs */
enum netvsc_xrid {
/** Transmit descriptors (one per transmit buffer ID) */
NETVSC_TX_BASE_XRID = 0,
/** Initialisation */
NETVSC_INIT_XRID = ( NETVSC_TX_BASE_XRID + NETVSC_TX_NUM_DESC ),
/** NDIS version */
NETVSC_NDIS_VERSION_XRID,
/** Establish receive buffer */
NETVSC_RX_ESTABLISH_XRID,
/** Revoke receive buffer */
NETVSC_RX_REVOKE_XRID,
};
/** NetVSC status codes */
enum netvsc_status {
NETVSC_NONE = 0,
NETVSC_OK = 1,
NETVSC_FAIL = 2,
NETVSC_TOO_NEW = 3,
NETVSC_TOO_OLD = 4,
NETVSC_BAD_PACKET = 5,
NETVSC_BUSY = 6,
NETVSC_UNSUPPORTED = 7,
};
/** NetVSC message header */
struct netvsc_header {
/** Type */
uint32_t type;
} __attribute__ (( packed ));
/** NetVSC initialisation message */
#define NETVSC_INIT_MSG 1
/** NetVSC initialisation message */
struct netvsc_init_message {
/** Message header */
struct netvsc_header header;
/** Minimum supported protocol version */
uint32_t min;
/** Maximum supported protocol version */
uint32_t max;
/** Reserved */
uint8_t reserved[20];
} __attribute__ (( packed ));
/** Oldest known NetVSC protocol version */
#define NETVSC_VERSION_1 2 /* sic */
/** NetVSC initialisation completion */
#define NETVSC_INIT_CMPLT 2
/** NetVSC initialisation completion */
struct netvsc_init_completion {
/** Message header */
struct netvsc_header header;
/** Protocol version */
uint32_t version;
/** Maximum memory descriptor list length */
uint32_t max_mdl_len;
/** Status */
uint32_t status;
/** Reserved */
uint8_t reserved[16];
} __attribute__ (( packed ));
/** NetVSC NDIS version message */
#define NETVSC_NDIS_VERSION_MSG 100
/** NetVSC NDIS version message */
struct netvsc_ndis_version_message {
/** Message header */
struct netvsc_header header;
/** Major version */
uint32_t major;
/** Minor version */
uint32_t minor;
/** Reserved */
uint8_t reserved[20];
} __attribute__ (( packed ));
/** NetVSC NDIS major version */
#define NETVSC_NDIS_MAJOR 6
/** NetVSC NDIS minor version */
#define NETVSC_NDIS_MINOR 1
/** NetVSC establish receive data buffer message */
#define NETVSC_RX_ESTABLISH_MSG 101
/** NetVSC establish receive data buffer completion */
#define NETVSC_RX_ESTABLISH_CMPLT 102
/** NetVSC revoke receive data buffer message */
#define NETVSC_RX_REVOKE_MSG 103
/** NetVSC establish transmit data buffer message */
#define NETVSC_TX_ESTABLISH_MSG 104
/** NetVSC establish transmit data buffer completion */
#define NETVSC_TX_ESTABLISH_CMPLT 105
/** NetVSC revoke transmit data buffer message */
#define NETVSC_TX_REVOKE_MSG 106
/** NetVSC establish data buffer message */
struct netvsc_establish_buffer_message {
/** Message header */
struct netvsc_header header;
/** GPADL ID */
uint32_t gpadl;
/** Page set ID */
uint16_t pageset;
/** Reserved */
uint8_t reserved[22];
} __attribute__ (( packed ));
/** NetVSC receive data buffer section */
struct netvsc_rx_buffer_section {
/** Starting offset */
uint32_t start;
/** Subsection length */
uint32_t len;
/** Number of subsections */
uint32_t count;
/** Ending offset */
uint32_t end;
} __attribute__ (( packed ));
/** NetVSC establish receive data buffer completion */
struct netvsc_rx_establish_buffer_completion {
/** Message header */
struct netvsc_header header;
/** Status */
uint32_t status;
/** Number of sections (must be 1) */
uint32_t count;
/** Section descriptors */
struct netvsc_rx_buffer_section section[1];
} __attribute__ (( packed ));
/** NetVSC establish transmit data buffer completion */
struct netvsc_tx_establish_buffer_completion {
/** Message header */
struct netvsc_header header;
/** Status */
uint32_t status;
/** Section length */
uint32_t len;
} __attribute__ (( packed ));
/** NetVSC revoke data buffer message */
struct netvsc_revoke_buffer_message {
/** Message header */
struct netvsc_header header;
/** Page set ID */
uint16_t pageset;
/** Reserved */
uint8_t reserved[26];
} __attribute__ (( packed ));
/** NetVSC RNDIS message */
#define NETVSC_RNDIS_MSG 107
/** NetVSC RNDIS message */
struct netvsc_rndis_message {
/** Message header */
struct netvsc_header header;
/** RNDIS channel */
uint32_t channel;
/** Buffer index (or NETVSC_RNDIS_NO_BUFFER) */
uint32_t buffer;
/** Buffer length */
uint32_t len;
/** Reserved */
uint8_t reserved[16];
} __attribute__ (( packed ));
/** RNDIS data channel (for RNDIS_PACKET_MSG only) */
#define NETVSC_RNDIS_DATA 0
/** RNDIS control channel (for all other RNDIS messages) */
#define NETVSC_RNDIS_CONTROL 1
/** "No buffer used" index */
#define NETVSC_RNDIS_NO_BUFFER 0xffffffffUL
/** A NetVSC descriptor ring */
struct netvsc_ring {
/** Number of descriptors */
unsigned int count;
/** I/O buffers, indexed by buffer ID */
struct io_buffer **iobufs;
/** Buffer ID ring */
uint8_t *ids;
/** Buffer ID producer counter */
unsigned int id_prod;
/** Buffer ID consumer counter */
unsigned int id_cons;
};
/**
* Initialise descriptor ring
*
* @v ring Descriptor ring
* @v count Maximum number of used descriptors
* @v iobufs I/O buffers
* @v ids Buffer IDs
*/
static inline __attribute__ (( always_inline )) void
netvsc_init_ring ( struct netvsc_ring *ring, unsigned int count,
struct io_buffer **iobufs, uint8_t *ids ) {
ring->count = count;
ring->iobufs = iobufs;
ring->ids = ids;
}
/**
* Check whether or not descriptor ring is full
*
* @v ring Descriptor ring
* @v is_full Ring is full
*/
static inline __attribute__ (( always_inline )) int
netvsc_ring_is_full ( struct netvsc_ring *ring ) {
unsigned int fill_level;
fill_level = ( ring->id_prod - ring->id_cons );
assert ( fill_level <= ring->count );
return ( fill_level >= ring->count );
}
/**
* Check whether or not descriptor ring is empty
*
* @v ring Descriptor ring
* @v is_empty Ring is empty
*/
static inline __attribute__ (( always_inline )) int
netvsc_ring_is_empty ( struct netvsc_ring *ring ) {
return ( ring->id_prod == ring->id_cons );
}
/** A NetVSC data buffer */
struct netvsc_buffer {
/** Transfer page set */
struct vmbus_xfer_pages pages;
/** Establish data buffer message type */
uint8_t establish_type;
/** Establish data buffer relative transaction ID */
uint8_t establish_xrid;
/** Revoke data buffer message type */
uint8_t revoke_type;
/** Revoke data buffer relative transaction ID */
uint8_t revoke_xrid;
/** Buffer length */
size_t len;
/** Buffer */
userptr_t data;
/** GPADL ID */
unsigned int gpadl;
};
/**
* Initialise data buffer
*
* @v buffer Data buffer
* @v pageset Page set ID
* @v op Page set operations
* @v establish_type Establish data buffer message type
* @v establish_xrid Establish data buffer relative transaction ID
* @v revoke_type Revoke data buffer message type
* @v revoke_type Revoke data buffer relative transaction ID
* @v len Required length
*/
static inline __attribute__ (( always_inline )) void
netvsc_init_buffer ( struct netvsc_buffer *buffer, uint16_t pageset,
struct vmbus_xfer_pages_operations *op,
uint8_t establish_type, uint8_t establish_xrid,
uint8_t revoke_type, uint8_t revoke_xrid, size_t len ) {
buffer->pages.pageset = cpu_to_le16 ( pageset );
buffer->pages.op = op;
buffer->establish_type = establish_type;
buffer->establish_xrid = establish_xrid;
buffer->revoke_type = revoke_type;
buffer->revoke_xrid = revoke_xrid;
buffer->len = len;
}
/** A NetVSC device */
struct netvsc_device {
/** VMBus device */
struct vmbus_device *vmdev;
/** RNDIS device */
struct rndis_device *rndis;
/** Name */
const char *name;
/** Transmit ring */
struct netvsc_ring tx;
/** Transmit buffer IDs */
uint8_t tx_ids[NETVSC_TX_NUM_DESC];
/** Transmit I/O buffers */
struct io_buffer *tx_iobufs[NETVSC_TX_NUM_DESC];
/** Receive buffer */
struct netvsc_buffer rx;
/** Relative transaction ID for current blocking transaction */
unsigned int wait_xrid;
/** Return status code for current blocking transaction */
int wait_rc;
};
/**
* Check if NetVSC device is obsolete
*
* @v netvsc NetVSC device
* @v is_obsolete NetVSC device is obsolete
*
* Check if NetVSC device is obsolete (i.e. was opened before the most
* recent Hyper-V reset).
*/
static inline __attribute__ (( always_inline )) int
netvsc_is_obsolete ( struct netvsc_device *netvsc ) {
return vmbus_gpadl_is_obsolete ( netvsc->rx.gpadl );
}
#endif /* _NETVSC_H */