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