blob: 338310d0c01f31a4521b2bef9c79819883f32b2f [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_CONNECTIVITY_ETHERNET_DRIVERS_GVNIC_ABI_H_
#define SRC_CONNECTIVITY_ETHERNET_DRIVERS_GVNIC_ABI_H_
#include <netinet/if_ether.h>
#include <zircon/compiler.h>
#include <cstddef>
#include "src/connectivity/ethernet/drivers/gvnic/bigendian.h"
// Compute the size of a field of a struct without an instantition.
#define sizeof_field(s, f) sizeof(((s *)0)->f)
// Fixed Configuration Registers in Bar 0
struct __PACKED GvnicRegisters {
BigEndian<uint32_t> dev_status;
BigEndian<uint32_t> drv_status;
BigEndian<uint32_t> max_tx_queues;
BigEndian<uint32_t> max_rx_queues;
BigEndian<uint32_t> admin_queue_pfn;
BigEndian<uint32_t> admin_queue_doorbell;
BigEndian<uint32_t> admin_queue_counter;
uint8_t padding[2];
BigEndian<uint8_t> dma_mask;
BigEndian<uint8_t> driver_version;
BigEndian<uint64_t> admin_queue_base_address;
BigEndian<uint32_t> admin_queue_length;
};
static_assert(sizeof(GvnicRegisters) == 44);
// Since we will be reading and writing individual struct members, and relying on their offsets, it
// is vital that these struct members are the correct size and offset. Check that the offsets and
// size of each member matches the docs.
#define assert_offset_size(o, s, f) \
static_assert(offsetof(GvnicRegisters, f) == (o) && sizeof_field(GvnicRegisters, f) == (s))
assert_offset_size(0x00, 4, dev_status);
assert_offset_size(0x04, 4, drv_status);
assert_offset_size(0x08, 4, max_tx_queues);
assert_offset_size(0x0C, 4, max_rx_queues);
assert_offset_size(0x10, 4, admin_queue_pfn);
assert_offset_size(0x14, 4, admin_queue_doorbell);
assert_offset_size(0x18, 4, admin_queue_counter);
assert_offset_size(0x1C, 2, padding);
assert_offset_size(0x1E, 1, dma_mask);
assert_offset_size(0x1f, 1, driver_version);
assert_offset_size(0x20, 8, admin_queue_base_address);
assert_offset_size(0x28, 4, admin_queue_length);
#undef assert_offset_size
//
// Common definitions
//
#define PCI_VENDOR_ID_GOOGLE 0x1AE0u
#define PCI_DEV_ID_GVNIC 0x0042u
#define GVNIC_REGISTER_BAR (0)
#define GVNIC_MSIX_BAR (1)
#define GVNIC_DOORBELL_BAR (2)
// Device Status Register bits
#define GVNIC_DEVICE_STATUS_RESET (0x1u << (1))
#define GVNIC_DEVICE_STATUS_LINK_STATUS (0x1u << (2))
#define GVNIC_DEVICE_STATUS_REPORT_STATS (0x1u << (3))
#define GVNIC_DEVICE_STATUS_DEVICE_IS_RESET (0x1u << (4))
// Driver Status Register bits
#define GVNIC_DRIVER_STATUS_RUN (0x1u << (0))
#define GVNIC_DRIVER_STATUS_RESET (0x1u << (1))
// Interrupt Doorbell bits
#define GVNIC_IRQ_ACK (0x1u << (31))
#define GVNIC_IRQ_MASK (0x1u << (30))
#define GVNIC_IRQ_EVENT (0x1u << (29))
//
// Admin queue definitions
//
// The size (in octets) of the admin queue buffer.
#define GVNIC_ADMINQ_SIZE (4096)
// The length (number of elements) of the admin queue buffer.
#define GVNIC_ADMINQ_LEN (GVNIC_ADMINQ_SIZE / sizeof(GvnicAdminqEntry))
// Some of these enum values are missing intentionally.
enum GveAdminqOpcodes : uint32_t {
GVNIC_ADMINQ_DESCRIBE_DEVICE = 0x1,
GVNIC_ADMINQ_CONFIGURE_DEVICE_RESOURCES = 0x2,
GVNIC_ADMINQ_REGISTER_PAGE_LIST = 0x3,
GVNIC_ADMINQ_UNREGISTER_PAGE_LIST = 0x4,
GVNIC_ADMINQ_CREATE_TX_QUEUE = 0x5,
GVNIC_ADMINQ_CREATE_RX_QUEUE = 0x6,
GVNIC_ADMINQ_DESTROY_TX_QUEUE = 0x7,
GVNIC_ADMINQ_DESTROY_RX_QUEUE = 0x8,
GVNIC_ADMINQ_DECONFIGURE_DEVICE_RESOURCES = 0x9,
GVNIC_ADMINQ_SET_DRIVER_PARAMETER = 0xB,
GVNIC_ADMINQ_REPORT_STATS = 0xC,
GVNIC_ADMINQ_REPORT_LINK_SPEED = 0xD,
GVNIC_ADMINQ_GET_PTYPE_MAP = 0xE,
};
#define GVNIC_ADMINQ_DEVICE_DESCRIPTOR_VERSION 1
struct __PACKED GvnicAdminqDescribeDevice {
// Points to an allocated GvnicDeviceDescriptor. Filled by device
BigEndian<uint64_t> device_descriptor_addr;
BigEndian<uint32_t> device_descriptor_version;
BigEndian<uint32_t> available_length;
};
static_assert(sizeof(GvnicAdminqDescribeDevice) == 16);
struct __PACKED GvnicDeviceDescriptor {
// Maximum number of pages that may be registered by the guest across all queue page lists.
BigEndian<uint64_t> max_registered_pages;
uint8_t reserved1[2];
// Number of entries in each Tx queue, in units of descriptors. Must be a power of two.
BigEndian<uint16_t> tx_queue_size;
// Number of entries in each Rx queue (Rx descriptor/data ring pair). Must be a power of two.
BigEndian<uint16_t> rx_queue_size;
// The default number of queues.
BigEndian<uint16_t> default_num_queues;
// MTU supported by the device.
BigEndian<uint16_t> mtu;
// Number of 32 bit completion event counters that must be allocated by the guest.
BigEndian<uint16_t> event_counters;
// Number of pages per qpl for TX queues.
BigEndian<uint16_t> tx_pages_per_qpl;
// Number of pages per qpl for RX queues.
BigEndian<uint16_t> rx_pages_per_qpl;
// MAC address of the NIC.
uint8_t mac[ETH_ALEN];
// Number of additional device options trailing the device descriptor.
BigEndian<uint16_t> num_device_options;
// The total length of the device descriptor in bytes, including any trailing DeviceOption fields.
BigEndian<uint16_t> total_length;
uint8_t reserved2[6];
};
static_assert(sizeof(GvnicDeviceDescriptor) == 40);
struct __PACKED GvnicDeviceOption {
BigEndian<uint16_t> option_id;
BigEndian<uint16_t> option_length;
BigEndian<uint32_t> required_features_mask;
};
static_assert(sizeof(GvnicDeviceOption) == 8);
#define GVNIC_DEV_OPT_ID_RAW_ADDRESSING 0x1
#define GVNIC_DEV_OPT_LEN_RAW_ADDRESSING 0x0
#define GVNIC_DEV_OPT_FEAT_MASK_RAW_ADDRESSING 0x0
struct __PACKED GvnicAdminqConfigureDeviceResources {
BigEndian<uint64_t> counter_array;
BigEndian<uint64_t> irq_db_addr_base;
BigEndian<uint32_t> num_counters;
BigEndian<uint32_t> num_irq_dbs;
BigEndian<uint32_t> irq_db_stride;
BigEndian<uint32_t> ntfy_blk_msix_base_idx;
uint8_t queue_format;
};
static_assert(sizeof(GvnicAdminqConfigureDeviceResources) == 33);
enum GveQueueFormat : uint8_t {
GVNIC_UNSPECIFIED_FORMAT = 0x0,
GVNIC_GQI_RDA_FORMAT = 0x1, // RDA = Raw DMA Address
GVNIC_GQI_QPL_FORMAT = 0x2, // QPL = Queue Page List
GVNIC_DQO_RDA_FORMAT = 0x3, // DQO is for a future card
GVNIC_DQO_QPL_FORMAT = 0x4,
};
#define RDA_PAGE_LIST_ID 0xFFFFFFFF
struct __PACKED GvnicAdminqRegisterPageList {
BigEndian<uint32_t> page_list_id;
BigEndian<uint32_t> num_pages;
BigEndian<uint64_t> page_list_address;
BigEndian<uint64_t> page_size;
};
static_assert(sizeof(GvnicAdminqRegisterPageList) == 24);
struct __PACKED GvnicAdminqUnregisterPageList {
BigEndian<uint32_t> page_list_id;
};
static_assert(sizeof(GvnicAdminqUnregisterPageList) == 4);
struct __PACKED GvnicQueueResources {
// gVNIC BAR2 is a flat array of 32-bit big endian doorbells. db_index is the index in BAR2 of a
// queue's doorbell. db_index is network byte order.
BigEndian<uint32_t> db_index;
// counter_index is the index in a per-NIC guest-allocated counter array of a queue's event
// counter. counter_index is in network byte order.
BigEndian<uint32_t> counter_index;
// Padding bytes to push us out to a cacheline ensuing QueueResources structs are
// cacheline-independent of each other.
uint8_t reserved[56];
};
static_assert(sizeof(GvnicQueueResources) == 64);
struct __PACKED GvnicAdminqCreateTxQueue {
BigEndian<uint32_t> queue_id;
uint8_t reserved[4];
BigEndian<uint64_t> queue_resources_addr;
BigEndian<uint64_t> tx_ring_addr;
BigEndian<uint32_t> queue_page_list_id;
BigEndian<uint32_t> ntfy_id;
BigEndian<uint64_t> tx_comp_ring_addr;
BigEndian<uint16_t> tx_ring_size;
};
static_assert(sizeof(GvnicAdminqCreateTxQueue) == 42);
struct __PACKED GvnicAdminqCreateRxQueue {
BigEndian<uint32_t> queue_id;
BigEndian<uint32_t> slice;
uint8_t reserved[4];
BigEndian<uint32_t> ntfy_id;
BigEndian<uint64_t> queue_resources_addr;
BigEndian<uint64_t> rx_desc_ring_addr;
BigEndian<uint64_t> rx_data_ring_addr;
BigEndian<uint32_t> queue_page_list_id;
BigEndian<uint16_t> rx_ring_size;
BigEndian<uint16_t> packet_buffer_size;
};
static_assert(sizeof(GvnicAdminqCreateRxQueue) == 48);
struct __PACKED GvnicAdminqDestroyTransmitQueue {
BigEndian<uint32_t> queue_id;
};
static_assert(sizeof(GvnicAdminqDestroyTransmitQueue) == 4);
struct __PACKED GvnicAdminqDestroyReceiveQueue {
BigEndian<uint32_t> queue_id;
};
static_assert(sizeof(GvnicAdminqDestroyReceiveQueue) == 4);
struct __PACKED GvnicAdminqDeconfigureDeviceResources {};
// No size assert here, since structs always have a size of at least 1 byte
struct __PACKED GvnicAdminqSetDriverParameter {
BigEndian<uint32_t> parameter_type;
uint8_t padding[4];
BigEndian<uint64_t> parameter_value;
};
struct __PACKED GvnicAdminqReportStats {
BigEndian<uint64_t> stats_report_len;
BigEndian<uint64_t> stats_report_addr;
BigEndian<uint64_t> interval_ms;
};
struct __PACKED GvnicAdminqReportLinkSpeed {
BigEndian<uint64_t> link_speed_address;
};
struct __PACKED GvnicAdminqLinkSpeed {
BigEndian<uint64_t> link_speed;
};
struct __PACKED GvnicAdminqGetPtypeMap {
BigEndian<uint64_t> ptype_map_len;
BigEndian<uint64_t> ptype_map_addr;
};
struct __PACKED GvnicAdminqEntry {
BigEndian<uint32_t> opcode;
BigEndian<uint32_t> status;
union {
GvnicAdminqDescribeDevice describe_device;
GvnicAdminqConfigureDeviceResources device_resources;
GvnicAdminqRegisterPageList register_page_list;
GvnicAdminqUnregisterPageList unregister_page_list;
GvnicAdminqCreateTxQueue create_tx_queue;
GvnicAdminqCreateRxQueue create_rx_queue;
GvnicAdminqDestroyTransmitQueue destroy_transmit_queue;
GvnicAdminqDestroyReceiveQueue destroy_receive_queue;
GvnicAdminqDeconfigureDeviceResources deconfigure_device_resources;
GvnicAdminqSetDriverParameter set_driver_param;
GvnicAdminqReportStats report_stats;
GvnicAdminqReportLinkSpeed report_link_speed;
GvnicAdminqGetPtypeMap get_ptype_map;
char padding[56];
};
};
static_assert(sizeof(GvnicAdminqEntry) == 64);
enum GvnicAdminqStatus : uint32_t {
GVNIC_ADMINQ_STATUS_UNSET = 0,
GVNIC_ADMINQ_STATUS_PASSED = 1,
GVNIC_ADMINQ_STATUS_ABORTED = 0xFFFFFFF0,
GVNIC_ADMINQ_STATUS_ALREADY_EXISTS = 0xFFFFFFF1,
GVNIC_ADMINQ_STATUS_CANCELLED = 0xFFFFFFF2,
GVNIC_ADMINQ_STATUS_DATA_LOSS = 0xFFFFFFF3,
GVNIC_ADMINQ_STATUS_DEADLINE_EXCEEDED = 0xFFFFFFF4,
GVNIC_ADMINQ_STATUS_FAILED_PRECONDITION = 0xFFFFFFF5,
GVNIC_ADMINQ_STATUS_INTERNAL_ERROR = 0xFFFFFFF6,
GVNIC_ADMINQ_STATUS_INVALID_ARGUMENT = 0xFFFFFFF7,
GVNIC_ADMINQ_STATUS_NOT_FOUND = 0xFFFFFFF8,
GVNIC_ADMINQ_STATUS_OUT_OF_RANGE = 0xFFFFFFF9,
GVNIC_ADMINQ_STATUS_PERMISSION_DENIED = 0xFFFFFFFA,
GVNIC_ADMINQ_STATUS_UNAUTHENTICATED = 0xFFFFFFFB,
GVNIC_ADMINQ_STATUS_RESOURCES_EXHAUSTED = 0xFFFFFFFC,
GVNIC_ADMINQ_STATUS_UNAVAILBLE = 0xFFFFFFFD,
GVNIC_ADMINQ_STATUS_UNIMPLEMENTED = 0xFFFFFFFE,
GVNIC_ADMINQ_STATUS_UNKNOWN_ERROR = 0xFFFFFFFF,
};
//
// Transmit/receive descriptors
//
// Transmit Descriptor Types
#define GVNIC_TXD_STD (0x0u << 4) // Sandard
#define GVNIC_TXD_TSO (0x1u << 4) // TSO Packet
#define GVNIC_TXD_SEG (0x2u << 4) // Segment
#define GVNIC_TXD_META (0x3u << 4) // Metadata
#define GVNIC_TXF_L4CSUM (0x1u << (0)) // Need csum offload
#define GVNIC_TXF_TSTAMP (0x1u << (2)) // Timestamp required
struct __PACKED GvnicTxPktDesc {
uint8_t type_flags;
uint8_t checksum_offset; // In shorts (not bytes)
uint8_t l4_offset; // In shorts (not bytes)
uint8_t descriptor_count;
BigEndian<uint16_t> len; // In bytes
BigEndian<uint16_t> seg_len; // In bytes
BigEndian<uint64_t> seg_addr; // Must be even
};
static_assert(sizeof(GvnicTxPktDesc) == 16);
struct __PACKED GvnicTxSegDesc {
uint8_t type_flags;
uint8_t l3_offset; // In shorts (not bytes)
BigEndian<uint16_t> reserved;
BigEndian<uint16_t> mss;
BigEndian<uint16_t> seg_len; // In bytes
BigEndian<uint64_t> seg_addr; // Must be even
};
static_assert(sizeof(GvnicTxSegDesc) == 16);
union gvnic_tx_desc {
GvnicTxPktDesc pkt;
GvnicTxSegDesc seg;
};
#define GVNIC_RX_FLAG_FRAG (0x1u << (6))
#define GVNIC_RX_FLAG_IPV4 (0x1u << (7))
#define GVNIC_RX_FLAG_IPV6 (0x1u << (8))
#define GVNIC_RX_FLAG_TCP (0x1u << (9))
#define GVNIC_RX_FLAG_UDP (0x1u << (10))
#define GVNIC_RX_FLAG_ERR (0x1u << (11)) // Packet Error Detected
#define GVNIC_RX_FLAG_CONT (0x1u << (13))
#define GVNIC_RX_FLAG_SEQ 0x7u
// The rx data is padded with extra bytes at the start.
#define GVNIC_RX_PADDING 2
struct __PACKED GvnicRxDesc {
uint8_t padding[48];
BigEndian<uint32_t> rss_hash; // Can be ignored.
BigEndian<uint16_t> gro_mss; // Unused.
BigEndian<uint16_t> reserved; // Reserved.
uint8_t header_length; // Unused.
uint8_t packet_data_offset; // Unused.
BigEndian<uint16_t> checksum; // Can be ignored.
BigEndian<uint16_t> length; // Length of the packet in bytes. (Including 2 byte padding)
BigEndian<uint16_t> flags_seq; // Useful for GVNIC_RX_FLAG_ERR only.
};
static_assert(sizeof(GvnicRxDesc) == 64);
#endif // SRC_CONNECTIVITY_ETHERNET_DRIVERS_GVNIC_ABI_H_