summaryrefslogtreecommitdiff
path: root/roms/ipxe/src/drivers/infiniband/hermon.h
blob: e0b028f263e86cca2ab040dadccdf8a1e78dd0a8 (plain)
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
#ifndef _HERMON_H
#define _HERMON_H

/** @file
 *
 * Mellanox Hermon Infiniband HCA driver
 *
 */

FILE_LICENCE ( GPL2_OR_LATER );

#include <stdint.h>
#include <ipxe/uaccess.h>
#include <ipxe/ib_packet.h>
#include <ipxe/bofm.h>
#include <ipxe/nvsvpd.h>
#include <ipxe/nvo.h>
#include "mlx_bitops.h"
#include "MT25408_PRM.h"

/*
 * Hardware constants
 *
 */

/* Ports in existence */
#define HERMON_MAX_PORTS		2
#define HERMON_PORT_BASE		1

/* PCI BARs */
#define HERMON_PCI_CONFIG_BAR		PCI_BASE_ADDRESS_0
#define HERMON_PCI_CONFIG_BAR_SIZE	0x100000
#define HERMON_PCI_UAR_BAR		PCI_BASE_ADDRESS_2

/* Device reset */
#define HERMON_RESET_OFFSET		0x0f0010
#define HERMON_RESET_MAGIC		0x01000000UL
#define HERMON_RESET_WAIT_TIME_MS	1000

/* Work queue entry and completion queue entry opcodes */
#define HERMON_OPCODE_NOP		0x00
#define HERMON_OPCODE_SEND		0x0a
#define HERMON_OPCODE_RECV_ERROR	0xfe
#define HERMON_OPCODE_SEND_ERROR	0xff

/* HCA command register opcodes */
#define HERMON_HCR_QUERY_DEV_CAP	0x0003
#define HERMON_HCR_QUERY_FW		0x0004
#define HERMON_HCR_INIT_HCA		0x0007
#define HERMON_HCR_CLOSE_HCA		0x0008
#define HERMON_HCR_INIT_PORT		0x0009
#define HERMON_HCR_CLOSE_PORT		0x000a
#define HERMON_HCR_SET_PORT		0x000c
#define HERMON_HCR_SW2HW_MPT		0x000d
#define HERMON_HCR_WRITE_MTT		0x0011
#define HERMON_HCR_MAP_EQ		0x0012
#define HERMON_HCR_SW2HW_EQ		0x0013
#define HERMON_HCR_HW2SW_EQ		0x0014
#define HERMON_HCR_QUERY_EQ		0x0015
#define HERMON_HCR_SW2HW_CQ		0x0016
#define HERMON_HCR_HW2SW_CQ		0x0017
#define HERMON_HCR_QUERY_CQ		0x0018
#define HERMON_HCR_RST2INIT_QP		0x0019
#define HERMON_HCR_INIT2RTR_QP		0x001a
#define HERMON_HCR_RTR2RTS_QP		0x001b
#define HERMON_HCR_RTS2RTS_QP		0x001c
#define HERMON_HCR_2RST_QP		0x0021
#define HERMON_HCR_QUERY_QP		0x0022
#define HERMON_HCR_CONF_SPECIAL_QP	0x0023
#define HERMON_HCR_MAD_IFC		0x0024
#define HERMON_HCR_READ_MCG		0x0025
#define HERMON_HCR_WRITE_MCG		0x0026
#define HERMON_HCR_MGID_HASH		0x0027
#define HERMON_HCR_MOD_STAT_CFG		0x0034
#define HERMON_HCR_QUERY_PORT		0x0043
#define HERMON_HCR_SENSE_PORT		0x004d
#define HERMON_HCR_RUN_FW		0x0ff6
#define HERMON_HCR_DISABLE_LAM		0x0ff7
#define HERMON_HCR_ENABLE_LAM		0x0ff8
#define HERMON_HCR_UNMAP_ICM		0x0ff9
#define HERMON_HCR_MAP_ICM		0x0ffa
#define HERMON_HCR_UNMAP_ICM_AUX	0x0ffb
#define HERMON_HCR_MAP_ICM_AUX		0x0ffc
#define HERMON_HCR_SET_ICM_SIZE		0x0ffd
#define HERMON_HCR_UNMAP_FA		0x0ffe
#define HERMON_HCR_MAP_FA		0x0fff

/* Service types */
#define HERMON_ST_RC			0x00
#define HERMON_ST_UD			0x03
#define HERMON_ST_MLX			0x07

/* Port types */
#define HERMON_PORT_TYPE_UNKNOWN	0
#define HERMON_PORT_TYPE_IB		1
#define HERMON_PORT_TYPE_ETH		2

/* MTUs */
#define HERMON_MTU_2048			0x04
#define HERMON_MTU_ETH			0x07

#define HERMON_INVALID_LKEY		0x00000100UL

#define HERMON_PAGE_SIZE		( ( size_t ) 4096 )

#define HERMON_DB_POST_SND_OFFSET	0x14
#define HERMON_DB_EQ_OFFSET(_eqn)	\
	( 0x800 + HERMON_PAGE_SIZE * ( (_eqn) / 4 ) + 0x08 * ( (_eqn) % 4 ) )

#define HERMON_QP_OPT_PARAM_PM_STATE	0x00000400UL
#define HERMON_QP_OPT_PARAM_QKEY	0x00000020UL
#define HERMON_QP_OPT_PARAM_ALT_PATH	0x00000001UL

#define HERMON_MAP_EQ			( 0UL << 31 )
#define HERMON_UNMAP_EQ			( 1UL << 31 )

#define HERMON_SET_PORT_GENERAL_PARAM	0x0000
#define HERMON_SET_PORT_RECEIVE_QP	0x0100
#define HERMON_SET_PORT_MAC_TABLE	0x0200
#define HERMON_SET_PORT_VLAN_TABLE	0x0300
#define HERMON_SET_PORT_PRIORITY_TABLE	0x0400
#define HERMON_SET_PORT_GID_TABLE	0x0500

#define HERMON_EV_PORT_STATE_CHANGE	0x09

#define HERMON_SCHED_QP0		0x3f
#define HERMON_SCHED_DEFAULT		0x83

#define HERMON_LOG_MULTICAST_HASH_SIZE	7

#define HERMON_PM_STATE_ARMED		0x00
#define HERMON_PM_STATE_REARM		0x01
#define HERMON_PM_STATE_MIGRATED	0x03

#define HERMON_RETRY_MAX		0x07

#define HERMON_MOD_STAT_CFG_SET		0x01
#define HERMON_MOD_STAT_CFG_QUERY	0x03

#define HERMON_VPD_FIELD( port ) \
	PCI_VPD_FIELD ( PCI_VPD_TAG_RW, 'V', ( '5' + (port) - 1 ) )

/*
 * Datatypes that seem to be missing from the autogenerated documentation
 *
 */
struct hermonprm_mgm_hash_st {
	pseudo_bit_t reserved0[0x00020];
/* -------------- */
	pseudo_bit_t hash[0x00010];
	pseudo_bit_t reserved1[0x00010];
} __attribute__ (( packed ));

struct hermonprm_mcg_entry_st {
	struct hermonprm_mcg_hdr_st hdr;
	struct hermonprm_mcg_qp_dw_st qp[8];
} __attribute__ (( packed ));

struct hermonprm_cq_db_record_st {
	pseudo_bit_t update_ci[0x00018];
	pseudo_bit_t reserved0[0x00008];
/* -------------- */
	pseudo_bit_t arm_ci[0x00018];
	pseudo_bit_t cmd[0x00003];
	pseudo_bit_t reserved1[0x00001];
	pseudo_bit_t cmd_sn[0x00002];
	pseudo_bit_t reserved2[0x00002];
} __attribute__ (( packed ));

struct hermonprm_send_db_register_st {
	pseudo_bit_t reserved[0x00008];
	pseudo_bit_t qn[0x00018];
} __attribute__ (( packed ));

struct hermonprm_event_db_register_st {
	pseudo_bit_t ci[0x00018];
	pseudo_bit_t reserver[0x00007];
	pseudo_bit_t a[0x00001];
} __attribute__ (( packed ));

struct hermonprm_scalar_parameter_st {
	pseudo_bit_t value_hi[0x00020];
/* -------------- */
	pseudo_bit_t value[0x00020];
} __attribute__ (( packed ));

struct hermonprm_event_mask_st {
	pseudo_bit_t reserved0[0x00020];
/* -------------- */
	pseudo_bit_t completion[0x00001];
	pseudo_bit_t path_migration_succeeded[0x00001];
	pseudo_bit_t communication_established[0x00001];
	pseudo_bit_t send_queue_drained[0x00001];
	pseudo_bit_t cq_error[0x00001];
	pseudo_bit_t wq_catastrophe[0x00001];
	pseudo_bit_t qpc_catastrophe[0x00001];
	pseudo_bit_t path_migration_failed[0x00001];
	pseudo_bit_t internal_error[0x00001];
	pseudo_bit_t port_state_change[0x00001];
	pseudo_bit_t command_done[0x00001];
	pseudo_bit_t fexch_error[0x00001];
	pseudo_bit_t reserved1[0x00004];
	pseudo_bit_t wq_invalid_request[0x00001];
	pseudo_bit_t wq_access_violation[0x00001];
	pseudo_bit_t srq_catastrophe[0x00001];
	pseudo_bit_t srq_last_wqe[0x00001];
	pseudo_bit_t srq_rq_limit[0x00001];
	pseudo_bit_t gpio[0x00001];
	pseudo_bit_t clientreregister[0x00001];
	pseudo_bit_t reserved2[0x00009];
} __attribute__ (( packed ));

struct hermonprm_port_state_change_event_st {
	pseudo_bit_t reserved[0x00020];
/* -------------- */
	struct hermonprm_port_state_change_st data;
} __attribute__ (( packed ));

struct hermonprm_sense_port_st {
	pseudo_bit_t reserved0[0x00020];
/* -------------- */
	pseudo_bit_t port_type[0x00002];
	pseudo_bit_t reserved1[0x0001e];
} __attribute__ (( packed ));

struct hermonprm_set_port_ib_st {
	pseudo_bit_t rqk[0x00001];
	pseudo_bit_t rcm[0x00001];
	pseudo_bit_t reserved0[0x00002];
	pseudo_bit_t vl_cap[0x00004];
	pseudo_bit_t reserved1[0x00004];
	pseudo_bit_t mtu_cap[0x00004];
	pseudo_bit_t g0[0x00001];
	pseudo_bit_t ng[0x00001];
	pseudo_bit_t sig[0x00001];
	pseudo_bit_t mg[0x00001];
	pseudo_bit_t mp[0x00001];
	pseudo_bit_t mvc[0x00001];
	pseudo_bit_t mmc[0x00001];
	pseudo_bit_t reserved2[0x00004];
	pseudo_bit_t lws[0x00001];
	pseudo_bit_t lss[0x00001];
	pseudo_bit_t reserved3[0x00003];
/* -------------- */
	pseudo_bit_t capability_mask[0x00020];
/* -------------- */
	pseudo_bit_t system_image_guid_h[0x00020];
/* -------------- */
	pseudo_bit_t system_image_guid_l[0x00020];
/* -------------- */
	pseudo_bit_t guid0_h[0x00020];
/* -------------- */
	pseudo_bit_t guid0_l[0x00020];
/* -------------- */
	pseudo_bit_t node_guid_h[0x00020];
/* -------------- */
	pseudo_bit_t node_guid_l[0x00020];
/* -------------- */
	pseudo_bit_t egress_sniff_qpn[0x00018];
	pseudo_bit_t egress_sniff_mode[0x00002];
	pseudo_bit_t reserved4[0x00006];
/* -------------- */
	pseudo_bit_t ingress_sniff_qpn[0x00018];
	pseudo_bit_t ingress_sniff_mode[0x00002];
	pseudo_bit_t reserved5[0x00006];
/* -------------- */
	pseudo_bit_t max_gid[0x00010];
	pseudo_bit_t max_pkey[0x00010];
/* -------------- */
	pseudo_bit_t reserved6[0x00020];
/* -------------- */
	pseudo_bit_t reserved7[0x00020];
/* -------------- */
	pseudo_bit_t reserved8[0x00020];
/* -------------- */
	pseudo_bit_t reserved9[0x00020];
/* -------------- */
	pseudo_bit_t reserved10[0x00020];
/* -------------- */
	pseudo_bit_t reserved11[0x00020];
/* -------------- */
	pseudo_bit_t reserved12[0x00020];
/* -------------- */
	pseudo_bit_t reserved13[0x00020];
/* -------------- */
	pseudo_bit_t reserved14[0x00020];
/* -------------- */
	pseudo_bit_t reserved15[0x00020];
/* -------------- */
	pseudo_bit_t reserved16[0x00020];
/* -------------- */
	pseudo_bit_t reserved17[0x00020];
/* -------------- */
	pseudo_bit_t reserved18[0x00020];
/* -------------- */
	pseudo_bit_t reserved19[0x00020];
/* -------------- */
	pseudo_bit_t reserved20[0x00020];
/* -------------- */
	pseudo_bit_t reserved21[0x00020];
/* -------------- */
	pseudo_bit_t reserved22[0x00020];
/* -------------- */
	pseudo_bit_t link_width_supported[0x00004];
	pseudo_bit_t link_speed_supported[0x00004];
	pseudo_bit_t reserved23[0x00018];
/* -------------- */
} __attribute__ (( packed ));

struct hermonprm_query_port_cap_st {
	pseudo_bit_t eth_mtu[0x00010];
	pseudo_bit_t ib_mtu[0x00004];
	pseudo_bit_t reserved0[0x00004];
	pseudo_bit_t ib[0x00001];
	pseudo_bit_t eth[0x00001];
	pseudo_bit_t reserved1[0x00005];
	pseudo_bit_t link_state[0x00001];
/* -------------- */
	pseudo_bit_t log_max_pkey[0x00004];
	pseudo_bit_t log_max_gid[0x00004];
	pseudo_bit_t ib_port_width[0x00004];
	pseudo_bit_t reserved2[0x00004];
	pseudo_bit_t eth_link_speed[0x00004];
	pseudo_bit_t reserved3[0x00004];
	pseudo_bit_t ib_link_speed[0x00004];
	pseudo_bit_t reserved4[0x00004];
/* -------------- */
	pseudo_bit_t max_vl_ib[0x00004];
	pseudo_bit_t reserved5[0x00004];
	pseudo_bit_t log_max_mac[0x00004];
	pseudo_bit_t log_max_vlan[0x00004];
	pseudo_bit_t reserved6[0x00010];
/* -------------- */
	pseudo_bit_t reserved7[0x00020];
/* -------------- */
	pseudo_bit_t mac_47_32[0x00010];
	pseudo_bit_t reserved8[0x00010];
/* -------------- */
	pseudo_bit_t mac_31_0[0x00020];
/* -------------- */
	pseudo_bit_t vendor_oui[0x00018];
	pseudo_bit_t transceiver_type[0x00008];
/* -------------- */
	pseudo_bit_t reserved9[0x00010];
	pseudo_bit_t wavelength[0x00010];
/* -------------- */
	pseudo_bit_t transceiver_code_hi[0x00020];
/* -------------- */
	pseudo_bit_t transceiver_code_lo[0x00020];
/* -------------- */
	pseudo_bit_t reserved10[0x000c0];
} __attribute__ (( packed ));

struct hermonprm_set_port_general_context_st {
	pseudo_bit_t v_mtu[0x00001];
	pseudo_bit_t v_pprx[0x00001];
	pseudo_bit_t v_pptx[0x00001];
	pseudo_bit_t reserved0[0x0001d];
/* -------------- */
	pseudo_bit_t mtu[0x00010];
	pseudo_bit_t reserved1[0x00010];
/* -------------- */
	pseudo_bit_t reserved2[0x00010];
	pseudo_bit_t pfctx[0x00008];
	pseudo_bit_t reserved3[0x00007];
	pseudo_bit_t pptx[0x00001];
/* -------------- */
	pseudo_bit_t reserved4[0x00010];
	pseudo_bit_t pfcrx[0x00008];
	pseudo_bit_t reserved5[0x00007];
	pseudo_bit_t pprx[0x00001];
/* -------------- */
} __attribute__ (( packed ));

struct hermonprm_set_port_rqp_calc_st {
	pseudo_bit_t base_qpn[0x00018];
	pseudo_bit_t reserved0[0x00008];
/* -------------- */
	pseudo_bit_t n_p[0x00002];
	pseudo_bit_t reserved1[0x00006];
	pseudo_bit_t n_v[0x00003];
	pseudo_bit_t reserved2[0x00005];
	pseudo_bit_t n_m[0x00004];
	pseudo_bit_t reserved3[0x0000c];
/* -------------- */
	pseudo_bit_t mac_miss_index[0x00008];
	pseudo_bit_t reserved4[0x00018];
/* -------------- */
	pseudo_bit_t vlan_miss_index[0x00007];
	pseudo_bit_t reserved5[0x00008];
	pseudo_bit_t intra_miss[0x00001];
	pseudo_bit_t no_vlan_index[0x00007];
	pseudo_bit_t reserved6[0x00008];
	pseudo_bit_t intra_no_vlan[0x00001];
/* -------------- */
	pseudo_bit_t no_vlan_prio[0x00003];
	pseudo_bit_t reserved7[0x0001d];
/* -------------- */
	pseudo_bit_t promisc_qpn[0x00018];
	pseudo_bit_t reserved8[0x00007];
	pseudo_bit_t en_uc_promisc[0x00001];
/* -------------- */
	pseudo_bit_t def_mcast_qpn[0x00018];
	pseudo_bit_t reserved9[0x00005];
	pseudo_bit_t mc_by_vlan[0x00001];
	pseudo_bit_t mc_promisc_mode[0x00002];
/* -------------- */
	pseudo_bit_t reserved10[0x00020];
/* -------------- */
} __attribute__ (( packed ));

struct hermonprm_set_port_mac_table_st {
	pseudo_bit_t mac_h[0x00010];
	pseudo_bit_t reserved0[0x0000f];
	pseudo_bit_t v[0x00001];
/* -------------- */
	pseudo_bit_t mac_l[0x00020];
/* -------------- */
} __attribute__ (( packed ));

struct hermonprm_set_port_vlan_st {
	pseudo_bit_t vlan_id[0x0000c];
	pseudo_bit_t reserved0[0x00012];
	pseudo_bit_t intra[0x00001];
	pseudo_bit_t v[0x00001];
/* -------------- */
} __attribute__ (( packed ));

struct hermonprm_mod_stat_cfg_input_mod_st {
	pseudo_bit_t offset[0x00008];
	pseudo_bit_t portnum[0x00008];
	pseudo_bit_t xnum[0x00004];
	pseudo_bit_t linkspeed[0x00003];
	pseudo_bit_t autoneg[0x00001];
	pseudo_bit_t reserved[0x00004];
	pseudo_bit_t setup_mode[0x00004];
} __attribute__ (( packed ));

/*
 * Wrapper structures for hardware datatypes
 *
 */

struct MLX_DECLARE_STRUCT ( hermonprm_completion_queue_context );
struct MLX_DECLARE_STRUCT ( hermonprm_completion_queue_entry );
struct MLX_DECLARE_STRUCT ( hermonprm_completion_with_error );
struct MLX_DECLARE_STRUCT ( hermonprm_cq_db_record );
struct MLX_DECLARE_STRUCT ( hermonprm_eqc );
struct MLX_DECLARE_STRUCT ( hermonprm_event_db_register );
struct MLX_DECLARE_STRUCT ( hermonprm_event_mask );
struct MLX_DECLARE_STRUCT ( hermonprm_event_queue_entry );
struct MLX_DECLARE_STRUCT ( hermonprm_hca_command_register );
struct MLX_DECLARE_STRUCT ( hermonprm_init_hca );
struct MLX_DECLARE_STRUCT ( hermonprm_mad_ifc );
struct MLX_DECLARE_STRUCT ( hermonprm_mcg_entry );
struct MLX_DECLARE_STRUCT ( hermonprm_mgm_hash );
struct MLX_DECLARE_STRUCT ( hermonprm_mod_stat_cfg );
struct MLX_DECLARE_STRUCT ( hermonprm_mod_stat_cfg_input_mod );
struct MLX_DECLARE_STRUCT ( hermonprm_mpt );
struct MLX_DECLARE_STRUCT ( hermonprm_mtt );
struct MLX_DECLARE_STRUCT ( hermonprm_port_state_change_event );
struct MLX_DECLARE_STRUCT ( hermonprm_qp_db_record );
struct MLX_DECLARE_STRUCT ( hermonprm_qp_ee_state_transitions );
struct MLX_DECLARE_STRUCT ( hermonprm_query_dev_cap );
struct MLX_DECLARE_STRUCT ( hermonprm_query_fw );
struct MLX_DECLARE_STRUCT ( hermonprm_query_port_cap );
struct MLX_DECLARE_STRUCT ( hermonprm_queue_pair_ee_context_entry );
struct MLX_DECLARE_STRUCT ( hermonprm_scalar_parameter );
struct MLX_DECLARE_STRUCT ( hermonprm_sense_port );
struct MLX_DECLARE_STRUCT ( hermonprm_send_db_register );
struct MLX_DECLARE_STRUCT ( hermonprm_set_port_ib );
struct MLX_DECLARE_STRUCT ( hermonprm_set_port_general_context );
struct MLX_DECLARE_STRUCT ( hermonprm_set_port_mac_table );
struct MLX_DECLARE_STRUCT ( hermonprm_set_port_rqp_calc );
struct MLX_DECLARE_STRUCT ( hermonprm_set_port_vlan );
struct MLX_DECLARE_STRUCT ( hermonprm_ud_address_vector );
struct MLX_DECLARE_STRUCT ( hermonprm_virtual_physical_mapping );
struct MLX_DECLARE_STRUCT ( hermonprm_wqe_segment_ctrl_mlx );
struct MLX_DECLARE_STRUCT ( hermonprm_wqe_segment_ctrl_send );
struct MLX_DECLARE_STRUCT ( hermonprm_wqe_segment_data_ptr );
struct MLX_DECLARE_STRUCT ( hermonprm_wqe_segment_ud );

/*
 * Composite hardware datatypes
 *
 */

struct hermonprm_write_mtt {
	struct hermonprm_scalar_parameter mtt_base_addr;
	struct hermonprm_scalar_parameter reserved;
	struct hermonprm_mtt mtt;
} __attribute__ (( packed ));

#define HERMON_MAX_GATHER 2

struct hermonprm_ud_send_wqe {
	struct hermonprm_wqe_segment_ctrl_send ctrl;
	struct hermonprm_wqe_segment_ud ud;
	struct hermonprm_wqe_segment_data_ptr data[HERMON_MAX_GATHER];
} __attribute__ (( packed ));

struct hermonprm_mlx_send_wqe {
	struct hermonprm_wqe_segment_ctrl_mlx ctrl;
	struct hermonprm_wqe_segment_data_ptr data[HERMON_MAX_GATHER];
	uint8_t headers[IB_MAX_HEADER_SIZE];
} __attribute__ (( packed ));

struct hermonprm_rc_send_wqe {
	struct hermonprm_wqe_segment_ctrl_send ctrl;
	struct hermonprm_wqe_segment_data_ptr data[HERMON_MAX_GATHER];
} __attribute__ (( packed ));

struct hermonprm_eth_send_wqe {
	struct hermonprm_wqe_segment_ctrl_send ctrl;
	struct hermonprm_wqe_segment_data_ptr data[HERMON_MAX_GATHER];
} __attribute__ (( packed ));

#define HERMON_MAX_SCATTER 1

struct hermonprm_recv_wqe {
	struct hermonprm_wqe_segment_data_ptr data[HERMON_MAX_SCATTER];
} __attribute__ (( packed ));

union hermonprm_completion_entry {
	struct hermonprm_completion_queue_entry normal;
	struct hermonprm_completion_with_error error;
} __attribute__ (( packed ));

union hermonprm_event_entry {
	struct hermonprm_event_queue_entry generic;
	struct hermonprm_port_state_change_event port_state_change;
} __attribute__ (( packed ));

union hermonprm_doorbell_register {
	struct hermonprm_send_db_register send;
	struct hermonprm_event_db_register event;
	uint32_t dword[1];
} __attribute__ (( packed ));

union hermonprm_mad {
	struct hermonprm_mad_ifc ifc;
	union ib_mad mad;
} __attribute__ (( packed ));

union hermonprm_set_port {
	struct hermonprm_set_port_ib ib;
	struct hermonprm_set_port_general_context general;
	struct hermonprm_set_port_rqp_calc rqp_calc;
	struct hermonprm_set_port_mac_table mac_table[128];
	struct hermonprm_set_port_vlan vlan;
} __attribute__ (( packed ));

/*
 * iPXE-specific definitions
 *
 */

/** Hermon device capabilitiess */
struct hermon_dev_cap {
	/** CMPT entry size */
	size_t cmpt_entry_size;
	/** Number of reserved QPs */
	unsigned int reserved_qps;
	/** QP context entry size */
	size_t qpc_entry_size;
	/** Alternate path context entry size */
	size_t altc_entry_size;
	/** Auxiliary context entry size */
	size_t auxc_entry_size;
	/** Number of reserved SRQs */
	unsigned int reserved_srqs;
	/** SRQ context entry size */
	size_t srqc_entry_size;
	/** Number of reserved CQs */
	unsigned int reserved_cqs;
	/** CQ context entry size */
	size_t cqc_entry_size;
	/** Number of reserved EQs */
	unsigned int reserved_eqs;
	/** EQ context entry size */
	size_t eqc_entry_size;
	/** Number of reserved MTTs */
	unsigned int reserved_mtts;
	/** MTT entry size */
	size_t mtt_entry_size;
	/** Number of reserved MRWs */
	unsigned int reserved_mrws;
	/** DMPT entry size */
	size_t dmpt_entry_size;
	/** Number of reserved UARs */
	unsigned int reserved_uars;
	/** Number of ports */
	unsigned int num_ports;
	/** Dual-port different protocol */
	int dpdp;
};

/** Number of cMPT entries of each type */
#define HERMON_CMPT_MAX_ENTRIES ( 1 << 24 )

/** Hermon ICM memory map entry */
struct hermon_icm_map {
	/** Offset (virtual address within ICM) */
	uint64_t offset;
	/** Length */
	size_t len;
};

/** Discontiguous regions within Hermon ICM */
enum hermon_icm_map_regions {
	HERMON_ICM_QP_CMPT = 0,
	HERMON_ICM_SRQ_CMPT,
	HERMON_ICM_CQ_CMPT,
	HERMON_ICM_EQ_CMPT,
	HERMON_ICM_OTHER,
	HERMON_ICM_NUM_REGIONS
};

/** UAR page for doorbell accesses
 *
 * Pages 0-127 are reserved for event queue doorbells only, so we use
 * page 128.
 */
#define HERMON_UAR_NON_EQ_PAGE	128

/** Maximum number of allocatable MTT entries
 *
 * This is a policy decision, not a device limit.
 */
#define HERMON_MAX_MTTS		64

/** A Hermon MTT descriptor */
struct hermon_mtt {
	/** MTT offset */
	unsigned int mtt_offset;
	/** Number of pages */
	unsigned int num_pages;
	/** MTT base address */
	unsigned int mtt_base_addr;
	/** Offset within page */
	unsigned int page_offset;
};

/** Alignment of Hermon send work queue entries */
#define HERMON_SEND_WQE_ALIGN 128

/** A Hermon send work queue entry */
union hermon_send_wqe {
	struct hermonprm_wqe_segment_ctrl_send ctrl;
	struct hermonprm_ud_send_wqe ud;
	struct hermonprm_mlx_send_wqe mlx;
	struct hermonprm_rc_send_wqe rc;
	struct hermonprm_eth_send_wqe eth;
	uint8_t force_align[HERMON_SEND_WQE_ALIGN];
} __attribute__ (( packed ));

/** A Hermon send work queue */
struct hermon_send_work_queue {
	/** Number of work queue entries, including headroom
	 *
	 * Hermon requires us to leave unused space within the send
	 * WQ, so we create a send WQ with more entries than are
	 * requested in the create_qp() call.
	 */
	unsigned int num_wqes;
	/** Work queue entries */
	union hermon_send_wqe *wqe;
	/** Size of work queue */
	size_t wqe_size;
	/** Doorbell register */
	void *doorbell;
};

/** Alignment of Hermon receive work queue entries */
#define HERMON_RECV_WQE_ALIGN 16

/** A Hermon receive work queue entry */
union hermon_recv_wqe {
	struct hermonprm_recv_wqe recv;
	uint8_t force_align[HERMON_RECV_WQE_ALIGN];
} __attribute__ (( packed ));

/** A Hermon receive work queue */
struct hermon_recv_work_queue {
	/** Work queue entries */
	union hermon_recv_wqe *wqe;
	/** Size of work queue */
	size_t wqe_size;
	/** Doorbell record */
	struct hermonprm_qp_db_record *doorbell;
};

/** Number of special queue pairs */
#define HERMON_NUM_SPECIAL_QPS 8

/** Number of queue pairs reserved for the "special QP" block
 *
 * The special QPs must be within a contiguous block aligned on its
 * own size.
 */
#define HERMON_RSVD_SPECIAL_QPS	( ( HERMON_NUM_SPECIAL_QPS << 1 ) - 1 )

/** Maximum number of allocatable queue pairs
 *
 * This is a policy decision, not a device limit.
 */
#define HERMON_MAX_QPS		8

/** Queue pair number randomisation mask */
#define HERMON_QPN_RANDOM_MASK 0xfff000

/** Hermon queue pair state */
enum hermon_queue_pair_state {
	HERMON_QP_ST_RST = 0,
	HERMON_QP_ST_INIT,
	HERMON_QP_ST_RTR,
	HERMON_QP_ST_RTS,
};

/** A Hermon queue pair */
struct hermon_queue_pair {
	/** Work queue buffer */
	void *wqe;
	/** Size of work queue buffer */
	size_t wqe_size;
	/** MTT descriptor */
	struct hermon_mtt mtt;
	/** Send work queue */
	struct hermon_send_work_queue send;
	/** Receive work queue */
	struct hermon_recv_work_queue recv;
	/** Queue state */
	enum hermon_queue_pair_state state;
};

/** Maximum number of allocatable completion queues
 *
 * This is a policy decision, not a device limit.
 */
#define HERMON_MAX_CQS		8

/** A Hermon completion queue */
struct hermon_completion_queue {
	/** Completion queue entries */
	union hermonprm_completion_entry *cqe;
	/** Size of completion queue */
	size_t cqe_size;
	/** MTT descriptor */
	struct hermon_mtt mtt;
	/** Doorbell record */
	struct hermonprm_cq_db_record *doorbell;
};

/** Maximum number of allocatable event queues
 *
 * This is a policy decision, not a device limit.
 */
#define HERMON_MAX_EQS		8

/** A Hermon event queue */
struct hermon_event_queue {
	/** Event queue entries */
	union hermonprm_event_entry *eqe;
	/** Size of event queue */
	size_t eqe_size;
	/** MTT descriptor */
	struct hermon_mtt mtt;
	/** Event queue number */
	unsigned long eqn;
	/** Next event queue entry index */
	unsigned long next_idx;
	/** Doorbell register */
	void *doorbell;
};

/** Number of event queue entries
 *
 * This is a policy decision.
 */
#define HERMON_NUM_EQES		8

/** A Hermon resource bitmask */
typedef uint32_t hermon_bitmask_t;

/** Size of a hermon resource bitmask */
#define HERMON_BITMASK_SIZE(max_entries)				     \
	( ( (max_entries) + ( 8 * sizeof ( hermon_bitmask_t ) ) - 1 ) /	     \
	  ( 8 * sizeof ( hermon_bitmask_t ) ) )

struct hermon;
struct hermon_port;

/** A Hermon port type */
struct hermon_port_type {
	/** Register port
	 *
	 * @v hermon		Hermon device
	 * @v port		Hermon port
	 * @ret rc		Return status code
	 */
	int ( * register_dev ) ( struct hermon *hermon,
				 struct hermon_port *port );
	/** Port state changed
	 *
	 * @v hermon		Hermon device
	 * @v port		Hermon port
	 * @v link_up		Link is up
	 */
	void ( * state_change ) ( struct hermon *hermon,
				  struct hermon_port *port,
				  int link_up );
	/** Unregister port
	 *
	 * @v hermon		Hermon device
	 * @v port		Hermon port
	 */
	void ( * unregister_dev ) ( struct hermon *hermon,
				    struct hermon_port *port );
};

/** A Hermon port */
struct hermon_port {
	/** Infiniband device */
	struct ib_device *ibdev;
	/** Network device */
	struct net_device *netdev;
	/** Ethernet completion queue */
	struct ib_completion_queue *eth_cq;
	/** Ethernet queue pair */
	struct ib_queue_pair *eth_qp;
	/** Port type */
	struct hermon_port_type *type;
	/** Non-volatile option storage */
	struct nvo_block nvo;
};

/** A Hermon device */
struct hermon {
	/** PCI device */
	struct pci_device *pci;
	/** PCI configuration registers */
	void *config;
	/** PCI user Access Region */
	void *uar;

	/** Command toggle */
	unsigned int toggle;
	/** Command input mailbox */
	void *mailbox_in;
	/** Command output mailbox */
	void *mailbox_out;

	/** Device open request counter */
	unsigned int open_count;

	/** Firmware size */
	size_t firmware_len;
	/** Firmware area in external memory
	 *
	 * This is allocated when first needed, and freed only on
	 * final teardown, in order to avoid memory map changes at
	 * runtime.
	 */
	userptr_t firmware_area;
	/** ICM map */
	struct hermon_icm_map icm_map[HERMON_ICM_NUM_REGIONS];
	/** ICM size */
	size_t icm_len;
	/** ICM AUX size */
	size_t icm_aux_len;
	/** ICM area
	 *
	 * This is allocated when first needed, and freed only on
	 * final teardown, in order to avoid memory map changes at
	 * runtime.
	 */
	userptr_t icm;

	/** Event queue */
	struct hermon_event_queue eq;
	/** Unrestricted LKey
	 *
	 * Used to get unrestricted memory access.
	 */
	unsigned long lkey;

	/** Completion queue in-use bitmask */
	hermon_bitmask_t cq_inuse[ HERMON_BITMASK_SIZE ( HERMON_MAX_CQS ) ];
	/** Queue pair in-use bitmask */
	hermon_bitmask_t qp_inuse[ HERMON_BITMASK_SIZE ( HERMON_MAX_QPS ) ];
	/** MTT entry in-use bitmask */
	hermon_bitmask_t mtt_inuse[ HERMON_BITMASK_SIZE ( HERMON_MAX_MTTS ) ];

	/** Device capabilities */
	struct hermon_dev_cap cap;
	/** Special QPN base */
	unsigned long special_qpn_base;
	/** QPN base */
	unsigned long qpn_base;

	/** Non-volatile storage in PCI VPD */
	struct nvs_vpd_device nvsvpd;

	/** Ports */
	struct hermon_port port[HERMON_MAX_PORTS];

	/** BOFM device */
	struct bofm_device bofm;
};

/** Global protection domain */
#define HERMON_GLOBAL_PD		0x123456

/** Memory key prefix */
#define HERMON_MKEY_PREFIX		0x77000000UL

/*
 * HCA commands
 *
 */

#define HERMON_HCR_BASE			0x80680
#define HERMON_HCR_REG(x)		( HERMON_HCR_BASE + 4 * (x) )
#define HERMON_HCR_MAX_WAIT_MS		2000
#define HERMON_MBOX_ALIGN		4096
#define HERMON_MBOX_SIZE		1024

/* HCA command is split into
 *
 * bits  11:0	Opcode
 * bit     12	Input uses mailbox
 * bit     13	Output uses mailbox
 * bits 22:14	Input parameter length (in dwords)
 * bits 31:23	Output parameter length (in dwords)
 *
 * Encoding the information in this way allows us to cut out several
 * parameters to the hermon_command() call.
 */
#define HERMON_HCR_IN_MBOX		0x00001000UL
#define HERMON_HCR_OUT_MBOX		0x00002000UL
#define HERMON_HCR_OPCODE( _command )	( (_command) & 0xfff )
#define HERMON_HCR_IN_LEN( _command )	( ( (_command) >> 12 ) & 0x7fc )
#define HERMON_HCR_OUT_LEN( _command )	( ( (_command) >> 21 ) & 0x7fc )

/** Build HCR command from component parts */
#define HERMON_HCR_INOUT_CMD( _opcode, _in_mbox, _in_len,		     \
			     _out_mbox, _out_len )			     \
	( (_opcode) |							     \
	  ( (_in_mbox) ? HERMON_HCR_IN_MBOX : 0 ) |			     \
	  ( ( (_in_len) / 4 ) << 14 ) |					     \
	  ( (_out_mbox) ? HERMON_HCR_OUT_MBOX : 0 ) |			     \
	  ( ( (_out_len) / 4 ) << 23 ) )

#define HERMON_HCR_IN_CMD( _opcode, _in_mbox, _in_len )			     \
	HERMON_HCR_INOUT_CMD ( _opcode, _in_mbox, _in_len, 0, 0 )

#define HERMON_HCR_OUT_CMD( _opcode, _out_mbox, _out_len )		     \
	HERMON_HCR_INOUT_CMD ( _opcode, 0, 0, _out_mbox, _out_len )

#define HERMON_HCR_VOID_CMD( _opcode )					     \
	HERMON_HCR_INOUT_CMD ( _opcode, 0, 0, 0, 0 )

#endif /* _HERMON_H */