1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
|
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright 2026 Oxide Computer Company
*/
#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"
/*
* AWS ENA Ethernet Driver
*/
#ifdef __cplusplus
extern "C" {
#endif
#define ENA_MODULE_NAME "ena"
/*
* The minimum supported ENA device controller version.
*/
#define ENA_CTRL_MAJOR_VSN_MIN 0
#define ENA_CTRL_MINOR_VSN_MIN 0
#define ENA_CTRL_SUBMINOR_VSN_MIN 1
/*
* These values are used to communicate the driver version to the AWS
* hypervisor via the HOST_ATTR_CONFIG feature. We don't know what
* exactly AWS does with this info, but it's fairly safe to assume
* it's used solely for debug/informational purposes. The Linux driver
* updates these values frequently as bugs are fixed and features are
* added. Some instance types have minimum driver version requirements
* but they do not appear to check the version we pass.
*/
#define ENA_MODULE_VER_MAJOR 1
#define ENA_MODULE_VER_MINOR 1
#define ENA_MODULE_VER_SUBMINOR 0
/*
* The Linux driver doesn't document what the specification version
* number controls or the contract around version changes. The best we
* can do is use the same version that they use and port version
* changes as they come (the last one was in 2018).
*
* common: ENA_COMMON_SPEC_VERSION_{MAJOR,MINOR}
*/
#define ENA_SPEC_VERSION_MAJOR 2
#define ENA_SPEC_VERSION_MINOR 0
/* PCI BAR index for the register BAR */
#define ENA_REG_BAR 0
/* PCI BAR index for the LLQ memory BAR */
#define ENA_LLQ_BAR 2
/*
* A sentinel value passed as argument to ena_ring_rx() to indicate
* the Rx ring is being read in interrupt mode, not polling mode.
*/
#define ENA_INTERRUPT_MODE -1
#define ENA_RX_BUF_IPHDR_ALIGNMENT 2
#define ENA_ADMINQ_DEPTH 32
#define ENA_AENQ_NUM_DESCS 32
/* Convert milliseconds to nanoseconds. */
#define ENA_MS_TO_NS(ms) ((ms) * 1000000ul)
/*
* The default amount of time we will wait for an admin command to complete,
* specified in nanoseconds. This can be overridden by hints received from the
* device. We default to half a second.
*/
#define ENA_ADMIN_CMD_DEF_TIMEOUT_NS MSEC2NSEC(500)
/*
* The interval of the watchdog timer, in nanoseconds.
*/
#define ENA_WATCHDOG_INTERVAL_NS MSEC2NSEC(1000)
/*
* The device sends a keepalive message every second. If we don't see any for
* a while we will trigger a device reset. Other open source drivers use
* 6 seconds for this value, so do we.
*/
#define ENA_DEVICE_KEEPALIVE_TIMEOUT_NS MSEC2NSEC(6000)
/*
* The number of consecutive times a TX queue needs to be seen as blocked by
* the watchdog timer before a reset is invoked. Since the watchdog interval
* is one second, this is approximately in seconds.
*/
#define ENA_TX_STALL_TIMEOUT 8
/*
* In order to avoid rapidly sending basic stats requests to the controller, we
* impose a limit of one request every 10ms.
*/
#define ENA_BASIC_STATS_MINIMUM_INTERVAL_NS MSEC2NSEC(10);
/*
* Property macros.
*/
#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;
/*
* The length given by DMA engine, kept around for debugging
* purposes.
*/
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;
/*
* We always sync the entire range, and therefore expect success.
*/
#ifdef DEBUG
#define ENA_DMA_SYNC(buf, flag) \
ASSERT0(ddi_dma_sync((buf).edb_dma_hdl, 0, 0, (flag)))
#else /* DEBUG */
#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;
/*
* The command context is used to track outstanding requests and match
* them to device responses.
*/
typedef struct ena_cmd_ctx {
list_node_t ectx_node;
/*
* The index into ea_cmd_ctxs where this ctx lives. Used as
* the command ID value in the command descriptor. This allows
* us to match a response to its associated context.
*/
uint16_t ectx_id;
/* Is the command pending? */
bool ectx_pending;
/* The type of command associated with this context. */
enahw_cmd_opcode_t ectx_cmd_opcode;
/*
* The location to copy the full response to. This is
* specified by the caller of the command during
* submission.
*/
enahw_resp_desc_t *ectx_resp;
} ena_cmd_ctx_t;
/*
* The admin queue, the queue through which commands are sent to the
* device.
*
* WO: Write Once (at initialization)
*
* In general, only a single lock needs to be held in order to access
* the different parts of the admin queue:
*
* sq_lock: Any data dealing with submitting admin commands, which
* includes acquiring a command context.
*
* cq_lock: Any data dealing with reading command responses.
*
* stat_lock: For accessing statistics.
*
* In some cases, the ectx_lock/stat_lock may be held in tandem with
* either the SQ or CQ lock. In that case, the SQ/CQ lock is always
* entered first.
*/
typedef struct ena_adminq {
kmutex_t ea_sq_lock; /* WO */
kmutex_t ea_cq_lock; /* WO */
kmutex_t ea_stat_lock; /* WO */
hrtime_t ea_cmd_timeout_ns; /* WO */
uint16_t ea_qlen; /* WO */
bool ea_poll_mode; /* WO */
ena_cmd_ctx_t *ea_cmd_ctxs; /* WO */
list_t ea_cmd_ctxs_free; /* ea_sq_lock */
list_t ea_cmd_ctxs_used; /* ea_sq_lock */
uint16_t ea_pending_cmds; /* ea_sq_lock */
ena_admin_sq_t ea_sq; /* eq_sq_lock */
ena_admin_cq_t ea_cq; /* eq_cq_lock */
/* ea_stat_lock */
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;
/*
* Cache of the last set of value hints received from the device. See the
* definition of ehahw_device_hints_t in ena_hw.h for more detail on the
* purpose of each.
*/
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, /* PCI config space */
ENA_ATTACH_REGS, /* BAR mapping */
ENA_ATTACH_DEV_INIT, /* ENA device initialization */
ENA_ATTACH_READ_CONF, /* Read driver conf file */
ENA_ATTACH_DEV_CFG, /* Set any needed device config */
ENA_ATTACH_INTR_ALLOC, /* interrupt handles allocated */
ENA_ATTACH_INTR_HDLRS, /* intr handlers set */
ENA_ATTACH_TXQS_ALLOC, /* Tx Queues allocated */
ENA_ATTACH_RXQS_ALLOC, /* Tx Queues allocated */
ENA_ATTACH_MAC_REGISTER, /* registered with mac */
ENA_ATTACH_INTRS_ENABLE, /* interrupts are enabled */
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;
/*
* The TCB is used to track information relating to the Tx of a
* packet. At the moment we support copy only.
*/
typedef struct ena_tx_control_block {
/*
* The index into et_tcbs where this tcb lives. Used as the request ID
* value in the Tx descriptor. This allows us to match a response to
* its associated TCB.
*/
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, /* TxQ ready and waiting */
ENA_TXQ_STATE_RUNNING = 1 << 4, /* intrs enabled */
} ena_txq_state_t;
typedef struct ena_txq_stat {
/* Number of times mac_ether_offload_info() has failed. */
kstat_named_t ets_hck_meoifail;
/*
* Total number of times the ring was blocked due to
* insufficient descriptors, or unblocked due to recycling
* descriptors.
*/
kstat_named_t ets_blocked;
kstat_named_t ets_unblocked;
/* The total number descriptors that have been recycled. */
kstat_named_t ets_recycled;
/*
* Number of bytes and packets that have been _submitted_ to
* the device.
*/
kstat_named_t ets_bytes;
kstat_named_t ets_packets;
} ena_txq_stat_t;
/*
* A transmit queue, made up of a Submission Queue (SQ) and Completion
* Queue (CQ) to form a logical descriptor ring for sending packets.
*
* Write Once (WO)
*
* This value is written once, before the datapath is activated, in
* a function which is controlled by mac(9E). Some values may be
* written earlier, during ena attach, like et_ena and
* et_sq_num_descs.
*
* Tx Mutex (TM) -- et_lock
*
* This value is protected by the Tx queue's mutex. Some values may
* be initialized in a WO path, but also continually updated as part
* of normal datapath operation, such as et_sq_avail_descs. These
* values need mutex protection.
*/
typedef struct ena_txq {
kmutex_t et_lock; /* WO */
struct ena *et_ena; /* WO */
uint_t et_txqs_idx; /* WO */
mac_ring_handle_t et_mrh; /* WO */
uint64_t et_m_gen_num; /* TM */
ena_txq_state_t et_state; /* WO */
uint16_t et_intr_vector; /* WO */
enahw_tx_desc_t *et_sq_descs; /* TM */
ena_dma_buf_t et_sq_dma; /* WO */
/* Is the Tx queue currently in a blocked state? */
bool et_blocked; /* TM */
/*
* The number of descriptors owned by this ring. This value
* never changes after initialization.
*/
uint16_t et_sq_num_descs; /* WO */
/*
* The number of descriptors currently available for Tx
* submission. When this value reaches zero the ring must
* block until device notifies us of freed descriptors.
*/
uint16_t et_sq_avail_descs; /* TM */
/*
* The current tail index of the queue (the first free
* descriptor for host Tx submission). After initialization,
* this value only increments, relying on unsigned wrap
* around. The ENA device seems to expect this behavior,
* performing its own modulo on the value for the purposes of
* indexing, much like the driver code needs to do in order to
* access the proper TCB entry.
*/
uint16_t et_sq_tail_idx; /* TM */
/*
* The phase is used to know which CQ descriptors may be
* reclaimed. This is explained further in ena.c.
*/
uint16_t et_sq_phase; /* TM */
uint16_t et_sq_hw_idx; /* WO */
/*
* The "doorbell" address is how the host indicates to the
* device which descriptors are ready for Tx processing.
*/
uint32_t *et_sq_db_addr; /* WO */
/*
* LLQ state for this queue. When LLQ is active descriptors
* are written to device memory at et_sq_llq_addr rather than
* to host memory at et_sq_descs.
*
* The bounce buffer (et_sq_llq_buf) is used to stage a
* complete LLQ entry before copying it to device memory.
*
* The burst counter (et_sq_llq_entries_left) tracks the
* number of LLQ entries that may be written before the next
* doorbell, for the LIMIT_TX_BURST acceleration feature.
*/
void *et_sq_llq_addr; /* WO */
uint8_t *et_sq_llq_buf; /* TM */
uint32_t et_sq_llq_entries_left; /* TM */
/*
* The TCBs track host Tx information, like a pointer to the
* mblk being submitted. The TCBs currently available for use are
* maintained in a free list.
*/
ena_tx_control_block_t *et_tcbs; /* TM */
ena_tx_control_block_t **et_tcbs_freelist; /* TM */
uint16_t et_tcbs_freelist_size; /* TM */
enahw_tx_cdesc_t *et_cq_descs; /* TM */
ena_dma_buf_t et_cq_dma; /* WO */
uint16_t et_cq_num_descs; /* WO */
uint16_t et_cq_head_idx; /* TM */
uint16_t et_cq_phase; /* TM */
uint16_t et_cq_hw_idx; /* WO */
/*
* This address is used to control the CQ interrupts.
*/
uint32_t *et_cq_unmask_addr; /* WO */
uint32_t *et_cq_numa_addr; /* WO (currently unused) */
/*
* This is used to detect transmit stalls and invoke a reset. The
* watchdog increments this counter when it sees that the TX
* ring is still blocked, and if it exceeds the threshold then the
* device is assumed to have stalled and needs to be reset.
*/
uint32_t et_stall_watchdog; /* TM */
/*
* This mutex protects the Tx queue stats. This mutex may be
* entered while et_lock is held, but et_lock is not required
* to access/modify the stats. However, if both locks are
* held, then et_lock must be entered first.
*/
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, /* RxQ ready and waiting */
ENA_RXQ_STATE_RUNNING = 1 << 5, /* intrs enabled */
} 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 {
/* The total number of packets/bytes received on this queue. */
kstat_named_t ers_packets;
kstat_named_t ers_bytes;
/*
* At this time we expect all incoming frames to fit in a
* single buffer/descriptor. In some rare event that the
* device doesn't cooperate this stat is incremented.
*/
kstat_named_t ers_multi_desc;
/*
* The total number of times we failed to allocate a new mblk
* for an incoming frame.
*/
kstat_named_t ers_allocb_fail;
/*
* The total number of times the Rx interrupt handler reached
* its maximum limit for number of packets to process in a
* single interrupt. If you see this number increase
* continuously at a steady rate, then it may be an indication
* the driver is not entering polling mode.
*/
kstat_named_t ers_intr_limit;
/*
* The total number of times the device detected an incorrect
* IPv4 header checksum.
*/
kstat_named_t ers_hck_ipv4_err;
/*
* The total number of times the device detected an incorrect
* L4/ULP checksum.
*/
kstat_named_t ers_hck_l4_err;
} ena_rxq_stat_t;
/*
* A receive queue, made up of a Submission Queue (SQ) and Completion
* Queue (CQ) to form a logical descriptor ring for receiving packets.
*
* Write Once (WO)
*
* This value is written once, before the datapath is activated, in
* a function which is controlled by mac(9E).
*
* Rx Mutex (RM) -- er_lock
*
* This value is protected by the Rx queue's mutex. Some values may
* be initialized in a WO path, but also continually updated as part
* of normal datapath operation, such as er_sq_avail_descs. These
* values need mutex protection.
*/
typedef struct ena_rxq {
kmutex_t er_lock;
struct ena *er_ena; /* WO */
uint_t er_rxqs_idx; /* WO */
mac_ring_handle_t er_mrh; /* WO */
uint64_t er_m_gen_num; /* WO */
ena_rxq_state_t er_state; /* WO */
uint16_t er_intr_vector; /* WO */
ena_rxq_mode_t er_mode; /* RM */
uint16_t er_intr_limit; /* RM */
enahw_rx_desc_t *er_sq_descs; /* RM */
ena_dma_buf_t er_sq_dma; /* WO */
uint16_t er_sq_num_descs; /* WO */
uint16_t er_sq_avail_descs; /* RM */
uint16_t er_sq_tail_idx; /* RM */
uint16_t er_sq_phase; /* RM */
uint16_t er_sq_hw_idx; /* WO */
uint32_t *er_sq_db_addr; /* WO */
enahw_rx_cdesc_t *er_cq_descs; /* RM */
ena_dma_buf_t er_cq_dma; /* WO */
uint16_t er_cq_num_descs; /* WO */
uint16_t er_cq_head_idx; /* RM */
uint16_t er_cq_phase; /* RM */
uint16_t er_cq_hw_idx; /* WO */
uint32_t *er_cq_unmask_addr; /* WO */
uint32_t *er_cq_numa_addr; /* WO (currently unused) */
ena_rx_ctrl_block_t *er_rcbs; /* RM */
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;
/*
* These are stats based on enahw_resp_basic_stats_t and data that accompanies
* the asynchronous keepalive event.
*/
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;
/* These are stats based on enahw_resp_eni_stats_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;
/* These stats monitor which AENQ handlers have been called. */
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
/*
* This structure contains the per-instance (PF of VF) state of the
* device.
*/
typedef struct ena {
dev_info_t *ena_dip;
int ena_instance;
#ifdef DEBUG
/*
* In debug kernels, the registers are cached here at various points
* for easy inspection via mdb(1).
*/
ena_reg_t ena_reg[ENAHW_NUM_REGS];
#endif
/*
* Global lock, used to synchronize administration changes to
* the ena_t. This lock should not be held in the datapath.
*/
kmutex_t ena_lock;
ena_attach_seq_t ena_attach_seq;
/*
* We use atomic ops for ena_state so that datapath consumers
* do not need to enter ena_lock.
*/
uint32_t ena_state;
/*
* The reason for the last device reset.
*/
enahw_reset_reason_t ena_reset_reason;
/*
* Watchdog
*/
kmutex_t ena_watchdog_lock;
ddi_periodic_t ena_watchdog_periodic;
uint64_t ena_watchdog_last_keepalive;
/*
* PCI config space handle
*/
ddi_acc_handle_t ena_pci_hdl;
/*
* Memory BAR for registers
*/
off_t ena_reg_size;
caddr_t ena_reg_base;
ddi_acc_handle_t ena_reg_hdl;
/*
* Memory BAR for LLQ device memory
*/
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;
/*
* Vendor information.
*/
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;
/*
* Device and controller versions.
*/
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;
/*
* Interrupts
*/
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;
/*
* The MTU and data layer frame sizes.
*/
uint32_t ena_mtu;
uint32_t ena_max_frame_hdr;
uint32_t ena_max_frame_total;
/* The size (in bytes) of the Rx/Tx data buffers. */
uint32_t ena_tx_buf_sz;
uint32_t ena_rx_buf_sz;
/*
* The maximum number of Scatter Gather List segments the
* device can address.
*/
uint8_t ena_tx_sgl_max_sz;
uint8_t ena_rx_sgl_max_sz;
/* The number of descriptors per Rx/Tx queue. */
uint16_t ena_rxq_num_descs;
uint16_t ena_txq_num_descs;
/*
* The maximum number of frames which may be read per Rx
* interrupt.
*/
uint16_t ena_rxq_intr_limit;
/* The Rx/Tx data queues (rings). */
ena_rxq_t *ena_rxqs;
uint16_t ena_num_rxqs;
ena_txq_t *ena_txqs;
uint16_t ena_num_txqs;
/* These statistics are device-wide. */
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;
/*
* This tracks AENQ-related stats, it is implicitly
* device-wide.
*/
ena_aenq_stat_t ena_aenq_stat;
kstat_t *ena_aenq_kstat;
/*
* The Admin Queue, through which call device commands are
* sent.
*/
ena_adminq_t ena_aq;
ena_aenq_t ena_aenq;
ena_dma_buf_t ena_host_info;
/*
* Hardware 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;
/*
* LLQ (Low Latency Queue) state. When ena_llq_enabled is true,
* TX descriptors are written to device, rather than host, memory.
*/
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;
/* This is calculated from the Rx/Tx queue nums. */
uint16_t ena_max_io_queues;
/* Hardware Offloads */
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;
/*
* Misc
*/
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 *);
/*
* Logging functions.
*/
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);
/*
* Hardware access.
*/
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
/*
* Watchdog
*/
extern void ena_enable_watchdog(ena_t *);
extern void ena_disable_watchdog(ena_t *);
/*
* Stats
*/
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 *);
/*
* DMA
*/
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 *);
/*
* Interrupts
*/
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 *);
/*
* MAC
*/
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 *);
/*
* Admin API
*/
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);
/*
* Async event queue
*/
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 *);
/*
* Rx/Tx allocations
*/
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 /* _ENA_H */
|