| #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 */ | |
| void *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 */ |