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
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _SYS_IB_ADAPTERS_HERMON_H
#define _SYS_IB_ADAPTERS_HERMON_H
/*
* hermon.h
* Contains the #defines and typedefs necessary for the Hermon softstate
* structure and for proper attach() and detach() processing. Also
* includes all the other Hermon header files (and so is the only header
* file that is directly included by the Hermon source files).
* Lastly, this file includes everything necessary for implementing the
* devmap interface and for maintaining the "mapped resource database".
*/
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/taskq.h>
#include <sys/atomic.h>
#ifdef FMA_TEST
#include <sys/modhash.h>
#endif
#include <sys/ib/ibtl/ibci.h>
#include <sys/ib/ibtl/impl/ibtl_util.h>
#include <sys/ib/adapters/mlnx_umap.h>
/*
* First include all the Hermon typedefs, then include all the other Hermon
* specific headers (many of which depend on the typedefs having already
* been defined).
*/
#include <sys/ib/adapters/hermon/hermon_typedef.h>
#include <sys/ib/adapters/hermon/hermon_hw.h>
#include <sys/ib/adapters/hermon/hermon_agents.h>
#include <sys/ib/adapters/hermon/hermon_cfg.h>
#include <sys/ib/adapters/hermon/hermon_cmd.h>
#include <sys/ib/adapters/hermon/hermon_cq.h>
#include <sys/ib/adapters/hermon/hermon_event.h>
#include <sys/ib/adapters/hermon/hermon_fcoib.h>
#include <sys/ib/adapters/hermon/hermon_ioctl.h>
#include <sys/ib/adapters/hermon/hermon_misc.h>
#include <sys/ib/adapters/hermon/hermon_mr.h>
#include <sys/ib/adapters/hermon/hermon_wr.h>
#include <sys/ib/adapters/hermon/hermon_qp.h>
#include <sys/ib/adapters/hermon/hermon_srq.h>
#include <sys/ib/adapters/hermon/hermon_rsrc.h>
#include <sys/ib/adapters/hermon/hermon_fm.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Number of initial states to setup. Used in call to ddi_soft_state_init()
*/
#define HERMON_INITIAL_STATES 3
/*
* Macro and defines used to calculate device instance number from minor
* number (and vice versa).
*/
#define HERMON_MINORNUM_SHIFT 3
#define HERMON_DEV_INSTANCE(dev) (getminor((dev)) & \
((1 << HERMON_MINORNUM_SHIFT) - 1))
/*
* Locations for the various Hermon hardware CMD,UAR & MSIx PCIe BARs
*/
#define HERMON_CMD_BAR 1 /* device config space */
#define HERMON_UAR_BAR 2 /* UAR Region */
#define HERMON_MSIX_BAR 3 /* MSI-X Table */
#define HERMON_ONCLOSE_FLASH_INPROGRESS (1 << 0)
#define HERMON_MSIX_MAX 256 /* max # of interrupt vectors */
/*
* VPD header size - or more rightfully, the area of interest for fwflash
* There's more, but we don't need it for our use so we don't read it
*/
#define HERMON_VPD_HDR_DWSIZE 0x10 /* 16 Dwords */
#define HERMON_VPD_HDR_BSIZE 0x40 /* 64 Bytes */
/*
* Offsets to be used w/ reset to save/restore PCI capability stuff
*/
#define HERMON_PCI_CAP_DEV_OFFS 0x08
#define HERMON_PCI_CAP_LNK_OFFS 0x10
/*
* Some defines for the software reset. These define the value that should
* be written to begin the reset (HERMON_SW_RESET_START), the delay before
* beginning to poll for completion (HERMON_SW_RESET_DELAY), the in-between
* polling delay (HERMON_SW_RESET_POLL_DELAY), and the value that indicates
* that the reset has not completed (HERMON_SW_RESET_NOTDONE).
*/
#define HERMON_SW_RESET_START 0x00000001
#define HERMON_SW_RESET_DELAY 1000000 /* 1000 ms, per 0.36 PRM */
#define HERMON_SW_RESET_POLL_DELAY 100 /* 100 us */
#define HERMON_SW_RESET_NOTDONE 0xFFFFFFFF
/*
* These defines are used in the Hermon software reset operation. They define
* the total number PCI registers to read/restore during the reset. And they
* also specify two config registers which should not be read or restored.
*/
#define HERMON_SW_RESET_NUMREGS 0x40
#define HERMON_SW_RESET_REG22_RSVD 0x16 /* 22 dec */
#define HERMON_SW_RESET_REG23_RSVD 0x17 /* 23 dec */
/*
* Macro used to output HCA warning messages. Note: HCA warning messages
* are only generated when an unexpected condition has been detected. This
* can be the result of a software bug or some other problem. Previously
* this was used for hardware errors, but those now use HERMON_FMANOTE
* instead, indicating that the driver state is more likely in an
* unpredictable state, and that shutdown/restart is suggested.
*
* HERMON_WARNING messages are not considered important enough to print
* to the console, just to the message log.
*/
#define HERMON_WARNING(state, string) \
cmn_err(CE_CONT, "!hermon%d: %s\n", (state)->hs_instance, string)
/*
* Macro used to set attach failure messages. Also, the attach message buf
* size is set here.
*/
#define HERMON_ATTACH_MSGSIZE 80
#define HERMON_ATTACH_MSG(attach_buf, attach_msg) \
(void) snprintf((attach_buf), HERMON_ATTACH_MSGSIZE, (attach_msg));
#define HERMON_ATTACH_MSG_INIT(attach_buf) \
(attach_buf)[0] = '\0';
/*
* Macros used for controlling whether or not event callbacks will be forwarded
* to the IBTF. This is necessary because there are certain race conditions
* that can occur (e.g. calling IBTF with an asynch event before the IBTF
* registration has successfully completed or handling an event after we've
* detached from the IBTF.)
*
* HERMON_ENABLE_IBTF_CALLB() initializes the "hs_ibtfpriv" field in the Hermon
* softstate. When "hs_ibtfpriv" is non-NULL, it is OK to forward asynch
* and CQ events to the IBTF.
*
* HERMON_DO_IBTF_ASYNC_CALLB() and HERMON_DO_IBTF_CQ_CALLB() both set and clear
* the "hs_in_evcallb" flag, as necessary, to indicate that an IBTF
* callback is currently in progress. This is necessary so that we can
* block on this condition in hermon_detach().
*
* HERMON_QUIESCE_IBTF_CALLB() is used in hermon_detach() to set the
* "hs_ibtfpriv" to NULL (thereby disabling any further IBTF callbacks)
* and to poll on the "hs_in_evcallb" flag. When this flag is zero, all
* IBTF callbacks have quiesced and it is safe to continue with detach
* (i.e. continue detaching from IBTF).
*/
#define HERMON_ENABLE_IBTF_CALLB(state, tmp_ibtfpriv) \
(state)->hs_ibtfpriv = (tmp_ibtfpriv);
#define HERMON_DO_IBTF_ASYNC_CALLB(state, type, event) \
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS((state)->hs_in_evcallb)) \
(state)->hs_in_evcallb = 1; \
ibc_async_handler((state)->hs_ibtfpriv, (type), (event)); \
(state)->hs_in_evcallb = 0;
#define HERMON_DO_IBTF_CQ_CALLB(state, cq) \
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS((state)->hs_in_evcallb)) \
(state)->hs_in_evcallb = 1; \
ibc_cq_handler((state)->hs_ibtfpriv, (cq)->cq_hdlrarg); \
(state)->hs_in_evcallb = 0;
#define HERMON_QUIESCE_IBTF_CALLB(state) \
{ \
uint_t count = 0; \
\
state->hs_ibtfpriv = NULL; \
while (((state)->hs_in_evcallb != 0) && \
(count++ < HERMON_QUIESCE_IBTF_CALLB_POLL_MAX)) { \
drv_usecwait(HERMON_QUIESCE_IBTF_CALLB_POLL_DELAY); \
} \
}
/*
* Defines used by the HERMON_QUIESCE_IBTF_CALLB() macro to determine the
* duration and number of times (at maximum) to poll while waiting for IBTF
* callbacks to quiesce.
*/
#define HERMON_QUIESCE_IBTF_CALLB_POLL_DELAY 1
#define HERMON_QUIESCE_IBTF_CALLB_POLL_MAX 1000000
/*
* Macros to retrieve PCI id's of the device
*/
#define HERMON_DDI_PROP_GET(dip, property) \
(ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, \
property, -1))
#define HERMON_GET_VENDOR_ID(dip) HERMON_DDI_PROP_GET(dip, "vendor-id")
#define HERMON_GET_DEVICE_ID(dip) HERMON_DDI_PROP_GET(dip, "device-id")
#define HERMON_GET_REVISION_ID(dip) HERMON_DDI_PROP_GET(dip, "revision-id")
/*
* Defines used to record the device mode to which Hermon driver has been
* attached. HERMON_MAINTENANCE_MODE is used when the device has
* come up in the "maintenance mode". In this mode, no InfiniBand interfaces
* are enabled, but the device's firmware can be updated/flashed (and
* test/debug interfaces should be useable).
* HERMON_HCA_MODE isused when the device has come up in the
* normal HCA mode. In this mode, all necessary InfiniBand interfaces are
* enabled (and, if necessary, HERMON firmware can be updated/flashed).
*/
#define HERMON_MAINTENANCE_MODE 1
#define HERMON_HCA_MODE 2
/*
* Used to determine if the device is operational, or not in maintenance mode.
* This means either the driver has attached successfully against an hermon
* device in hermon compatibility mode, or against a hermon device in full HCA
* mode.
*/
#define HERMON_IS_OPERATIONAL(mode) \
(mode == HERMON_HCA_MODE)
/*
* The following define is used (in hermon_umap_db_set_onclose_cb()) to
* indicate that a cleanup callback is needed to undo initialization done
* by the firmware flash burn code.
*/
#define HERMON_ONCLOSE_FLASH_INPROGRESS (1 << 0)
/*
* The following enumerated type and structures are used during driver
* initialization. Note: The HERMON_DRV_CLEANUP_ALL type is used as a marker
* for end of the cleanup steps. No cleanup steps should be added after
* HERMON_DRV_CLEANUP_ALL. Any addition steps should be added before it.
*/
typedef enum {
HERMON_DRV_CLEANUP_LEVEL0,
HERMON_DRV_CLEANUP_LEVEL1,
HERMON_DRV_CLEANUP_LEVEL2,
HERMON_DRV_CLEANUP_LEVEL3,
HERMON_DRV_CLEANUP_LEVEL4,
HERMON_DRV_CLEANUP_LEVEL5,
HERMON_DRV_CLEANUP_LEVEL6,
HERMON_DRV_CLEANUP_LEVEL7,
HERMON_DRV_CLEANUP_LEVEL8,
HERMON_DRV_CLEANUP_LEVEL9,
HERMON_DRV_CLEANUP_LEVEL10,
HERMON_DRV_CLEANUP_LEVEL11,
HERMON_DRV_CLEANUP_LEVEL12,
HERMON_DRV_CLEANUP_LEVEL13,
HERMON_DRV_CLEANUP_LEVEL14,
HERMON_DRV_CLEANUP_LEVEL15,
HERMON_DRV_CLEANUP_LEVEL16,
HERMON_DRV_CLEANUP_LEVEL17,
HERMON_DRV_CLEANUP_LEVEL18,
HERMON_DRV_CLEANUP_LEVEL19,
/* No more driver cleanup steps below this point! */
HERMON_DRV_CLEANUP_ALL
} hermon_drv_cleanup_level_t;
/*
* The hermon_dma_info_t structure is used to store information related to
* the various ICM resources' DMA allocations. The related ICM table and
* virtual address are stored here. The DMA and Access handles are stored
* here. Also, the allocation length and virtual (host) address.
*/
struct hermon_dma_info_s {
ddi_dma_handle_t dma_hdl;
ddi_acc_handle_t acc_hdl;
uint64_t icmaddr; /* ICM virtual address */
uint64_t vaddr; /* host virtual address */
uint_t length; /* length requested */
uint_t icm_refcnt; /* refcnt */
};
_NOTE(SCHEME_PROTECTS_DATA("safe sharing",
hermon_dma_info_s::icm_refcnt))
/*
* The hermon_cmd_reg_t structure is used to hold the address of the each of
* the most frequently accessed hardware registers. Specifically, it holds
* the HCA Command Registers (HCR, used to pass command and mailbox
* information back and forth to Hermon firmware) and the lock used to guarantee
* mutually exclusive access to the registers.
* Related to this, is the "clr_int" register which is used to clear the
* interrupt once all EQs have been serviced.
* Finally, there is the software reset register which is used to reinitialize
* the Hermon device and to put it into a known state at driver startup time.
* Below we also have the offsets (into the CMD register space) for each of
* the various registers.
*/
typedef struct hermon_cmd_reg_s {
hermon_hw_hcr_t *hcr;
kmutex_t hcr_lock;
uint64_t *clr_intr;
uint64_t *eq_arm;
uint64_t *eq_set_ci;
uint32_t *sw_reset;
uint32_t *sw_semaphore;
uint32_t *fw_err_buf;
} hermon_cmd_reg_t;
_NOTE(MUTEX_PROTECTS_DATA(hermon_cmd_reg_t::hcr_lock,
hermon_cmd_reg_t::hcr))
/* SOME TEMPORARY PRINTING THINGS */
#define HERMON_PRINT_CI (0x01 << 0)
#define HERMON_PRINT_MEM (0x01 << 1)
#define HERMON_PRINT_CQ (0x01 << 2)
#define HD_PRINT(state, mask) \
if (state->hs_debug_lev & mask)
/* END PRINTING THINGS */
/*
* The hermon_state_t structure is the HCA software state structure. It
* contains all the pointers and placeholder for everything that the HCA
* driver needs to properly operate. One of these structures exists for
* every instance of the HCA driver.
*/
struct hermon_state_s {
dev_info_t *hs_dip;
int hs_instance;
/* PCI device, vendor, and revision IDs */
uint16_t hs_vendor_id;
uint16_t hs_device_id;
uint8_t hs_revision_id;
/*
* DMA information for the InfiniHost Context Memory (ICM),
* ICM Auxiliary allocation and the firmware. Also, record
* of ICM and ICMA sizes, in bytes.
*/
uint64_t hs_icm_sz;
hermon_icm_table_t *hs_icm;
uint64_t hs_icma_sz;
hermon_dma_info_t hs_icma_dma;
hermon_dma_info_t hs_fw_dma;
/* Hermon interrupt/MSI information */
int hs_intr_types_avail;
uint_t hs_intr_type_chosen;
int hs_intrmsi_count;
int hs_intrmsi_avail;
int hs_intrmsi_allocd;
ddi_intr_handle_t hs_intrmsi_hdl[HERMON_MSIX_MAX];
uint_t hs_intrmsi_pri;
int hs_intrmsi_cap;
ddi_cb_handle_t hs_intr_cb_hdl;
/* Do not use reserved EQs */
uint_t hs_rsvd_eqs;
uint_t hs_cq_erreqnum;
/* cq_sched data */
kmutex_t hs_cq_sched_lock;
hermon_cq_sched_t *hs_cq_sched_array;
hermon_cq_sched_t hs_cq_sched_default;
uint_t hs_cq_sched_array_size;
/* hermon HCA name and HCA part number */
char hs_hca_name[64];
char hs_hca_pn[64];
int hs_hca_pn_len;
/* Hermon device operational mode */
int hs_operational_mode;
/* Attach buffer saved per state to store detailed attach errors */
char hs_attach_buf[HERMON_ATTACH_MSGSIZE];
/* Hermon NodeGUID, SystemImageGUID, and NodeDescription */
uint64_t hs_nodeguid;
uint64_t hs_sysimgguid;
char hs_nodedesc[64];
/* Info passed to IBTF during registration */
ibc_hca_info_t hs_ibtfinfo;
ibc_clnt_hdl_t hs_ibtfpriv;
/*
* Hermon register mapping. Holds the device access attributes,
* kernel mapped addresses, and DDI access handles for both
* Hermon's CMD and UAR BARs.
*/
ddi_device_acc_attr_t hs_reg_accattr;
caddr_t hs_reg_cmd_baseaddr; /* Hermon CMD BAR */
ddi_acc_handle_t hs_reg_cmdhdl;
caddr_t hs_reg_uar_baseaddr; /* Hermon UAR BAR */
ddi_acc_handle_t hs_reg_uarhdl;
caddr_t hs_reg_msi_baseaddr; /* Hermon MSIx BAR */
ddi_acc_handle_t hs_reg_msihdl;
/*
* Some additional things for UAR Pages
*/
uint64_t hs_kernel_uar_index; /* kernel UAR index */
uint64_t hs_bf_offset; /* offset from UAR */
/* Bar to Blueflame */
caddr_t hs_reg_bf_baseaddr; /* blueflame base */
ddi_acc_handle_t hs_reg_bfhdl; /* blueflame handle */
/*
* Hermon PCI config space registers. This array is used to
* save and restore the PCI config registers before and after a
* software reset.
*/
uint32_t hs_cfg_data[HERMON_SW_RESET_NUMREGS];
/* for reset per Linux driver */
uint32_t hs_pci_cap_offset;
uint32_t hs_pci_cap_devctl;
uint32_t hs_pci_cap_lnkctl;
/*
* Hermon UAR page resources. Holds the resource pointers for
* UAR page #0 (reserved) and for UAR page #1 (used for kernel
* driver doorbells). In addition, we save a pointer to the
* UAR page #1 doorbells which will be used throughout the driver
* whenever it is necessary to ring one of them. And, in case we
* are unable to do 64-bit writes to the page (because of system
* architecture), we include a lock (to ensure atomic 64-bit access).
*/
hermon_rsrc_t *hs_uarpg0_rsrc_rsrvd;
hermon_rsrc_t *hs_uarkpg_rsrc;
hermon_hw_uar_t *hs_uar;
kmutex_t hs_uar_lock;
/*
* Used during a call to open() if we are in maintenance mode, this
* field serves as a semi-unique rolling count index value, used only
* in the setup of umap_db entries. This is primarily needed to
* firmware device access ioctl operations can still be guaranteed to
* close in the event of an unplanned process exit, even in maintenance
* mode.
*/
uint_t hs_open_ar_indx;
/*
* Hermon command registers. This structure contains the addresses
* for each of the most frequently accessed CMD registers. Since
* almost all accesses to the Hermon hardware are through the Hermon
* command interface (i.e. the HCR), we save away the pointer to
* the HCR, as well as pointers to the ECR and INT registers (as
* well as their corresponding "clear" registers) for interrupt
* processing. And we also save away a pointer to the software
* reset register (see above).
*/
hermon_cmd_reg_t hs_cmd_regs;
uint32_t hs_cmd_toggle;
/*
* Hermon resource pointers. The following are pointers to the
* kmem cache (from which the Hermon resource handles are allocated),
* and the array of "resource pools" (which store all the pertinent
* information necessary to manage each of the various types of
* resources that are used by the driver. See hermon_rsrc.h for
* more detail.
*/
kmem_cache_t *hs_rsrc_cache;
hermon_rsrc_pool_info_t *hs_rsrc_hdl;
/*
* Hermon mailbox lists. These hold the information necessary to
* manage the pools of pre-allocated Hermon mailboxes (both "In" and
* "Out" type). See hermon_cmd.h for more detail.
*/
hermon_mboxlist_t hs_in_mblist;
hermon_mboxlist_t hs_out_mblist;
/*
* Hermon interrupt mailbox lists. We allocate both an "In" mailbox
* and an "Out" type mailbox for the interrupt context. This is in
* order to guarantee that a mailbox entry will always be available in
* the interrupt context, and we can NOSLEEP without having to worry
* about possible failure allocating the mbox. We create this as an
* mboxlist so that we have the potential for having multiple mboxes
* available based on the number of interrupts we can receive at once.
*/
hermon_mboxlist_t hs_in_intr_mblist;
hermon_mboxlist_t hs_out_intr_mblist;
/*
* Hermon outstanding command list. Used to hold all the information
* necessary to manage the Hermon "outstanding command list". See
* hermon_cmd.h for more detail.
*/
hermon_cmdlist_t hs_cmd_list;
/*
* This structure contains the Hermon driver's "configuration profile".
* This is the collected set of configuration information, such as
* number of QPs, CQs, mailboxes and other resources, sizes of
* individual resources, other system level configuration information,
* etc. See hermon_cfg.h for more detail.
*/
hermon_cfg_profile_t *hs_cfg_profile;
/*
* This flag contains the profile setting, selecting which profile the
* driver would use. This is needed in the case where we have to
* fallback to a smaller profile based on some DDR conditions. If we
* don't fallback, then it is set to the size of DDR in the system.
*/
uint32_t hs_cfg_profile_setting;
/*
* The following are a collection of resource handles used by the
* Hermon driver (internally). First is the protection domain (PD)
* handle that is used when mapping all kernel memory (work queues,
* completion queues, etc). Next is an array of EQ handles. This
* array is indexed by EQ number and allows the Hermon driver to quickly
* convert an EQ number into the software structure associated with the
* given EQ. Likewise, we have three arrays for CQ, QP and SRQ
* handles. These arrays are also indexed by CQ, QP or SRQ number and
* allow the driver to quickly find the corresponding CQ, QP or SRQ
* software structure. Note: while the EQ table is of fixed size
* (because there are a maximum of 64 EQs), each of the CQ, QP and SRQ
* handle lists must be allocated at driver startup.
*/
hermon_pdhdl_t hs_pdhdl_internal;
hermon_eqhdl_t hs_eqhdl[HERMON_NUM_EQ];
kmutex_t hs_dbr_lock; /* lock for dbr mgmt */
/* linked list of kernel dbr resources */
hermon_dbr_info_t *hs_kern_dbr;
/* linked list of non-kernel dbr resources */
hermon_user_dbr_t *hs_user_dbr;
/*
* The AVL tree is used to store information regarding QP number
* allocations. The lock protects access to the AVL tree.
*/
avl_tree_t hs_qpn_avl;
kmutex_t hs_qpn_avl_lock;
/*
* This field is used to indicate whether or not the Hermon driver is
* currently in an IBTF event callback elsewhere in the system. Note:
* It is "volatile" because we intend to poll on this value - in
* hermon_detach() - until we are assured that no further IBTF callbacks
* are currently being processed.
*/
volatile uint32_t hs_in_evcallb;
/*
* The following structures are used to store the results of several
* device query commands passed to the Hermon hardware at startup.
* Specifically, we have hung onto the results of QUERY_DDR (which
* gives information about how much DDR memory is present and where
* it is located), QUERY_FW (which gives information about firmware
* version numbers and the location and extent of firmware's footprint
* in DDR, QUERY_DEVLIM (which gives the device limitations/resource
* maximums) and QUERY_PORT (where some of the specs from DEVLIM moved),
* QUERY_ADAPTER (which gives additional miscellaneous
* information), and INIT/QUERY_HCA (which serves the purpose of
* recording what configuration information was passed to the firmware
* when the HCA was initialized).
*/
struct hermon_hw_queryfw_s hs_fw;
struct hermon_hw_querydevlim_s hs_devlim;
struct hermon_hw_query_port_s hs_queryport;
struct hermon_hw_set_port_s *hs_initport;
struct hermon_hw_queryadapter_s hs_adapter;
struct hermon_hw_initqueryhca_s hs_hcaparams;
/*
* The following are used for managing special QP resources.
* Specifically, we have a lock, a set of flags (in "hs_spec_qpflags")
* used to track the special QP resources, and two Hermon resource
* handle pointers. Each resource handle actually corresponds to two
* consecutive QP contexts (one per port) for each special QP type.
*/
kmutex_t hs_spec_qplock;
uint_t hs_spec_qpflags;
hermon_rsrc_t *hs_spec_qp0;
hermon_rsrc_t *hs_spec_qp1;
/*
* For Hermon, you have to alloc 8 qp's total, but the last 4 are
* unused/reserved. The following represents the handle for those
* last 4 qp's
*/
hermon_rsrc_t *hs_spec_qp_unused;
/*
* Related in some ways to the special QP handling above are these
* resources which are used specifically for implementing the Hermon
* agents (SMA, PMA, and BMA). Although, each of these agents does
* little more that intercept the appropriate incoming MAD and forward
* it along to the firmware (see hermon_agents.c for more details), we
* do still use a task queue to queue them up. We can also configure
* the driver to force firmware handling for certain classes of MAD,
* and, therefore, we require the agent list and number of agents
* in order to know what needs to be torn down at detach() time.
*/
hermon_agent_list_t *hs_agents;
ddi_taskq_t *hs_taskq_agents;
uint_t hs_num_agents;
/*
* Multicast group lists. These are used to track the "shadow" MCG
* lists that speed up the processing of attach and detach multicast
* group operations. See hermon_misc.h for more details. Note: we
* need the pointer to the "temporary" MCG entry here primarily
* because the size of a given MCG entry is configurable. Therefore,
* it is impossible to put this variable on the stack. And rather
* than allocate and deallocate the entry multiple times, we choose
* instead to preallocate it once and reuse it over and over again.
*/
kmutex_t hs_mcglock;
hermon_mcghdl_t hs_mcghdl;
hermon_hw_mcg_t *hs_mcgtmp;
/*
* Cache of the pkey table, sgid (guid-only) tables, and
* sgid (subnet) prefix. These arrays are set
* during port_query, and mainly used for generating MLX GSI wqes.
*/
ib_pkey_t *hs_pkey[HERMON_MAX_PORTS];
ib_sn_prefix_t hs_sn_prefix[HERMON_MAX_PORTS];
ib_guid_t *hs_guid[HERMON_MAX_PORTS];
/*
* Used for tracking Hermon kstat information
*/
hermon_ks_info_t *hs_ks_info;
/*
* Used for Hermon info ioctl used by VTS
*/
kmutex_t hs_info_lock;
/*
* Used for Hermon FW flash burning. They are used exclusively
* within the ioctl calls for use when accessing the hermon
* flash device.
*/
kmutex_t hs_fw_flashlock;
int hs_fw_flashstarted;
dev_t hs_fw_flashdev;
uint32_t hs_fw_log_sector_sz;
uint32_t hs_fw_device_sz;
uint32_t hs_fw_flashbank;
uint32_t *hs_fw_sector;
uint32_t hs_fw_gpio[4];
int hs_fw_cmdset;
/*
* Used for Hermon FM. They are basically used to manage
* the toggle switch to enable/disable Hermon FM.
* Please see the comment in hermon_fm.c.
*/
int hs_fm_capabilities; /* FM capabilities */
int hs_fm_disable; /* Hermon FM disable flag */
int hs_fm_state; /* Hermon FM state */
boolean_t hs_fm_async_fatal; /* async internal error */
uint32_t hs_fm_async_errcnt; /* async error count */
boolean_t hs_fm_poll_suspend; /* poll thread suspend */
kmutex_t hs_fm_lock; /* mutex for state */
hermon_hca_fm_t *hs_fm_hca_fm; /* HCA FM pointer */
ddi_acc_handle_t hs_fm_cmdhdl; /* fm-protected CMD hdl */
ddi_acc_handle_t hs_fm_uarhdl; /* fm-protected UAR hdl */
ddi_device_acc_attr_t hs_fm_accattr; /* fm-protected acc attr */
ddi_periodic_t hs_fm_poll_thread; /* fma poll thread */
int32_t hs_fm_degraded_reason; /* degradation cause */
#ifdef FMA_TEST
mod_hash_t *hs_fm_test_hash; /* testset */
mod_hash_t *hs_fm_id_hash; /* testid */
#endif
/* FCoIB data */
hermon_fcoib_t hs_fcoib;
boolean_t hs_fcoib_may_be_running; /* cq_poll test */
/*
* Hermon fastreboot support. To sw-reset Hermon HCA, the driver
* needs to save/restore MSI-X tables and PBA. Those members are
* used for the purpose.
*/
/* Access handle for PCI config space */
ddi_acc_handle_t hs_reg_pcihdl; /* PCI cfg handle */
ddi_acc_handle_t hs_fm_pcihdl; /* fm handle */
ushort_t hs_caps_ptr; /* MSI-X caps */
ushort_t hs_msix_ctrl; /* MSI-X ctrl */
/* members to handle MSI-X tables */
ddi_acc_handle_t hs_reg_msix_tblhdl; /* MSI-X table handle */
ddi_acc_handle_t hs_fm_msix_tblhdl; /* fm handle */
char *hs_msix_tbl_addr; /* MSI-X table addr */
char *hs_msix_tbl_entries; /* MSI-X table entry */
size_t hs_msix_tbl_size; /* MSI-X table size */
uint32_t hs_msix_tbl_offset; /* MSI-X table offset */
uint32_t hs_msix_tbl_rnumber; /* MSI-X table reg# */
/* members to handle MSI-X PBA */
ddi_acc_handle_t hs_reg_msix_pbahdl; /* MSI-X PBA handle */
ddi_acc_handle_t hs_fm_msix_pbahdl; /* fm handle */
char *hs_msix_pba_addr; /* MSI-X PBA addr */
char *hs_msix_pba_entries; /* MSI-X PBA entry */
size_t hs_msix_pba_size; /* MSI-X PBA size */
uint32_t hs_msix_pba_offset; /* MSI-X PBA offset */
uint32_t hs_msix_pba_rnumber; /* MSI-X PBA reg# */
boolean_t hs_quiescing; /* in fastreboot */
};
_NOTE(MUTEX_PROTECTS_DATA(hermon_state_s::hs_fw_flashlock,
hermon_state_s::hs_fw_flashstarted
hermon_state_s::hs_fw_flashdev
hermon_state_s::hs_fw_log_sector_sz
hermon_state_s::hs_fw_device_sz))
_NOTE(MUTEX_PROTECTS_DATA(hermon_state_s::hs_spec_qplock,
hermon_state_s::hs_spec_qpflags
hermon_state_s::hs_spec_qp0
hermon_state_s::hs_spec_qp1))
_NOTE(MUTEX_PROTECTS_DATA(hermon_state_s::hs_mcglock,
hermon_state_s::hs_mcghdl
hermon_state_s::hs_mcgtmp))
_NOTE(DATA_READABLE_WITHOUT_LOCK(hermon_state_s::hs_in_evcallb
hermon_state_s::hs_fw_log_sector_sz
hermon_state_s::hs_fw_device_sz
hermon_state_s::hs_spec_qpflags
hermon_state_s::hs_spec_qp0
hermon_state_s::hs_spec_qp1))
_NOTE(MUTEX_PROTECTS_DATA(hermon_state_s::hs_qpn_avl_lock,
hermon_state_s::hs_qpn_avl))
_NOTE(SCHEME_PROTECTS_DATA("safe sharing",
hermon_state_s::hs_fm_async_fatal
hermon_state_s::hs_fw_sector))
/*
* HERMON_IN_FASTREBOOT() shows if Hermon driver is at fastreboot.
* This macro should be used to check if the mutex lock can be used
* since the lock cannot be used if the driver is in the quiesce mode.
*/
#define HERMON_IN_FASTREBOOT(state) (state->hs_quiescing == B_TRUE)
/*
* Bit positions in the "hs_spec_qpflags" field above. The flags are (from
* least significant to most): (QP0,Port1), (QP0,Port2), (QP1,Port1), and
* (QP1,Port2). The masks are there to help with some specific allocation
* and freeing operations
*/
#define HERMON_SPECIAL_QP0_RSRC 0
#define HERMON_SPECIAL_QP0_RSRC_MASK 0x3
#define HERMON_SPECIAL_QP1_RSRC 2
#define HERMON_SPECIAL_QP1_RSRC_MASK 0xC
/*
* These flags specifies additional behaviors on database access.
* HERMON_UMAP_DB_REMOVE, for example, specifies that (if found) the database
* entry should be removed from the database. HERMON_UMAP_DB_IGNORE_INSTANCE
* specifies that a particular database query should ignore value in the
* "tdb_instance" field as a criterion for the search.
*/
#define HERMON_UMAP_DB_REMOVE (1 << 0)
#define HERMON_UMAP_DB_IGNORE_INSTANCE (1 << 1)
/*
* The hermon_umap_db_t structure contains what is referred to throughout the
* driver code as the "userland resources database". This structure contains
* all the necessary information to track resources that have been prepared
* for direct-from-userland access. There is an AVL tree ("hdl_umapdb_avl")
* which consists of the "hermon_umap_db_entry_t" (below) and a lock to ensure
* atomic access when adding or removing entries from the database.
*/
typedef struct hermon_umap_db_s {
kmutex_t hdl_umapdb_lock;
avl_tree_t hdl_umapdb_avl;
} hermon_umap_db_t;
/*
* The hermon_umap_db_priv_t structure currently contains information necessary
* to provide the "on close" callback to the firmware flash interfaces. It
* is intended that this structure could be extended to enable other "on
* close" callbacks as well.
*/
typedef struct hermon_umap_db_priv_s {
int (*hdp_cb)(void *);
void *hdp_arg;
} hermon_umap_db_priv_t;
/*
* The hermon_umap_db_common_t structure contains fields which are common
* between the database entries ("hermon_umap_db_entry_t") and the structure
* used to contain the search criteria ("hermon_umap_db_query_t"). This
* structure contains a key, a resource type (described above), an instance
* (corresponding to the driver instance which inserted the database entry),
* and a "value" field. Typically, "hdb_value" is a pointer to a Hermon
* resource object. Although for memory regions, the value field corresponds
* to the ddi_umem_cookie_t for the pinned userland memory.
* The structure also includes a placeholder for private data ("hdb_priv").
* Currently this data is being used for holding "on close" callback
* information to allow certain kinds of cleanup even if a userland process
* prematurely exits.
*/
typedef struct hermon_umap_db_common_s {
uint64_t hdb_key;
uint64_t hdb_value;
uint_t hdb_type;
uint_t hdb_instance;
void *hdb_priv;
} hermon_umap_db_common_t;
/*
* The hermon_umap_db_entry_t structure is the entry in "userland resources
* database". As required by the AVL framework, each entry contains an
* "avl_node_t". Then, as required to implement the database, each entry
* contains a "hermon_umap_db_common_t" structure used to contain all of the
* relevant entries.
*/
typedef struct hermon_umap_db_entry_s {
avl_node_t hdbe_avlnode;
hermon_umap_db_common_t hdbe_common;
} hermon_umap_db_entry_t;
/*
* The hermon_umap_db_query_t structure is used in queries to the "userland
* resources database". In addition to the "hermon_umap_db_common_t" structure
* used to contain the various search criteria, this structure also contains
* a flags field "hqdb_flags" which can be used to specify additional behaviors
* (as described above). Specifically, the flags field can be used to specify
* that an entry should be removed from the database, if found, and to
* specify whether the database lookup should consider "tdb_instance" in the
* search.
*/
typedef struct hermon_umap_db_query_s {
uint_t hqdb_flags;
hermon_umap_db_common_t hqdb_common;
} hermon_umap_db_query_t;
_NOTE(MUTEX_PROTECTS_DATA(hermon_umap_db_s::hdl_umapdb_lock,
hermon_umap_db_entry_s::hdbe_avlnode
hermon_umap_db_entry_s::hdbe_common.hdb_key
hermon_umap_db_entry_s::hdbe_common.hdb_value
hermon_umap_db_entry_s::hdbe_common.hdb_type
hermon_umap_db_entry_s::hdbe_common.hdb_instance))
/*
* The hermon_devmap_track_t structure contains all the necessary information
* to track resources that have been mapped through devmap. There is a
* back-pointer to the Hermon softstate, the logical offset corresponding with
* the mapped resource, the size of the mapped resource (zero indicates an
* "invalid mapping"), and a reference count and lock used to determine when
* to free the structure (specifically, this is necessary to handle partial
* unmappings).
*/
typedef struct hermon_devmap_track_s {
hermon_state_t *hdt_state;
uint64_t hdt_offset;
uint_t hdt_size;
int hdt_refcnt;
kmutex_t hdt_lock;
} hermon_devmap_track_t;
#define HERMON_ICM_SPLIT 64
#define HERMON_ICM_SPAN 4096
#define hermon_bitmap(bitmap, dma_info, icm_table, split_index, num_to_hdl) \
bitmap = (icm_table)->icm_bitmap[split_index]; \
if (bitmap == NULL) { \
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*(icm_table))) \
int num_spans = (icm_table)->num_spans; \
bitmap = \
(icm_table)->icm_bitmap[split_index] = \
kmem_zalloc((num_spans + 7) / 8, KM_SLEEP); \
ASSERT((icm_table)->icm_dma[split_index] == NULL); \
(icm_table)->icm_dma[split_index] = \
kmem_zalloc(num_spans * sizeof (hermon_dma_info_t), \
KM_SLEEP); \
if (num_to_hdl) { \
ASSERT((icm_table)->num_to_hdl[split_index] == NULL); \
(icm_table)->num_to_hdl[split_index] = \
kmem_zalloc(num_spans * \
sizeof (void **), KM_SLEEP); \
} \
} \
dma_info = (icm_table)->icm_dma[split_index]
/*
* The hermon_icm_table_t encodes data pertaining to a given ICM table, and
* holds an array of hermon_dma_info_t's related to its backing memory. Each
* ICM table is sized during initialization, but real memory is allocated
* and mapped into and out of ICM in the device throughout the life of the
* instance. We use a bitmap to determine whether or not a given ICM object
* has memory backing it or not, and an array of hermon_dma_info_t's to house
* the actual allocations. Memory is allocated in chunks of span_size, stored
* in the icm_dma array, and can later be looked up by using the bitmap index.
* The total number of ICM spans is equal to table_size / span_size. We also
* keep track of the ICM characteristics, such as ICM object size and the
* number of entries in the ICM area.
*/
struct hermon_icm_table_s {
kmutex_t icm_table_lock;
kcondvar_t icm_table_cv;
uint8_t icm_busy;
hermon_rsrc_type_t icm_type;
uint64_t icm_baseaddr;
uint64_t table_size;
uint64_t num_entries; /* maximum #entries */
uint32_t object_size;
uint32_t span; /* #rsrc's per span */
uint32_t num_spans; /* #dmainfos in icm_dma */
uint32_t split_shift;
uint32_t span_mask;
uint32_t span_shift;
uint32_t rsrc_mask;
uint16_t log_num_entries;
uint16_t log_object_size;
/* three arrays of pointers, each pointer points to arrays */
uint8_t *icm_bitmap[HERMON_ICM_SPLIT];
hermon_dma_info_t *icm_dma[HERMON_ICM_SPLIT];
void ***num_to_hdl[HERMON_ICM_SPLIT]; /* qp/cq/srq */
};
/*
* Split the rsrc index into three pieces:
*
* index1 - icm_bitmap[HERMON_ICM_SPLIT], icm_dma[HERMON_ICM_SPLIT]
* index2 - bitmap[], dma[]
* offset - rsrc within the icm mapping
*/
#define hermon_index(index1, index2, rindx, table, offset) \
index1 = (rindx) >> table->split_shift; \
index2 = ((rindx) & table->span_mask) >> table->span_shift; \
offset = (rindx) & table->rsrc_mask
/* Defined in hermon.c */
int hermon_dma_alloc(hermon_state_t *state, hermon_dma_info_t *dma_info,
uint16_t opcode);
void hermon_dma_attr_init(hermon_state_t *state, ddi_dma_attr_t *dma_attr);
void hermon_dma_free(hermon_dma_info_t *info);
int hermon_icm_alloc(hermon_state_t *state, hermon_rsrc_type_t type,
uint32_t icm_index1, uint32_t icm_index2);
void hermon_icm_free(hermon_state_t *state, hermon_rsrc_type_t type,
uint32_t icm_index1, uint32_t icm_index2);
void *hermon_icm_num_to_hdl(hermon_state_t *state, hermon_rsrc_type_t type,
uint32_t idx);
void hermon_icm_set_num_to_hdl(hermon_state_t *state, hermon_rsrc_type_t type,
uint32_t idx, void *hdl);
int hermon_device_mode(hermon_state_t *state);
/* Defined in hermon_umap.c */
int hermon_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
size_t *maplen, uint_t model);
ibt_status_t hermon_umap_ci_data_in(hermon_state_t *state,
ibt_ci_data_flags_t flags, ibt_object_type_t object, void *hdl,
void *data_p, size_t data_sz);
ibt_status_t hermon_umap_ci_data_out(hermon_state_t *state,
ibt_ci_data_flags_t flags, ibt_object_type_t object, void *hdl,
void *data_p, size_t data_sz);
void hermon_umap_db_init(void);
void hermon_umap_db_fini(void);
hermon_umap_db_entry_t *hermon_umap_db_alloc(uint_t instance, uint64_t key,
uint_t type, uint64_t value);
void hermon_umap_db_free(hermon_umap_db_entry_t *umapdb);
void hermon_umap_db_add(hermon_umap_db_entry_t *umapdb);
void hermon_umap_db_add_nolock(hermon_umap_db_entry_t *umapdb);
int hermon_umap_db_find(uint_t instance, uint64_t key, uint_t type,
uint64_t *value, uint_t flags, hermon_umap_db_entry_t **umapdb);
int hermon_umap_db_find_nolock(uint_t instance, uint64_t key, uint_t type,
uint64_t *value, uint_t flags, hermon_umap_db_entry_t **umapdb);
void hermon_umap_umemlock_cb(ddi_umem_cookie_t *umem_cookie);
int hermon_umap_db_set_onclose_cb(dev_t dev, uint64_t flag,
int (*callback)(void *), void *arg);
int hermon_umap_db_clear_onclose_cb(dev_t dev, uint64_t flag);
int hermon_umap_db_handle_onclose_cb(hermon_umap_db_priv_t *priv);
int hermon_rsrc_hw_entries_init(hermon_state_t *state,
hermon_rsrc_hw_entry_info_t *info);
void hermon_rsrc_hw_entries_fini(hermon_state_t *state,
hermon_rsrc_hw_entry_info_t *info);
#ifdef __cplusplus
}
#endif
#endif /* _SYS_IB_ADAPTERS_HERMON_H */
|