blob: 0f280c700baf13a6cc3ff07d664680959bffaed1 [file] [log] [blame]
#ifndef _ENA_H
#define _ENA_H
/** @file
*
* Amazon ENA network driver
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/if_ether.h>
/** BAR size */
#define ENA_BAR_SIZE 16384
/** Queue alignment */
#define ENA_ALIGN 4096
/** Number of admin queue entries */
#define ENA_AQ_COUNT 2
/** Number of admin completion queue entries */
#define ENA_ACQ_COUNT 2
/** Number of async event notification queue entries */
#define ENA_AENQ_COUNT 2
/** Number of transmit queue entries */
#define ENA_TX_COUNT 16
/** Number of receive queue entries */
#define ENA_RX_COUNT 128
/** Receive queue maximum fill level */
#define ENA_RX_FILL 16
/** Base address low register offset */
#define ENA_BASE_LO 0x0
/** Base address high register offset */
#define ENA_BASE_HI 0x4
/** Capability register value */
#define ENA_CAPS( count, size ) ( ( (size) << 16 ) | ( (count) << 0 ) )
/** Admin queue base address register */
#define ENA_AQ_BASE 0x10
/** Admin queue capabilities register */
#define ENA_AQ_CAPS 0x18
/** Admin completion queue base address register */
#define ENA_ACQ_BASE 0x20
/** Admin completion queue capabilities register */
#define ENA_ACQ_CAPS 0x28
/** Admin queue doorbell register */
#define ENA_AQ_DB 0x2c
/** Maximum time to wait for admin requests */
#define ENA_ADMIN_MAX_WAIT_MS 5000
/** Async event notification queue capabilities register */
#define ENA_AENQ_CAPS 0x34
/** Async event notification queue base address register */
#define ENA_AENQ_BASE 0x38
/** Device control register */
#define ENA_CTRL 0x54
#define ENA_CTRL_RESET 0x00000001UL /**< Reset */
/** Maximum time to wait for reset */
#define ENA_RESET_MAX_WAIT_MS 1000
/** Device status register */
#define ENA_STAT 0x58
#define ENA_STAT_RESET 0x00000008UL /**< Reset in progress */
/** Admin queue entry header */
struct ena_aq_header {
/** Request identifier */
uint8_t id;
/** Reserved */
uint8_t reserved;
/** Opcode */
uint8_t opcode;
/** Flags */
uint8_t flags;
} __attribute__ (( packed ));
/** Admin queue ownership phase flag */
#define ENA_AQ_PHASE 0x01
/** Admin completion queue entry header */
struct ena_acq_header {
/** Request identifier */
uint8_t id;
/** Reserved */
uint8_t reserved;
/** Status */
uint8_t status;
/** Flags */
uint8_t flags;
/** Extended status */
uint16_t ext;
/** Consumer index */
uint16_t cons;
} __attribute__ (( packed ));
/** Admin completion queue ownership phase flag */
#define ENA_ACQ_PHASE 0x01
/** Device attributes */
#define ENA_DEVICE_ATTRIBUTES 1
/** Device attributes */
struct ena_device_attributes {
/** Implementation */
uint32_t implementation;
/** Device version */
uint32_t version;
/** Supported features */
uint32_t features;
/** Reserved */
uint8_t reserved_a[4];
/** Physical address width */
uint32_t physical;
/** Virtual address width */
uint32_t virtual;
/** MAC address */
uint8_t mac[ETH_ALEN];
/** Reserved */
uint8_t reserved_b[2];
/** Maximum MTU */
uint32_t mtu;
} __attribute__ (( packed ));
/** Async event notification queue config */
#define ENA_AENQ_CONFIG 26
/** Async event notification queue config */
struct ena_aenq_config {
/** Bitmask of supported AENQ groups (device -> host) */
uint32_t supported;
/** Bitmask of enabled AENQ groups (host -> device) */
uint32_t enabled;
} __attribute__ (( packed ));
/** Host attributes */
#define ENA_HOST_ATTRIBUTES 28
/** Host attributes */
struct ena_host_attributes {
/** Host info base address */
uint64_t info;
/** Debug area base address */
uint64_t debug;
/** Debug area size */
uint32_t debug_len;
} __attribute__ (( packed ));
/** Host information */
struct ena_host_info {
/** Operating system type */
uint32_t type;
/** Operating system distribution (string) */
char dist_str[128];
/** Operating system distribution (numeric) */
uint32_t dist;
/** Kernel version (string) */
char kernel_str[32];
/** Kernel version (numeric) */
uint32_t kernel;
/** Driver version */
uint32_t version;
/** Linux network device features */
uint64_t linux_features;
/** ENA specification version */
uint16_t spec;
/** PCI bus:dev.fn address */
uint16_t busdevfn;
/** Number of CPUs */
uint16_t cpus;
/** Reserved */
uint8_t reserved_a[2];
/** Supported features */
uint32_t features;
} __attribute__ (( packed ));
/** Linux operating system type
*
* There is a defined "iPXE" operating system type (with value 5).
* However, some very broken versions of the ENA firmware will refuse
* to allow a completion queue to be created if the "iPXE" type is
* used.
*/
#define ENA_HOST_INFO_TYPE_LINUX 1
/** Driver version
*
* The driver version field is nominally used to report a version
* number outside of the VM for consumption by humans (and potentially
* by automated monitoring tools that could e.g. check for outdated
* versions with known security flaws).
*
* However, at some point in the development of the ENA firmware, some
* unknown person at AWS thought it would be sensible to apply a
* machine interpretation to this field and adjust the behaviour of
* the firmware based on its value, thereby creating a maintenance and
* debugging nightmare for all existing and future drivers.
*
* Hint to engineers: if you ever find yourself writing code of the
* form "if (version == SOME_MAGIC_NUMBER)" then something has gone
* very, very wrong. This *always* indicates that something is
* broken, either in your own code or in the code with which you are
* forced to interact.
*/
#define ENA_HOST_INFO_VERSION_WTF 0x00000002UL
/** ENA specification version */
#define ENA_HOST_INFO_SPEC_2_0 0x0200
/** Feature */
union ena_feature {
/** Device attributes */
struct ena_device_attributes device;
/** Async event notification queue config */
struct ena_aenq_config aenq;
/** Host attributes */
struct ena_host_attributes host;
};
/** Submission queue direction */
enum ena_sq_direction {
/** Transmit */
ENA_SQ_TX = 0x20,
/** Receive */
ENA_SQ_RX = 0x40,
};
/** Create submission queue */
#define ENA_CREATE_SQ 1
/** Create submission queue request */
struct ena_create_sq_req {
/** Header */
struct ena_aq_header header;
/** Direction */
uint8_t direction;
/** Reserved */
uint8_t reserved_a;
/** Policy */
uint16_t policy;
/** Completion queue identifier */
uint16_t cq_id;
/** Number of entries */
uint16_t count;
/** Base address */
uint64_t address;
/** Writeback address */
uint64_t writeback;
/** Reserved */
uint8_t reserved_b[8];
} __attribute__ (( packed ));
/** Submission queue policy */
enum ena_sq_policy {
/** Use host memory */
ENA_SQ_HOST_MEMORY = 0x0001,
/** Memory is contiguous */
ENA_SQ_CONTIGUOUS = 0x0100,
};
/** Create submission queue response */
struct ena_create_sq_rsp {
/** Header */
struct ena_acq_header header;
/** Submission queue identifier */
uint16_t id;
/** Reserved */
uint8_t reserved[2];
/** Doorbell register offset */
uint32_t doorbell;
/** LLQ descriptor ring offset */
uint32_t llq_desc;
/** LLQ header offset */
uint32_t llq_data;
} __attribute__ (( packed ));
/** Destroy submission queue */
#define ENA_DESTROY_SQ 2
/** Destroy submission queue request */
struct ena_destroy_sq_req {
/** Header */
struct ena_aq_header header;
/** Submission queue identifier */
uint16_t id;
/** Direction */
uint8_t direction;
/** Reserved */
uint8_t reserved;
} __attribute__ (( packed ));
/** Destroy submission queue response */
struct ena_destroy_sq_rsp {
/** Header */
struct ena_acq_header header;
} __attribute__ (( packed ));
/** Create completion queue */
#define ENA_CREATE_CQ 3
/** Create completion queue request */
struct ena_create_cq_req {
/** Header */
struct ena_aq_header header;
/** Interrupts enabled */
uint8_t intr;
/** Entry size (in 32-bit words) */
uint8_t size;
/** Number of entries */
uint16_t count;
/** MSI-X vector */
uint32_t vector;
/** Base address */
uint64_t address;
} __attribute__ (( packed ));
/** Empty MSI-X vector
*
* Some versions of the ENA firmware will complain if the completion
* queue's MSI-X vector field is left empty, even though the queue
* configuration specifies that interrupts are not used.
*/
#define ENA_MSIX_NONE 0xffffffffUL
/** Create completion queue response */
struct ena_create_cq_rsp {
/** Header */
struct ena_acq_header header;
/** Completion queue identifier */
uint16_t id;
/** Actual number of entries */
uint16_t count;
/** NUMA node register offset */
uint32_t node;
/** Doorbell register offset */
uint32_t doorbell;
/** Interrupt unmask register offset */
uint32_t intr;
} __attribute__ (( packed ));
/** Destroy completion queue */
#define ENA_DESTROY_CQ 4
/** Destroy completion queue request */
struct ena_destroy_cq_req {
/** Header */
struct ena_aq_header header;
/** Completion queue identifier */
uint16_t id;
/** Reserved */
uint8_t reserved[2];
} __attribute__ (( packed ));
/** Destroy completion queue response */
struct ena_destroy_cq_rsp {
/** Header */
struct ena_acq_header header;
} __attribute__ (( packed ));
/** Get feature */
#define ENA_GET_FEATURE 8
/** Get feature request */
struct ena_get_feature_req {
/** Header */
struct ena_aq_header header;
/** Length */
uint32_t len;
/** Address */
uint64_t address;
/** Flags */
uint8_t flags;
/** Feature identifier */
uint8_t id;
/** Reserved */
uint8_t reserved[2];
} __attribute__ (( packed ));
/** Get feature response */
struct ena_get_feature_rsp {
/** Header */
struct ena_acq_header header;
/** Feature */
union ena_feature feature;
} __attribute__ (( packed ));
/** Set feature */
#define ENA_SET_FEATURE 9
/** Set feature request */
struct ena_set_feature_req {
/** Header */
struct ena_aq_header header;
/** Length */
uint32_t len;
/** Address */
uint64_t address;
/** Flags */
uint8_t flags;
/** Feature identifier */
uint8_t id;
/** Reserved */
uint8_t reserved[2];
/** Feature */
union ena_feature feature;
} __attribute__ (( packed ));
/** Get statistics */
#define ENA_GET_STATS 11
/** Get statistics request */
struct ena_get_stats_req {
/** Header */
struct ena_aq_header header;
/** Reserved */
uint8_t reserved_a[12];
/** Type */
uint8_t type;
/** Scope */
uint8_t scope;
/** Reserved */
uint8_t reserved_b[2];
/** Queue ID */
uint16_t queue;
/** Device ID */
uint16_t device;
} __attribute__ (( packed ));
/** Basic statistics */
#define ENA_STATS_TYPE_BASIC 0
/** Ethernet statistics */
#define ENA_STATS_SCOPE_ETH 1
/** My device */
#define ENA_DEVICE_MINE 0xffff
/** Get statistics response */
struct ena_get_stats_rsp {
/** Header */
struct ena_acq_header header;
/** Transmit byte count */
uint64_t tx_bytes;
/** Transmit packet count */
uint64_t tx_packets;
/** Receive byte count */
uint64_t rx_bytes;
/** Receive packet count */
uint64_t rx_packets;
/** Receive drop count */
uint64_t rx_drops;
} __attribute__ (( packed ));
/** Admin queue request */
union ena_aq_req {
/** Header */
struct ena_aq_header header;
/** Create submission queue */
struct ena_create_sq_req create_sq;
/** Destroy submission queue */
struct ena_destroy_sq_req destroy_sq;
/** Create completion queue */
struct ena_create_cq_req create_cq;
/** Destroy completion queue */
struct ena_destroy_cq_req destroy_cq;
/** Get feature */
struct ena_get_feature_req get_feature;
/** Set feature */
struct ena_set_feature_req set_feature;
/** Get statistics */
struct ena_get_stats_req get_stats;
/** Padding */
uint8_t pad[64];
};
/** Admin completion queue response */
union ena_acq_rsp {
/** Header */
struct ena_acq_header header;
/** Create submission queue */
struct ena_create_sq_rsp create_sq;
/** Destroy submission queue */
struct ena_destroy_sq_rsp destroy_sq;
/** Create completion queue */
struct ena_create_cq_rsp create_cq;
/** Destroy completion queue */
struct ena_destroy_cq_rsp destroy_cq;
/** Get feature */
struct ena_get_feature_rsp get_feature;
/** Get statistics */
struct ena_get_stats_rsp get_stats;
/** Padding */
uint8_t pad[64];
};
/** Admin queue */
struct ena_aq {
/** Requests */
union ena_aq_req *req;
/** Producer counter */
unsigned int prod;
};
/** Admin completion queue */
struct ena_acq {
/** Responses */
union ena_acq_rsp *rsp;
/** Consumer counter */
unsigned int cons;
/** Phase */
unsigned int phase;
};
/** Async event notification queue event */
struct ena_aenq_event {
/** Type of event */
uint16_t group;
/** ID of event */
uint16_t syndrome;
/** Phase */
uint8_t flags;
/** Reserved */
uint8_t reserved[3];
/** Timestamp */
uint64_t timestamp;
/** Additional event data */
uint8_t data[48];
} __attribute__ (( packed ));
/** Async event notification queue */
struct ena_aenq {
/** Events */
struct ena_aenq_event *evt;
};
/** Transmit submission queue entry */
struct ena_tx_sqe {
/** Length */
uint16_t len;
/** Reserved */
uint8_t reserved_a;
/** Flags */
uint8_t flags;
/** Reserved */
uint8_t reserved_b[3];
/** Request identifier */
uint8_t id;
/** Address */
uint64_t address;
} __attribute__ (( packed ));
/** Receive submission queue entry */
struct ena_rx_sqe {
/** Length */
uint16_t len;
/** Reserved */
uint8_t reserved_a;
/** Flags */
uint8_t flags;
/** Request identifier */
uint16_t id;
/** Reserved */
uint8_t reserved_b[2];
/** Address */
uint64_t address;
} __attribute__ (( packed ));
/** Submission queue ownership phase flag */
#define ENA_SQE_PHASE 0x01
/** This is the first descriptor */
#define ENA_SQE_FIRST 0x04
/** This is the last descriptor */
#define ENA_SQE_LAST 0x08
/** Request completion */
#define ENA_SQE_CPL 0x10
/** Transmit completion queue entry */
struct ena_tx_cqe {
/** Request identifier */
uint16_t id;
/** Status */
uint8_t status;
/** Flags */
uint8_t flags;
/** Reserved */
uint8_t reserved[2];
/** Consumer index */
uint16_t cons;
} __attribute__ (( packed ));
/** Transmit completion request identifier */
#define ENA_TX_CQE_ID(id) ( (id) >> 2 )
/** Receive completion queue entry */
struct ena_rx_cqe {
/** Reserved */
uint8_t reserved_a[3];
/** Flags */
uint8_t flags;
/** Length */
uint16_t len;
/** Request identifier */
uint16_t id;
/** Reserved */
uint8_t reserved_b[8];
} __attribute__ (( packed ));
/** Completion queue ownership phase flag */
#define ENA_CQE_PHASE 0x01
/** Submission queue */
struct ena_sq {
/** Entries */
union {
/** Transmit submission queue entries */
struct ena_tx_sqe *tx;
/** Receive submission queue entries */
struct ena_rx_sqe *rx;
/** Raw data */
void *raw;
} sqe;
/** Buffer IDs */
uint8_t *ids;
/** Doorbell register offset */
unsigned int doorbell;
/** Total length of entries */
size_t len;
/** Producer counter */
unsigned int prod;
/** Phase */
unsigned int phase;
/** Submission queue identifier */
uint16_t id;
/** Direction */
uint8_t direction;
/** Number of entries */
uint8_t count;
/** Maximum fill level */
uint8_t max;
/** Fill level (limited to completion queue size) */
uint8_t fill;
};
/**
* Initialise submission queue
*
* @v sq Submission queue
* @v direction Direction
* @v count Number of entries
* @v max Maximum fill level
* @v size Size of each entry
* @v ids Buffer IDs
*/
static inline __attribute__ (( always_inline )) void
ena_sq_init ( struct ena_sq *sq, unsigned int direction, unsigned int count,
unsigned int max, size_t size, uint8_t *ids ) {
sq->len = ( count * size );
sq->direction = direction;
sq->count = count;
sq->max = max;
sq->ids = ids;
}
/** Completion queue */
struct ena_cq {
/** Entries */
union {
/** Transmit completion queue entries */
struct ena_tx_cqe *tx;
/** Receive completion queue entries */
struct ena_rx_cqe *rx;
/** Raw data */
void *raw;
} cqe;
/** Doorbell register offset */
unsigned int doorbell;
/** Total length of entries */
size_t len;
/** Consumer counter */
unsigned int cons;
/** Phase */
unsigned int phase;
/** Completion queue identifier */
uint16_t id;
/** Entry size (in 32-bit words) */
uint8_t size;
/** Requested number of entries */
uint8_t requested;
/** Actual number of entries */
uint8_t actual;
/** Actual number of entries minus one */
uint8_t mask;
};
/**
* Initialise completion queue
*
* @v cq Completion queue
* @v count Number of entries
* @v size Size of each entry
*/
static inline __attribute__ (( always_inline )) void
ena_cq_init ( struct ena_cq *cq, unsigned int count, size_t size ) {
cq->len = ( count * size );
cq->size = ( size / sizeof ( uint32_t ) );
cq->requested = count;
}
/** Queue pair */
struct ena_qp {
/** Submission queue */
struct ena_sq sq;
/** Completion queue */
struct ena_cq cq;
};
/** An ENA network card */
struct ena_nic {
/** Registers */
void *regs;
/** Host info */
struct ena_host_info *info;
/** Admin queue */
struct ena_aq aq;
/** Admin completion queue */
struct ena_acq acq;
/** Async event notification queue */
struct ena_aenq aenq;
/** Transmit queue */
struct ena_qp tx;
/** Receive queue */
struct ena_qp rx;
/** Transmit buffer IDs */
uint8_t tx_ids[ENA_TX_COUNT];
/** Transmit I/O buffers, indexed by buffer ID */
struct io_buffer *tx_iobuf[ENA_TX_COUNT];
/** Receive buffer IDs */
uint8_t rx_ids[ENA_RX_COUNT];
/** Receive I/O buffers, indexed by buffer ID */
struct io_buffer *rx_iobuf[ENA_RX_COUNT];
};
#endif /* _ENA_H */