#ifndef _ENA_H #define _ENA_H /** @file * * Amazon ENA network driver * */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include /** 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 */