#ifndef _ENA_H
#define _ENA_H
#include <sys/stdbool.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/types.h>
#include <sys/atomic.h>
#include <sys/list.h>
#include <sys/time.h>
#include <sys/modctl.h>
#include <sys/conf.h>
#include <sys/cpuvar.h>
#include <sys/pci.h>
#include <sys/sysmacros.h>
#include <sys/mac.h>
#include <sys/mac_ether.h>
#include <sys/mac_provider.h>
#include <sys/pattr.h>
#include <sys/strsun.h>
#include <sys/ethernet.h>
#include <sys/vlan.h>
#include <sys/utsname.h>
#include "ena_hw.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ENA_MODULE_NAME "ena"
#define ENA_CTRL_MAJOR_VSN_MIN 0
#define ENA_CTRL_MINOR_VSN_MIN 0
#define ENA_CTRL_SUBMINOR_VSN_MIN 1
#define ENA_MODULE_VER_MAJOR 1
#define ENA_MODULE_VER_MINOR 1
#define ENA_MODULE_VER_SUBMINOR 0
#define ENA_SPEC_VERSION_MAJOR 2
#define ENA_SPEC_VERSION_MINOR 0
#define ENA_REG_BAR 0
#define ENA_LLQ_BAR 2
#define ENA_INTERRUPT_MODE -1
#define ENA_RX_BUF_IPHDR_ALIGNMENT 2
#define ENA_ADMINQ_DEPTH 32
#define ENA_AENQ_NUM_DESCS 32
#define ENA_MS_TO_NS(ms) ((ms) * 1000000ul)
#define ENA_ADMIN_CMD_DEF_TIMEOUT_NS MSEC2NSEC(500)
#define ENA_WATCHDOG_INTERVAL_NS MSEC2NSEC(1000)
#define ENA_DEVICE_KEEPALIVE_TIMEOUT_NS MSEC2NSEC(6000)
#define ENA_TX_STALL_TIMEOUT 8
#define ENA_BASIC_STATS_MINIMUM_INTERVAL_NS MSEC2NSEC(10);
#define ENA_PROP_RXQ_NUM_DESCS "rx_queue_num_descs"
#define ENA_PROP_RXQ_NUM_DESCS_MIN 64
#define ENA_PROP_TXQ_NUM_DESCS "tx_queue_num_descs"
#define ENA_PROP_TXQ_NUM_DESCS_MIN 64
#define ENA_PROP_RXQ_INTR_LIMIT "rx_queue_intr_limit"
#define ENA_PROP_RXQ_INTR_LIMIT_MIN 16
#define ENA_PROP_RXQ_INTR_LIMIT_MAX 4096
#define ENA_PROP_RXQ_INTR_LIMIT_DEF 256
#define ENA_DMA_BIT_MASK(x) ((1ULL << (x)) - 1ULL)
#define ENA_DMA_VERIFY_ADDR(ena, phys_addr) \
VERIFY3U(ENA_DMA_BIT_MASK((ena)->ena_dma_width) & (phys_addr), \
==, (phys_addr))
typedef struct ena_dma_conf {
size_t edc_size;
uint64_t edc_align;
int edc_sgl;
uchar_t edc_endian;
bool edc_stream;
} ena_dma_conf_t;
typedef struct ena_dma_buf {
caddr_t edb_va;
size_t edb_len;
size_t edb_real_len;
size_t edb_used_len;
ddi_acc_handle_t edb_acc_hdl;
ddi_dma_handle_t edb_dma_hdl;
const ddi_dma_cookie_t *edb_cookie;
} ena_dma_buf_t;
#ifdef DEBUG
#define ENA_DMA_SYNC(buf, flag) \
ASSERT0(ddi_dma_sync((buf).edb_dma_hdl, 0, 0, (flag)))
#else
#define ENA_DMA_SYNC(buf, flag) \
((void)ddi_dma_sync((buf).edb_dma_hdl, 0, 0, (flag)))
#endif
typedef void (*ena_aenq_hdlr_t)(void *data, enahw_aenq_desc_t *desc);
typedef struct ena_aenq {
enahw_aenq_desc_t *eaenq_descs;
ena_dma_buf_t eaenq_dma;
ena_aenq_hdlr_t eaenq_hdlrs[ENAHW_AENQ_GROUPS_ARR_NUM];
uint16_t eaenq_num_descs;
uint16_t eaenq_head;
uint8_t eaenq_phase;
} ena_aenq_t;
typedef struct ena_admin_sq {
enahw_cmd_desc_t *eas_entries;
ena_dma_buf_t eas_dma;
uint32_t *eas_dbaddr;
uint16_t eas_tail;
uint8_t eas_phase;
} ena_admin_sq_t;
typedef struct ena_admin_cq {
enahw_resp_desc_t *eac_entries;
ena_dma_buf_t eac_dma;
uint16_t eac_head;
uint8_t eac_phase;
} ena_admin_cq_t;
typedef struct ena_cmd_ctx {
list_node_t ectx_node;
uint16_t ectx_id;
bool ectx_pending;
enahw_cmd_opcode_t ectx_cmd_opcode;
enahw_resp_desc_t *ectx_resp;
} ena_cmd_ctx_t;
typedef struct ena_adminq {
kmutex_t ea_sq_lock;
kmutex_t ea_cq_lock;
kmutex_t ea_stat_lock;
hrtime_t ea_cmd_timeout_ns;
uint16_t ea_qlen;
bool ea_poll_mode;
ena_cmd_ctx_t *ea_cmd_ctxs;
list_t ea_cmd_ctxs_free;
list_t ea_cmd_ctxs_used;
uint16_t ea_pending_cmds;
ena_admin_sq_t ea_sq;
ena_admin_cq_t ea_cq;
struct ena_adminq_stats {
uint64_t cmds_fail;
uint64_t cmds_submitted;
uint64_t cmds_success;
uint64_t queue_full;
} ea_stats;
} ena_adminq_t;
typedef struct ena_hints {
uint16_t eh_mmio_read_timeout;
uint16_t eh_keep_alive_timeout;
uint16_t eh_tx_comp_timeout;
uint16_t eh_missed_tx_reset_threshold;
uint16_t eh_admin_comp_timeout;
uint16_t eh_max_tx_sgl;
uint16_t eh_max_rx_sgl;
} ena_hints_t;
typedef enum ena_attach_seq {
ENA_ATTACH_PCI = 1,
ENA_ATTACH_REGS,
ENA_ATTACH_DEV_INIT,
ENA_ATTACH_READ_CONF,
ENA_ATTACH_DEV_CFG,
ENA_ATTACH_INTR_ALLOC,
ENA_ATTACH_INTR_HDLRS,
ENA_ATTACH_TXQS_ALLOC,
ENA_ATTACH_RXQS_ALLOC,
ENA_ATTACH_MAC_REGISTER,
ENA_ATTACH_INTRS_ENABLE,
ENA_ATTACH_END
} ena_attach_seq_t;
#define ENA_ATTACH_SEQ_FIRST (ENA_ATTACH_PCI)
#define ENA_ATTACH_NUM_ENTRIES (ENA_ATTACH_END - 1)
struct ena;
typedef bool (*ena_attach_fn_t)(struct ena *);
typedef void (*ena_cleanup_fn_t)(struct ena *, bool);
typedef struct ena_attach_desc {
ena_attach_seq_t ead_seq;
const char *ead_name;
ena_attach_fn_t ead_attach_fn;
bool ead_attach_hard_fail;
ena_cleanup_fn_t ead_cleanup_fn;
} ena_attach_desc_t;
typedef enum {
ENA_TCB_NONE,
ENA_TCB_COPY
} ena_tcb_type_t;
typedef struct ena_tx_control_block {
uint16_t etcb_id;
mblk_t *etcb_mp;
ena_tcb_type_t etcb_type;
ena_dma_buf_t etcb_dma;
} ena_tx_control_block_t;
typedef enum ena_txq_state {
ENA_TXQ_STATE_NONE = 0,
ENA_TXQ_STATE_HOST_ALLOC = 1 << 0,
ENA_TXQ_STATE_CQ_CREATED = 1 << 1,
ENA_TXQ_STATE_SQ_CREATED = 1 << 2,
ENA_TXQ_STATE_READY = 1 << 3,
ENA_TXQ_STATE_RUNNING = 1 << 4,
} ena_txq_state_t;
typedef struct ena_txq_stat {
kstat_named_t ets_hck_meoifail;
kstat_named_t ets_blocked;
kstat_named_t ets_unblocked;
kstat_named_t ets_recycled;
kstat_named_t ets_bytes;
kstat_named_t ets_packets;
} ena_txq_stat_t;
typedef struct ena_txq {
kmutex_t et_lock;
struct ena *et_ena;
uint_t et_txqs_idx;
mac_ring_handle_t et_mrh;
uint64_t et_m_gen_num;
ena_txq_state_t et_state;
uint16_t et_intr_vector;
enahw_tx_desc_t *et_sq_descs;
ena_dma_buf_t et_sq_dma;
bool et_blocked;
uint16_t et_sq_num_descs;
uint16_t et_sq_avail_descs;
uint16_t et_sq_tail_idx;
uint16_t et_sq_phase;
uint16_t et_sq_hw_idx;
uint32_t *et_sq_db_addr;
void *et_sq_llq_addr;
uint8_t *et_sq_llq_buf;
uint32_t et_sq_llq_entries_left;
ena_tx_control_block_t *et_tcbs;
ena_tx_control_block_t **et_tcbs_freelist;
uint16_t et_tcbs_freelist_size;
enahw_tx_cdesc_t *et_cq_descs;
ena_dma_buf_t et_cq_dma;
uint16_t et_cq_num_descs;
uint16_t et_cq_head_idx;
uint16_t et_cq_phase;
uint16_t et_cq_hw_idx;
uint32_t *et_cq_unmask_addr;
uint32_t *et_cq_numa_addr;
uint32_t et_stall_watchdog;
kmutex_t et_stat_lock;
ena_txq_stat_t et_stat;
kstat_t *et_kstat;
} ena_txq_t;
typedef enum ena_rxq_state {
ENA_RXQ_STATE_NONE = 0,
ENA_RXQ_STATE_HOST_ALLOC = 1 << 0,
ENA_RXQ_STATE_CQ_CREATED = 1 << 1,
ENA_RXQ_STATE_SQ_CREATED = 1 << 2,
ENA_RXQ_STATE_SQ_FILLED = 1 << 3,
ENA_RXQ_STATE_READY = 1 << 4,
ENA_RXQ_STATE_RUNNING = 1 << 5,
} ena_rxq_state_t;
typedef struct ena_rx_ctrl_block {
ena_dma_buf_t ercb_dma;
uint8_t ercb_offset;
uint16_t ercb_length;
} ena_rx_ctrl_block_t;
typedef enum {
ENA_RXQ_MODE_POLLING = 1,
ENA_RXQ_MODE_INTR = 2,
} ena_rxq_mode_t;
typedef struct ena_rxq_stat_t {
kstat_named_t ers_packets;
kstat_named_t ers_bytes;
kstat_named_t ers_multi_desc;
kstat_named_t ers_allocb_fail;
kstat_named_t ers_intr_limit;
kstat_named_t ers_hck_ipv4_err;
kstat_named_t ers_hck_l4_err;
} ena_rxq_stat_t;
typedef struct ena_rxq {
kmutex_t er_lock;
struct ena *er_ena;
uint_t er_rxqs_idx;
mac_ring_handle_t er_mrh;
uint64_t er_m_gen_num;
ena_rxq_state_t er_state;
uint16_t er_intr_vector;
ena_rxq_mode_t er_mode;
uint16_t er_intr_limit;
enahw_rx_desc_t *er_sq_descs;
ena_dma_buf_t er_sq_dma;
uint16_t er_sq_num_descs;
uint16_t er_sq_avail_descs;
uint16_t er_sq_tail_idx;
uint16_t er_sq_phase;
uint16_t er_sq_hw_idx;
uint32_t *er_sq_db_addr;
enahw_rx_cdesc_t *er_cq_descs;
ena_dma_buf_t er_cq_dma;
uint16_t er_cq_num_descs;
uint16_t er_cq_head_idx;
uint16_t er_cq_phase;
uint16_t er_cq_hw_idx;
uint32_t *er_cq_unmask_addr;
uint32_t *er_cq_numa_addr;
ena_rx_ctrl_block_t *er_rcbs;
kmutex_t er_stat_lock;
ena_rxq_stat_t er_stat;
kstat_t *er_kstat;
} ena_rxq_t;
typedef struct ena_device_stat {
kstat_named_t eds_reset_forced;
kstat_named_t eds_reset_error;
kstat_named_t eds_reset_fatal;
kstat_named_t eds_reset_keepalive;
kstat_named_t eds_reset_txstall;
} ena_device_stat_t;
typedef struct ena_basic_stat {
kstat_named_t ebs_tx_bytes;
kstat_named_t ebs_tx_pkts;
kstat_named_t ebs_tx_drops;
kstat_named_t ebs_rx_bytes;
kstat_named_t ebs_rx_pkts;
kstat_named_t ebs_rx_drops;
kstat_named_t ebs_rx_overruns;
} ena_basic_stat_t;
typedef struct ena_extended_stat {
kstat_named_t ees_bw_in_exceeded;
kstat_named_t ees_bw_out_exceeded;
kstat_named_t ees_pps_exceeded;
kstat_named_t ees_conns_exceeded;
kstat_named_t ees_linklocal_exceeded;
} ena_extended_stat_t;
typedef struct ena_aenq_stat {
kstat_named_t eaes_default;
kstat_named_t eaes_link_change;
kstat_named_t eaes_notification;
kstat_named_t eaes_keep_alive;
kstat_named_t eaes_request_reset;
kstat_named_t eaes_fatal_error;
kstat_named_t eaes_warning;
} ena_aenq_stat_t;
#ifdef DEBUG
typedef struct ena_reg {
const char *er_name;
const uint16_t er_offset;
uint32_t er_value;
} ena_reg_t;
#endif
#define ENA_STATE_UNKNOWN 0x00u
#define ENA_STATE_INITIALIZED 0x01u
#define ENA_STATE_STARTED 0x02u
#define ENA_STATE_ERROR 0x04u
#define ENA_STATE_RESETTING 0x08u
typedef struct ena {
dev_info_t *ena_dip;
int ena_instance;
#ifdef DEBUG
ena_reg_t ena_reg[ENAHW_NUM_REGS];
#endif
kmutex_t ena_lock;
ena_attach_seq_t ena_attach_seq;
uint32_t ena_state;
enahw_reset_reason_t ena_reset_reason;
kmutex_t ena_watchdog_lock;
ddi_periodic_t ena_watchdog_periodic;
uint64_t ena_watchdog_last_keepalive;
ddi_acc_handle_t ena_pci_hdl;
off_t ena_reg_size;
caddr_t ena_reg_base;
ddi_acc_handle_t ena_reg_hdl;
bool ena_llq_bar_mapped;
off_t ena_llq_bar_size;
caddr_t ena_llq_bar_base;
ddi_acc_handle_t ena_llq_bar_hdl;
uint16_t ena_pci_vid;
uint16_t ena_pci_did;
uint8_t ena_pci_rev;
uint16_t ena_pci_svid;
uint16_t ena_pci_sdid;
uint32_t ena_dev_major_vsn;
uint32_t ena_dev_minor_vsn;
uint32_t ena_ctrl_major_vsn;
uint32_t ena_ctrl_minor_vsn;
uint32_t ena_ctrl_subminor_vsn;
uint32_t ena_ctrl_impl_id;
int ena_num_intrs;
ddi_intr_handle_t *ena_intr_handles;
size_t ena_intr_handles_sz;
int ena_intr_caps;
uint_t ena_intr_pri;
mac_handle_t ena_mh;
size_t ena_page_sz;
uint32_t ena_mtu;
uint32_t ena_max_frame_hdr;
uint32_t ena_max_frame_total;
uint32_t ena_tx_buf_sz;
uint32_t ena_rx_buf_sz;
uint8_t ena_tx_sgl_max_sz;
uint8_t ena_rx_sgl_max_sz;
uint16_t ena_rxq_num_descs;
uint16_t ena_txq_num_descs;
uint16_t ena_rxq_intr_limit;
ena_rxq_t *ena_rxqs;
uint16_t ena_num_rxqs;
ena_txq_t *ena_txqs;
uint16_t ena_num_txqs;
kstat_t *ena_device_kstat;
ena_device_stat_t ena_device_stat;
hrtime_t ena_device_basic_stat_last_update;
kmutex_t ena_device_basic_stat_lock;
kstat_t *ena_device_basic_kstat;
kstat_t *ena_device_extended_kstat;
ena_aenq_stat_t ena_aenq_stat;
kstat_t *ena_aenq_kstat;
ena_adminq_t ena_aq;
ena_aenq_t ena_aenq;
ena_dma_buf_t ena_host_info;
ena_hints_t ena_device_hints;
uint32_t ena_supported_features;
uint32_t ena_capabilities;
uint8_t ena_dma_width;
bool ena_link_autoneg;
link_duplex_t ena_link_duplex;
uint64_t ena_link_speed_mbits;
enahw_link_speeds_t ena_link_speeds;
link_state_t ena_link_state;
uint32_t ena_aenq_supported_groups;
uint32_t ena_aenq_enabled_groups;
bool ena_llq_enabled;
enahw_llq_header_location_t ena_llq_header_location;
enahw_llq_ring_entry_size_t ena_llq_entry_size;
uint16_t ena_llq_entry_size_bytes;
enahw_llq_num_descs_before_header_t ena_llq_num_descs_before_header;
enahw_llq_stride_ctrl_t ena_llq_stride_ctrl;
uint16_t ena_llq_max_tx_burst_size;
uint32_t ena_tx_max_sq_num;
uint32_t ena_tx_max_sq_num_descs;
uint32_t ena_tx_max_cq_num;
uint32_t ena_tx_max_cq_num_descs;
uint16_t ena_tx_max_desc_per_pkt;
uint32_t ena_tx_max_hdr_len;
uint32_t ena_rx_max_sq_num;
uint32_t ena_rx_max_sq_num_descs;
uint32_t ena_rx_max_cq_num;
uint32_t ena_rx_max_cq_num_descs;
uint16_t ena_rx_max_desc_per_pkt;
uint16_t ena_max_io_queues;
bool ena_tx_l3_ipv4_csum;
bool ena_tx_l4_ipv4_part_csum;
bool ena_tx_l4_ipv4_full_csum;
bool ena_tx_l4_ipv4_lso;
bool ena_tx_l4_ipv6_part_csum;
bool ena_tx_l4_ipv6_full_csum;
bool ena_tx_l4_ipv6_lso;
bool ena_rx_l3_ipv4_csum;
bool ena_rx_l4_ipv4_csum;
bool ena_rx_l4_ipv6_csum;
bool ena_rx_hash;
uint32_t ena_max_mtu;
uint8_t ena_mac_addr[ETHERADDRL];
} ena_t;
extern bool ena_reset(ena_t *, const enahw_reset_reason_t);
extern bool ena_is_feat_avail(ena_t *, const enahw_feature_id_t);
extern bool ena_is_cap_avail(ena_t *, const enahw_capability_id_t);
extern void ena_update_hints(ena_t *, enahw_device_hints_t *);
extern bool ena_debug;
extern void ena_err(const ena_t *, const char *, ...) __KPRINTFLIKE(2);
extern void ena_dbg(const ena_t *, const char *, ...) __KPRINTFLIKE(2);
extern void ena_panic(const ena_t *, const char *, ...) __KPRINTFLIKE(2);
extern void ena_trigger_reset(ena_t *, enahw_reset_reason_t);
extern uint32_t ena_hw_bar_read32(const ena_t *, const uint16_t);
extern uint32_t ena_hw_abs_read32(const ena_t *, uint32_t *);
extern void ena_hw_bar_write32(const ena_t *, const uint16_t, const uint32_t);
extern void ena_hw_abs_write32(const ena_t *, uint32_t *, const uint32_t);
extern const char *enahw_reset_reason(enahw_reset_reason_t);
#ifdef DEBUG
extern void ena_init_regcache(ena_t *);
extern void ena_update_regcache(ena_t *);
#else
#define ena_init_regcache(x)
#define ena_update_regcache(x)
#endif
extern void ena_enable_watchdog(ena_t *);
extern void ena_disable_watchdog(ena_t *);
extern void ena_stat_device_cleanup(ena_t *);
extern bool ena_stat_device_init(ena_t *);
extern void ena_stat_device_basic_cleanup(ena_t *);
extern bool ena_stat_device_basic_init(ena_t *);
extern void ena_stat_device_extended_cleanup(ena_t *);
extern bool ena_stat_device_extended_init(ena_t *);
extern void ena_stat_aenq_cleanup(ena_t *);
extern bool ena_stat_aenq_init(ena_t *);
extern void ena_stat_rxq_cleanup(ena_rxq_t *);
extern bool ena_stat_rxq_init(ena_rxq_t *);
extern void ena_stat_txq_cleanup(ena_txq_t *);
extern bool ena_stat_txq_init(ena_txq_t *);
extern bool ena_dma_alloc(ena_t *, ena_dma_buf_t *, ena_dma_conf_t *,
size_t);
extern void ena_dma_free(ena_dma_buf_t *);
extern void ena_dma_bzero(ena_dma_buf_t *);
extern void ena_set_dma_addr(const ena_t *, const uint64_t, enahw_addr_t *);
extern void ena_set_dma_addr_values(const ena_t *, const uint64_t, uint32_t *,
uint16_t *);
extern bool ena_intr_add_handlers(ena_t *);
extern void ena_intr_remove_handlers(ena_t *, bool);
extern void ena_tx_intr_work(ena_txq_t *);
extern void ena_rx_intr_work(ena_rxq_t *);
extern bool ena_intrs_disable(ena_t *);
extern bool ena_intrs_enable(ena_t *);
extern bool ena_mac_register(ena_t *);
extern int ena_mac_unregister(ena_t *);
extern void ena_ring_tx_stop(mac_ring_driver_t);
extern int ena_ring_tx_start(mac_ring_driver_t, uint64_t);
extern mblk_t *ena_ring_tx(void *, mblk_t *);
extern void ena_ring_rx_stop(mac_ring_driver_t);
extern int ena_ring_rx_start(mac_ring_driver_t rh, uint64_t gen_num);
extern int ena_m_stat(void *, uint_t, uint64_t *);
extern mblk_t *ena_ring_rx_poll(void *, int);
extern int ena_ring_rx_stat(mac_ring_driver_t, uint_t, uint64_t *);
extern int ena_ring_tx_stat(mac_ring_driver_t, uint_t, uint64_t *);
extern int ena_admin_submit_cmd(ena_t *, enahw_cmd_desc_t *,
enahw_resp_desc_t *, ena_cmd_ctx_t **);
extern int ena_admin_poll_for_resp(ena_t *, ena_cmd_ctx_t *);
extern void ena_free_host_info(ena_t *);
extern bool ena_init_host_info(ena_t *);
extern void ena_create_cmd_ctx(ena_t *);
extern void ena_release_all_cmd_ctx(ena_t *);
extern int ena_create_cq(ena_t *, uint16_t, uint64_t, bool, uint32_t,
uint16_t *, uint32_t **, uint32_t **);
extern int ena_destroy_cq(ena_t *, uint16_t);
extern int ena_create_sq(ena_t *, uint16_t, uint64_t, bool, uint16_t,
uint16_t *, uint32_t **, void **);
extern int ena_destroy_sq(ena_t *, uint16_t, bool);
extern int ena_set_feature(ena_t *, enahw_cmd_desc_t *,
enahw_resp_desc_t *, const enahw_feature_id_t, const uint8_t);
extern int ena_get_feature(ena_t *, enahw_resp_desc_t *,
const enahw_feature_id_t, const uint8_t);
extern int ena_admin_get_basic_stats(ena_t *, enahw_resp_desc_t *);
extern int ena_admin_get_eni_stats(ena_t *, enahw_resp_desc_t *);
extern int enahw_resp_status_to_errno(ena_t *, enahw_resp_status_t);
extern bool ena_aenq_init(ena_t *);
extern bool ena_aenq_configure(ena_t *);
extern void ena_aenq_enable(ena_t *);
extern void ena_aenq_work(ena_t *);
extern void ena_aenq_free(ena_t *);
extern bool ena_alloc_rxq(ena_rxq_t *);
extern void ena_cleanup_rxq(ena_rxq_t *, bool);
extern bool ena_alloc_txq(ena_txq_t *);
extern void ena_cleanup_txq(ena_txq_t *, bool);
#ifdef __cplusplus
}
#endif
#endif