summaryrefslogtreecommitdiff
path: root/usr/src/uts/intel/io/imc/imc.h
blob: 5f3def4930b7eec9bd1cc1e2681f8ffe2894b432 (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
/*
 * 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 2019 Joyent, Inc.
 */

#ifndef _INTEL_IMC_H
#define	_INTEL_IMC_H

#include <sys/types.h>
#include <sys/bitmap.h>
#include <sys/list.h>
#include <sys/sunddi.h>

/*
 * This header file contains the definitions used for the various generations of
 * the Intel IMC driver.
 */

#ifdef __cplusplus
extern "C" {
#endif

/*
 * The maximum number of sockets that the IMC driver supports. This is currently
 * determined by the Purley platforms (Skylake) which support up to 8 CPUs.
 */
#define	IMC_MAX_SOCKETS		8

/*
 * The maximum number of memory controllers that exist per socket. Currently all
 * supported platforms (Sandy Bridge -> Skylake) support at most two.
 */
#define	IMC_MAX_IMCPERSOCK	2

/*
 * The maximum number of channels that exist per IMC. Currently Skylake supports
 * 3 per IMC. On certain configurations of Haswell/Broadwell, there is only a
 * single IMC which supports all 4 channels.
 */
#define	IMC_MAX_CHANPERMC	4

/*
 * The maximum number of DIMMs that exist per channel. On Skylake this is two
 * DIMMs. However, Sandy Bridge through Broadwell support three.
 */
#define	IMC_MAX_DIMMPERCHAN	3

/*
 * The maximum number of rank disable bits per DIMM. This is currently
 * consistent across all generations that have these bits.
 */
#define	IMC_MAX_RANK_DISABLE	4

/*
 * The number of different PCI buses that we need to record for a given
 * platform. Pre-Skylake there are only two that are required, one for the IIO
 * and one for the non-IIO. On Skylake, more PCI buses are used.
 */
#define	IMC_MAX_PCIBUSES	3

/*
 * Macros to take apart the node id for a given processor. These assume that
 * we're reading the nodeid from the UBox and not from the SAD control.
 */
#define	IMC_NODEID_UBOX_MASK(x)		((x) & 0x7)

/*
 * On Ivy Bridge through Broadwell, the node id that is found in the SAD targets
 * has the HA indicator as NodeID[2]. This means that the actual target node of
 * the socket is NodeID[3] | NodeID[1:0].
 */
#define	IMC_NODEID_IVY_BRD_UPPER(x)	BITX(x, 3, 3)
#define	IMC_NODEID_IVY_BRD_LOWER(x)	BITX(x, 1, 0)
#define	IMC_NODEID_IVY_BRD_HA(x)	BITX(x, 2, 2)

/*
 * Macros to take apart the MCMTR register bits that we care about.
 */
#define	IMC_MCMTR_CLOSED_PAGE(x)	BITX(x, 0, 0)
#define	IMC_MCMTR_LOCKSTEP(x)		BITX(x, 1, 1)
#define	IMC_MCMTR_ECC_ENABLED(x)	BITX(x, 2, 2)

#define	IMC_MCMTR_DDR4_HAS_BRD(x)	BITX(x, 14, 14)

/*
 * Macros to take apart the dimmmtr_* registers in different generations. While
 * there are similarities, these often end up different between generations and
 * chips. These macros use a range of CPUs that they're valid for in the name.
 * Macros with no suffix are valid for all currently supported CPUs.
 */

#define	IMC_REG_MC_MTR0		0x80
#define	IMC_REG_MC_MTR1		0x84
#define	IMC_REG_MC_MTR2		0x88

#define	IMC_MTR_CA_WIDTH(x)	BITX(x, 1, 0)
#define	IMC_MTR_CA_BASE		10
#define	IMC_MTR_CA_MIN		10
#define	IMC_MTR_CA_MAX		12

#define	IMC_MTR_RA_WIDTH(x)	BITX(x, 4, 2)
#define	IMC_MTR_RA_BASE		12
#define	IMC_MTR_RA_MIN		13
#define	IMC_MTR_RA_MAX		18

#define	IMC_MTR_DENSITY_IVY_BRD(x)	BITX(x, 6, 5)
#define	IMC_MTR_DENSITY_SKX(x)		BITX(x, 7, 5)

#define	IMC_MTR_WIDTH_IVB_HAS(x)	BITX(x, 8, 7)
#define	IMC_MTR_WIDTH_BRD_SKX(x)	BITX(x, 9, 8)

#define	IMC_MTR_DDR_RANKS(x)		BITX(x, 13, 12)
#define	IMC_MTR_DDR_RANKS_MAX		4
#define	IMC_MTR_DDR_RANKS_MAX_HAS_SKX	8

#define	IMC_MTR_PRESENT_SNB_BRD(x)	BITX(x, 14, 14)
#define	IMC_MTR_PRESENT_SKYLAKE(x)	BITX(x, 15, 15)

#define	IMC_MTR_RANK_DISABLE(x)		BITX(x, 19, 16)

#define	IMC_MTR_DDR4_ENABLE_HAS_BRD(x)	BITX(x, 20, 20)
#define	IMC_MTR_HDRL_HAS_SKX(x)		BITX(x, 21, 21)
#define	IMC_MTR_HDRL_PARITY_HAS_SKX(x)	BITX(x, 22, 22)
#define	IMC_MTR_3DSRANKS_HAS_SKX(x)	BITX(x, 24, 23)

/*
 * Data for the RASENABLES register.
 */
#define	IMC_MC_MIRROR_SNB_BRD(x)	BITX(x, 0, 0)

/*
 * The maximum number of SAD rules that exist on all supported platforms.
 */
#define	IMC_MAX_SAD_RULES	24

/*
 * The maximum number of targets that can be interleaved in a sad rule.
 */
#define	IMC_MAX_SAD_INTERLEAVE	8

/*
 * The maximum number of route entries that exist in SAD. This is only used on
 * SKX.
 */
#define	IMC_MAX_SAD_MCROUTES	6

/*
 * Definitions used to decode the MC Route table. Note that at this time this is
 * very Skylake specific (as it's the only platform it's supported on).
 */
#define	IMC_REG_SKX_SAD_MC_ROUTE_TABLE	0xb4
#define	IMC_MC_ROUTE_RING_BITS		3
#define	IMC_MC_ROUTE_RING_MASK		0x7
#define	IMC_MC_ROUTE_CHAN_BITS		2
#define	IMC_MC_ROUTE_CHAN_MASK		0x3
#define	IMC_MC_ROUTE_CHAN_OFFSET	18

/*
 * Definitions to help decode TOLM (top of low memory) and TOHM (top of high
 * memory). The way this is done varies based on generation. These regions are
 * currently always 64-MByte aligned
 *
 * On Sandy Bridge and Ivy Bridge the low four bits of TOLM are bits 31:28. TOHM
 * is a single register. Bits 20:0 map to bits 45:25. Both registers represent
 * the upper limit (as in one higher than the max DRAM value).
 *
 * On Haswell through Skylake, TOLM is represented as a 32-bit quantity. No
 * shifting is required. However, only bits 31:26 are present. TOHM is spread
 * out among two registers. The lower 32-bits is masked in a similar fashion. In
 * both cases, these registers represent an inclusive range where we don't care
 * about other bits. To deal with this we'll increment the lowest bit we care
 * about to make it an exclusive range.
 *
 * Based on the above, we have opted to make both ranges in the IMC driver
 * normalized to an _exclusive_ value.
 *
 * Ivy Bridge has the values in both the CBo SAD and a VT-d section; however, we
 * use the CBo SAD which is why it looks like Sandy Bridge and not Haswell.
 */

#define	IMC_TOLM_SNB_IVY_MASK		0xf
#define	IMC_TOLM_SNB_IVY_SHIFT		28
#define	IMC_TOHM_SNB_IVY_MASK		0x1fffff
#define	IMC_TOHM_SNB_IVY_SHIFT		25

#define	IMC_TOLM_HAS_SKX_MASK		0xfc000000
#define	IMC_TOLM_HAS_SKY_EXCL		(1 << 26)
#define	IMC_TOHM_LOW_HAS_SKX_MASK	0xfc000000
#define	IMC_TOHM_HAS_SKY_EXCL		(1 << 26)

/*
 * Definitions to decode SAD values. These are sometimes subtlety different
 * across generations.
 */
#define	IMC_SAD_DRAM_RULE_ENABLE(x)		BITX(x, 0, 0)

#define	IMC_SAD_DRAM_INTERLEAVE_SNB_BRD(x)	BITX(x, 1, 1)
#define	IMC_SAD_DRAM_INTERLEAVE_SNB_BRD_8t6XOR	0
#define	IMC_SAD_DRAM_INTERLEAVE_SNB_BRD_8t6	1

#define	IMC_SAD_DRAM_INTERLEAVE_SKX(x)		BITX(x, 2, 1)
#define	IMC_SAD_DRAM_INTERLEAVE_SKX_8t6		0
#define	IMC_SAD_DRAM_INTERLEAVE_SKX_10t8	1
#define	IMC_SAD_DRAM_INTERLEAVE_SKX_14t12	2
#define	IMC_SAD_DRAM_INTERLEAVE_SKX_32t30	3

#define	IMC_SAD_DRAM_ATTR_SNB_BRD(x)		BITX(x, 3, 2)
#define	IMC_SAD_DRAM_ATTR_SKX(x)		BITX(x, 4, 3)
#define	IMC_SAD_DRAM_ATTR_DRAM			0
#define	IMC_SAD_DRAM_ATTR_MMCFG			1
#define	IMC_SAD_DRAM_ATTR_NXM			2

#define	IMC_SAD_DRAM_MOD23_SKX(x)		BITX(x, 6, 5)
#define	IMC_SAD_DRAM_MOD23_MOD3			0
#define	IMC_SAD_DRAM_MOD23_MOD2_C01		1
#define	IMC_SAD_DRAM_MOD23_MOD2_C12		2
#define	IMC_SAD_DRAM_MOD23_MOD2_C02		3

#define	IMC_SAD_DRAM_LIMIT_SNB_BRD(x)		BITX(x, 25, 6)
#define	IMC_SAD_DRAM_LIMIT_SKX(x)		BITX(x, 26, 7)
#define	IMC_SAD_DRAM_LIMIT_SHIFT		26
#define	IMC_SAD_DRAM_LIMIT_EXCLUSIVE		(1 << IMC_SAD_DRAM_LIMIT_SHIFT)

#define	IMC_SAD_DRAM_A7_IVB_BRD(x)		BITX(x, 26, 26)
#define	IMC_SAD_DRAM_MOD3_SKX(x)		BITX(x, 27, 27)
#define	IMC_SAD_DRAM_MOD3_MODE_SKX(x)		BITX(x, 31, 30)
#define	IMC_SAD_DRAM_MOD3_MODE_45t6		0
#define	IMC_SAD_DRAM_MOD3_MODE_45t8		1
#define	IMC_SAD_DRAM_MOD3_MODE_45t12		2

#define	IMC_SAD_ILEAVE_SNB_MASK			0x7
#define	IMC_SAD_ILEAVE_SNB_LEN			3
#define	IMC_SAD_ILEAVE_IVB_SKX_MASK		0xf
#define	IMC_SAD_ILEAVE_IVB_SKX_LEN		4

/*
 * The interleave targets on Skylake use the upper bit to indicate whether it is
 * referring to a local memory controller or if it actually refers to another
 * node that is far away. The maximum value includes the upper bit which is used
 * to indicate whether it is remote or far.
 */
#define	IMC_SAD_ILEAVE_SKX_LOCAL(x)		BITX(x, 3, 3)
#define	IMC_SAD_ILEAVE_SKX_TARGET(x)		BITX(x, 2, 0)
#define	IMC_SAD_ILEAVE_SKX_MAX			0xf

/*
 * Maximum number of TAD tables that we need to consider. On Sandy Bridge
 * through Broadwell this is based on the number of home agents that are present
 * in the system. On Sandy Bridge there is one, on others, there are up to two.
 * On Skylake, there is one TAD per IMC.
 */
#define	IMC_MAX_TAD	2

/*
 * Maximum number of TAD rules on any of the supported processors.
 */
#define	IMC_MAX_TAD_RULES	12

/*
 * Maximum number of interleave targets. Note, this only applies to Sandy Bridge
 * through Broadwell. Skylake gets this information in another form.
 */
#define	IMC_MAX_TAD_TARGETS	4

/*
 * Offset between the base TAD rule and the corresponding wayness rule on
 * Skylake.
 */
#define	IMC_SKX_WAYNESS_OFFSET	0x30

/*
 * Various macros to decode the TAD rules.
 */
#define	IMC_TAD_LIMIT(x)		BITX(x, 31, 12)
#define	IMC_TAD_LIMIT_SHIFT		26
#define	IMC_TAD_LIMIT_EXCLUSIVE		(1 << IMC_TAD_LIMIT_SHIFT)

#define	IMC_TAD_SOCK_WAY(x)		BITX(x, 11, 10)
#define	IMC_TAD_SOCK_WAY_1		0
#define	IMC_TAD_SOCK_WAY_2		1
#define	IMC_TAD_SOCK_WAY_4		2
#define	IMC_TAD_SOCK_WAY_8		3
#define	IMC_TAD_CHAN_WAY(x)		BITX(x, 9, 8)
#define	IMC_TAD_TARG3(x)		BITX(x, 7, 6)
#define	IMC_TAD_TARG2(x)		BITX(x, 5, 4)
#define	IMC_TAD_TARG1(x)		BITX(x, 3, 2)
#define	IMC_TAD_TARG0(x)		BITX(x, 1, 0)

#define	IMC_TAD_SNB_BRD_NTARGETS	4

/*
 * These are registers specific to the Skylake and newer TAD BASE registers.
 */
#define	IMC_TAD_BASE_BASE(x)		BITX(x, 31, 12)
#define	IMC_TAD_BASE_SHIFT		26

#define	IMC_TAD_BASE_CHAN_GRAN(x)	BITX(x, 7, 6)
#define	IMC_TAD_BASE_CHAN_GRAN_64B	0
#define	IMC_TAD_BASE_CHAN_GRAN_256B	1
#define	IMC_TAD_BASE_CHAN_GRAN_4KB	2

#define	IMC_TAD_BASE_SOCK_GRAN(x)	BITX(x, 5, 4)
#define	IMC_TAD_BASE_SOCK_GRAN_64B	0
#define	IMC_TAD_BASE_SOCK_GRAN_256B	1
#define	IMC_TAD_BASE_SOCK_GRAN_4KB	2
#define	IMC_TAD_BASE_SOCK_GRAN_1GB	3

#define	IMC_TADCHAN_OFFSET_SNB_BRD(x)	BITX(x, 25, 6)
#define	IMC_TADCHAN_OFFSET_SKX(x)	BITX(x, 23, 4)
#define	IMC_TADCHAN_OFFSET_SHIFT	26

/*
 * Macros to get at various TAD features.
 */
#define	IMC_TAD_SYSDEF_LOCKSTEP(x)	BITX(x, 7, 7)
#define	IMC_TAD_SYSDEF2_SHIFTUP(x)	BITX(x, 22, 22)
#define	IMC_TAD_SYSDEF2_CHANHASH(x)	BITX(x, 21, 21)

/*
 * Maximum number of different wayness entries that exist across the various IMC
 * generations. Each wayness then has a maximum number of target entries.
 */
#define	IMC_MAX_RANK_WAYS		5
#define	IMC_MAX_RANK_INTERLEAVES	8

/*
 * Macros to take apart the rank interleave wayness and offset registers.
 */
#define	IMC_RIR_WAYNESS_ENABLED(x)	BITX(x, 31, 31)
#define	IMC_RIR_WAYNESS_WAY(x)		BITX(x, 29, 28)
#define	IMC_RIR_LIMIT_HAS_SKX(x)	BITX(x, 11, 1)
#define	IMC_RIR_LIMIT_SNB_IVB(x)	BITX(x, 10, 1)
#define	IMC_RIR_LIMIT_SHIFT		29
#define	IMC_RIR_LIMIT_EXCLUSIVE		(1 << IMC_RIR_LIMIT_SHIFT)

/*
 * Currently, everything other than Broadwell has the same value for the target
 * offset.
 */
#define	IMC_RIR_OFFSET_TARGET_BRD(x)		BITX(x, 23, 20)
#define	IMC_RIR_OFFSET_TARGET(x)		BITX(x, 19, 16)
#define	IMC_RIR_OFFSET_OFFSET_HAS_SKX(x)	BITX(x, 15, 2)
#define	IMC_RIR_OFFSET_OFFSET_SNB_IVB(x)	BITX(x, 14, 2)
#define	IMC_RIR_OFFSET_SHIFT			29

/*
 * Definitions to cover manipulations of open and closed pages.
 */
#define	IMC_PAGE_BITS_CLOSED	6
#define	IMC_PAGE_BITS_OPEN	13

/*
 * Macros to decode and understand the CPUBUSNO registers in the UBOX_DECS.
 */
#define	IMC_UBOX_CPUBUSNO_0(x)			BITX(x, 7, 0)
#define	IMC_UBOX_CPUBUSNO_1(x)			BITX(x, 15, 8)
#define	IMC_UBOX_CPUBUSNO_2(x)			BITX(x, 23, 16)

/*
 * Hardware generations supported by the IMC driver.
 */
typedef enum {
	IMC_GEN_UNKNOWN = 0,
	IMC_GEN_SANDY,
	IMC_GEN_IVY,
	IMC_GEN_HASWELL,
	IMC_GEN_BROADWELL,
	/*
	 * IMC_GEN_SKYLAKE also covers Cascade Lake. The two are similar to the
	 * point of even having the same PCI IDs for all of the devices. The
	 * only difference in the cpuid signature between them is the stepping,
	 * hence we do not have a separate Cascade Lake target here, as it's
	 * really the same as Skylake.
	 */
	IMC_GEN_SKYLAKE
} imc_gen_t;

/*
 * Generation specific limits.
 */
typedef struct imc_gen_data {
	uint_t	igd_max_sockets;
	uint_t	igd_max_imcs;
	uint_t	igd_max_channels;
	uint_t	igd_max_dimms;
	uint_t	igd_max_ranks;
	uint_t	igd_mtr_offsets[IMC_MAX_DIMMPERCHAN];
	uint_t	igd_mcmtr_offset;
	uint_t	igd_topo_offset;
	uint_t	igd_num_mcroutes;
	uint_t	igd_tolm_offset;
	uint_t	igd_tohm_low_offset;
	uint_t	igd_tohm_hi_offset;
	uint_t	igd_sad_dram_offset;
	uint_t	igd_sad_ndram_rules;
	uint_t	igd_sad_nodeid_offset;
	uint_t	igd_tad_nrules;
	uint_t	igd_tad_rule_offset;
	uint_t	igd_tad_chan_offset;
	uint_t	igd_tad_sysdef;
	uint_t	igd_tad_sysdef2;
	uint_t	igd_mc_mirror;
	uint_t	igd_rir_nways;
	uint_t	igd_rir_way_offset;
	uint_t	igd_rir_nileaves;
	uint_t	igd_rir_ileave_offset;
	uint_t	igd_ubox_cpubusno_offset;
} imc_gen_data_t;

/*
 * Different types of PCI devices that show up on the core that we may need to
 * attach to.
 */
typedef enum {
	IMC_TYPE_UNKNOWN = 0,
	IMC_TYPE_MC0_M2M,	/* SKX Only */
	IMC_TYPE_MC1_M2M,	/* SKX Only */
	IMC_TYPE_MC0_MAIN0,
	IMC_TYPE_MC0_MAIN1,
	IMC_TYPE_MC1_MAIN0,
	IMC_TYPE_MC1_MAIN1,
	IMC_TYPE_MC0_CHANNEL0,
	IMC_TYPE_MC0_CHANNEL1,
	IMC_TYPE_MC0_CHANNEL2,
	IMC_TYPE_MC0_CHANNEL3,
	IMC_TYPE_MC1_CHANNEL0,
	IMC_TYPE_MC1_CHANNEL1,
	IMC_TYPE_MC1_CHANNEL2,
	IMC_TYPE_MC1_CHANNEL3,
	IMC_TYPE_SAD_DRAM,
	IMC_TYPE_SAD_MMIO,
	/*
	 * We want to note which device has the TOLM and TOHM registers.
	 * Unfortunately this is a rather complicated affair. On Sandy Bridge
	 * they are a part of the IMC_TYPE_SAD_MMIO. On Ivy Bridge, it's on its
	 * own dedicated device on the CBo.
	 *
	 * On Haswell onward, these move to the VT-D misc. registers. On Haswell
	 * and Broadwell, only one of these exist in the system. However, on
	 * Skylake these exist per socket.
	 */
	IMC_TYPE_SAD_MISC,
	IMC_TYPE_VTD_MISC,
	/*
	 * On SKX this exists on a per-core basis. It contains the memory
	 * controller routing table.
	 */
	IMC_TYPE_SAD_MCROUTE,
	IMC_TYPE_UBOX,
	IMC_TYPE_UBOX_CPUBUSNO,
	IMC_TYPE_HA0,
	IMC_TYPE_HA1,
} imc_type_t;

/*
 * Each entry in the stub table represents a device that we might attach to in a
 * given generation. This is only defined in the kernel to make it easier to
 * build the imc decoder in userland for testing.
 */
#ifdef	_KERNEL
typedef struct imc_stub_table {
	imc_gen_t	imcs_gen;
	imc_type_t	imcs_type;
	uint16_t	imcs_devid;
	uint16_t	imcs_pcidev;
	uint16_t	imcs_pcifunc;
	const char	*imcs_desc;
} imc_stub_table_t;

typedef struct imc_stub {
	avl_node_t		istub_link;
	dev_info_t		*istub_dip;
	uint16_t		istub_vid;
	uint16_t		istub_did;
	uint16_t		istub_bus;
	uint16_t		istub_dev;
	uint16_t		istub_func;
	ddi_acc_handle_t	istub_cfgspace;
	const imc_stub_table_t	*istub_table;
} imc_stub_t;
#else
typedef struct imc_stub {
	void	*istub_unused;
} imc_stub_t;
#endif	/* _KERNEL */

typedef enum {
	IMC_F_UNSUP_PLATFORM	= (1 << 0),
	IMC_F_SCAN_DISPATCHED	= (1 << 1),
	IMC_F_SCAN_COMPLETE	= (1 << 2),
	IMC_F_ATTACH_DISPATCHED	= (1 << 3),
	IMC_F_ATTACH_COMPLETE	= (1 << 4),
	IMC_F_MCREG_FAILED	= (1 << 5),
	IMC_F_VALIDATE_FAILED	= (1 << 6)
} imc_flags_t;

#define	IMC_F_ALL_FLAGS	(IMC_F_UNSUP_PLATFORM | IMC_F_SCAN_DISPATCHED | \
    IMC_F_SCAN_COMPLETE | IMC_F_ATTACH_DISPATCHED | IMC_F_ATTACH_COMPLETE | \
    IMC_F_MCREG_FAILED | IMC_F_VALIDATE_FAILED)

typedef enum imc_dimm_type {
	IMC_DIMM_UNKNOWN,
	IMC_DIMM_DDR3,
	IMC_DIMM_DDR4,
	IMC_DIMM_NVDIMM
} imc_dimm_type_t;

typedef enum imc_dimm_valid {
	IMC_DIMM_V_VALID	= 0,
	IMC_DIMM_V_BAD_PCI_READ	= (1 << 0),
	IMC_DIMM_V_BAD_ROWS	= (1 << 1),
	IMC_DIMM_V_BAD_COLUMNS	= (1 << 2),
	IMC_DIMM_V_BAD_DENSITY	= (1 <<	3),
	IMC_DIMM_V_BAD_WIDTH	= (1 << 4),
	IMC_DIMM_V_BAD_RANKS	= (1 << 5)
} imc_dimm_valid_t;

typedef struct imc_dimm {
	imc_dimm_valid_t	idimm_valid;
	boolean_t	idimm_present;
	uint8_t		idimm_3dsranks;
	boolean_t	idimm_hdrl_parity;
	boolean_t	idimm_hdrl;
	boolean_t	idimm_ranks_disabled[IMC_MAX_RANK_DISABLE];
	uint8_t		idimm_nbanks;
	uint8_t		idimm_nranks;
	uint8_t		idimm_width;
	uint8_t		idimm_density; /* In GiB */
	uint8_t		idimm_nrows;
	uint8_t		idimm_ncolumns;
	/* Synthesized */
	uint64_t	idimm_size;
	/* Raw data */
	uint32_t	idimm_mtr;
} imc_dimm_t;

typedef struct imc_rank_ileave_entry {
	uint8_t		irle_target;
	uint64_t	irle_offset;
} imc_rank_ileave_entry_t;

typedef struct imc_rank_ileave {
	boolean_t		irle_enabled;
	uint32_t		irle_raw;
	uint8_t			irle_nways;
	uint8_t			irle_nwaysbits;
	uint64_t		irle_limit;
	uint_t			irle_nentries;
	imc_rank_ileave_entry_t	irle_entries[IMC_MAX_RANK_INTERLEAVES];
} imc_rank_ileave_t;

typedef enum imc_channel_valid {
	IMC_CHANNEL_V_VALID		= 0,
	IMC_CHANNEL_V_BAD_PCI_READ	= 1 << 0,
} imc_channel_valid_t;

typedef struct imc_channel {
	imc_channel_valid_t	ich_valid;
	imc_stub_t		*ich_desc;
	uint_t			ich_ndimms;
	imc_dimm_t		ich_dimms[IMC_MAX_DIMMPERCHAN];
	uint_t			ich_ntad_offsets;
	uint32_t		ich_tad_offsets_raw[IMC_MAX_TAD_RULES];
	uint64_t		ich_tad_offsets[IMC_MAX_TAD_RULES];
	uint_t			ich_nrankileaves;
	imc_rank_ileave_t	ich_rankileaves[IMC_MAX_RANK_WAYS];
} imc_channel_t;

typedef struct imc_controller {
	imc_stub_t	*icn_main0;
	imc_stub_t	*icn_main1;
	imc_stub_t	*icn_m2m;
	boolean_t	icn_invalid;
	imc_dimm_type_t	icn_dimm_type;
	boolean_t	icn_ecc;
	boolean_t	icn_lockstep;
	boolean_t	icn_closed;
	uint32_t	icn_topo;
	uint_t		icn_nchannels;
	imc_channel_t	icn_channels[IMC_MAX_CHANPERMC];
} imc_mc_t;

typedef enum imc_sad_rule_type {
	IMC_SAD_TYPE_DRAM,
	IMC_SAD_TYPE_MMCFG,
	IMC_SAD_TYPE_NXM
} imc_sad_rule_type_t;

typedef enum imc_sad_rule_imode {
	IMC_SAD_IMODE_8t6,
	IMC_SAD_IMODE_8t6XOR,
	IMC_SAD_IMODE_10t8,
	IMC_SAD_IMODE_14t12,
	IMC_SAD_IMODE_32t30
} imc_sad_rule_imode_t;

typedef enum imc_sad_rule_mod_mode {
	IMC_SAD_MOD_MODE_NONE,
	IMC_SAD_MOD_MODE_45t6,
	IMC_SAD_MOD_MODE_45t8,
	IMC_SAD_MOD_MODE_45t12
} imc_sad_rule_mod_mode_t;

typedef enum imc_sad_rule_mod_type {
	IMC_SAD_MOD_TYPE_NONE,
	IMC_SAD_MOD_TYPE_MOD3,
	IMC_SAD_MOD_TYPE_MOD2_01,
	IMC_SAD_MOD_TYPE_MOD2_12,
	IMC_SAD_MOD_TYPE_MOD2_02
} imc_sad_rule_mod_type_t;

typedef struct imc_sad_mcroute_entry {
	uint8_t	ismce_imc;		/* ID of the target IMC */
	uint8_t	ismce_pchannel;		/* ID of the target physical channel */
} imc_sad_mcroute_entry_t;

typedef struct imc_sad_mcroute_table {
	uint32_t		ismc_raw_mcroute;
	uint_t			ismc_nroutes;
	imc_sad_mcroute_entry_t	ismc_mcroutes[IMC_MAX_SAD_MCROUTES];
} imc_sad_mcroute_table_t;

/*
 * This rule represents a single SAD entry.
 */
typedef struct imc_sad_rule {
	uint32_t		isr_raw_dram;
	uint32_t		isr_raw_interleave;
	boolean_t		isr_enable;
	boolean_t		isr_a7mode;
	boolean_t		isr_need_mod3;
	uint64_t		isr_limit;
	imc_sad_rule_type_t	isr_type;
	imc_sad_rule_imode_t	isr_imode;
	imc_sad_rule_mod_mode_t	isr_mod_mode;
	imc_sad_rule_mod_type_t	isr_mod_type;
	uint_t			isr_ntargets;
	uint8_t			isr_targets[IMC_MAX_SAD_INTERLEAVE];
} imc_sad_rule_t;

typedef enum imc_sad_flags {
	IMC_SAD_MCROUTE_VALID	= 1 << 0,
} imc_sad_flags_t;

typedef enum imc_sad_valid {
	IMC_SAD_V_VALID		= 0,
	IMC_SAD_V_BAD_PCI_READ	= 1 << 0,
	IMC_SAD_V_BAD_MCROUTE	= 1 << 1,
	IMC_SAD_V_BAD_DRAM_ATTR	= 1 << 2,
	IMC_SAD_V_BAD_MOD3	= 1 << 3,
} imc_sad_valid_t;

typedef struct imc_sad {
	imc_sad_flags_t	isad_flags;
	imc_sad_valid_t	isad_valid;
	imc_stub_t	*isad_dram;
	imc_stub_t	*isad_mmio;
	imc_stub_t	*isad_tolh;
	uint64_t	isad_tolm;
	uint64_t	isad_tohm;
	uint_t		isad_nrules;
	imc_sad_rule_t	isad_rules[IMC_MAX_SAD_RULES];
	imc_sad_mcroute_table_t isad_mcroute;
} imc_sad_t;

typedef enum imc_tad_gran {
	IMC_TAD_GRAN_64B = 0,
	IMC_TAD_GRAN_256B,
	IMC_TAD_GRAN_4KB,
	IMC_TAD_GRAN_1GB
} imc_tad_gran_t;

typedef struct imc_tad_rule {
	uint64_t	itr_base;
	uint64_t	itr_limit;
	uint32_t	itr_raw;
	uint32_t	itr_raw_gran;
	uint8_t		itr_sock_way;
	uint8_t		itr_chan_way;
	imc_tad_gran_t	itr_sock_gran;
	imc_tad_gran_t	itr_chan_gran;
	uint_t		itr_ntargets;
	uint8_t		itr_targets[IMC_MAX_TAD_TARGETS];
} imc_tad_rule_t;

typedef enum imc_tad_valid {
	IMC_TAD_V_VALID		= 1 << 0,
	IMC_TAD_V_BAD_PCI_READ	= 1 << 1,
	IMC_TAD_V_BAD_CHAN_GRAN	= 1 << 2
} imc_tad_valid_t;

typedef enum imc_tad_flags {
	IMC_TAD_FLAG_CHANSHIFT	= 1 << 0,
	IMC_TAD_FLAG_CHANHASH	= 1 << 1,
	IMC_TAD_FLAG_MIRROR	= 1 << 2,
	IMC_TAD_FLAG_LOCKSTEP	= 1 << 3
} imc_tad_flags_t;

typedef struct imc_tad {
	imc_tad_valid_t	itad_valid;
	imc_stub_t	*itad_stub;
	imc_tad_flags_t	itad_flags;
	uint_t		itad_nrules;
	imc_tad_rule_t	itad_rules[IMC_MAX_TAD_RULES];
} imc_tad_t;

typedef enum imc_socket_valid {
	IMC_SOCKET_V_VALID	= 0,
	IMC_SOCKET_V_BAD_NODEID	= 1 << 0
} imc_socket_valid_t;

typedef struct imc_socket {
	imc_socket_valid_t	isock_valid;
	uint_t			isock_bus[IMC_MAX_PCIBUSES];
	uint_t			isock_nbus;
	uint_t			isock_gen;
	nvlist_t		*isock_nvl;
	char			*isock_buf;
	size_t			isock_buflen;
	imc_sad_t		isock_sad;
	uint_t			isock_ntad;
	imc_tad_t		isock_tad[IMC_MAX_TAD];
	imc_stub_t		*isock_ubox;
	imc_stub_t		*isock_cpubusno;
	uint32_t		isock_nodeid;
	uint_t			isock_nimc;
	imc_mc_t		isock_imcs[IMC_MAX_IMCPERSOCK];
} imc_socket_t;

typedef struct imc {
	/*
	 * The initial members here are only used in the kernel. This is done to
	 * make it easier for us to be able to define a version of this to use
	 * in testing.
	 */
#ifdef	_KERNEL
	dev_info_t	*imc_dip;
	kmutex_t	imc_lock;
	imc_flags_t	imc_flags;
	const imc_gen_data_t	*imc_gen_data;
	ddi_taskq_t	*imc_taskq;
	uint_t		imc_nscanned;
	avl_tree_t	imc_stubs;
	nvlist_t	*imc_decoder_dump;
	char		*imc_decoder_buf;
	size_t		imc_decoder_len;
#endif	/* _KERNEL */
	imc_gen_t	imc_gen;

	/*
	 * Data about the memory in the system
	 */
	uint_t		imc_nsockets;
	imc_socket_t	imc_sockets[IMC_MAX_SOCKETS];

#ifdef _KERNEL
	/*
	 * The imc_sockets[] array is organized based on increasing PCI Bus ID.
	 * This array maps the socket id that user land thinks of back to the
	 * actual underlying socket in case hardware does not put them in order.
	 */
	imc_socket_t	*imc_spointers[IMC_MAX_SOCKETS];

	/*
	 * Store the IIO global VT-D misc. device. While there are sometimes
	 * multiple on the system, we only keep a single one around.
	 */
	imc_stub_t	*imc_gvtd_misc;
#endif
} imc_t;


/*
 * Decoder failure reasons
 */
typedef enum imc_decode_failure {
	IMC_DECODE_F_NONE = 0,
	/*
	 * Indicates that the memory address fell into a reserved legacy range.
	 * The legacy range index is stored in the failure data.
	 */
	IMC_DECODE_F_LEGACY_RANGE,
	/*
	 * Indicates that we had bad socket data. The socket in question is
	 * noted in the failure data.
	 */
	IMC_DECODE_F_BAD_SOCKET,
	/*
	 * Indicates that we had bad SAD data. The socket the SAD is associated
	 * with is noted in the failure data.
	 */
	IMC_DECODE_F_BAD_SAD,
	/*
	 * Indicates that the address was not contained in conventional, low,
	 * or high memory.
	 */
	IMC_DECODE_F_OUTSIDE_DRAM,
	/*
	 * Indicates that no valid SAD rule was found for the address.
	 */
	IMC_DECODE_F_NO_SAD_RULE,
	/*
	 * Indicates that the SAD interleave target was beyond the valid index.
	 */
	IMC_DECODE_F_BAD_SAD_INTERLEAVE,
	/*
	 * Indicates that the route suggested a remote processor we can't find.
	 */
	IMC_DECODE_F_BAD_REMOTE_MC_ROUTE,
	/*
	 * Indicates that we ended up in a loop trying to find the right socket
	 * to use.
	 */
	IMC_DECODE_F_SAD_SEARCH_LOOP,
	/*
	 * Indicates that we encountered a SAD rule that asked for inconsistent
	 * mod rules.
	 */
	IMC_DECODE_F_SAD_BAD_MOD,
	/*
	 * Indicates that the socket or tad rule we found doesn't actually point
	 * to something that we know about.
	 */
	IMC_DECODE_F_SAD_BAD_SOCKET,
	IMC_DECODE_F_SAD_BAD_TAD,
	/*
	 * Indicates that we could not find a matching tad rule.
	 */
	IMC_DECODE_F_NO_TAD_RULE,
	/*
	 * Indicates that we encountered the TAD channel 3-way interleave that
	 * we don't support.
	 */
	IMC_DECODE_F_TAD_3_ILEAVE,
	/*
	 * Indicates that we had a bad target index.
	 */
	IMC_DECODE_F_TAD_BAD_TARGET_INDEX,
	/*
	 * Indicates that we have a bad channel ID.
	 */
	IMC_DECODE_F_BAD_CHANNEL_ID,
	/*
	 * Indicates that the TAD rule offset in the channel interleave was
	 * incorrect.
	 */
	IMC_DECODE_F_BAD_CHANNEL_TAD_OFFSET,
	/*
	 * We couldn't find a valid rank interleave rule.
	 */
	IMC_DECODE_F_NO_RIR_RULE,
	/*
	 * Indicates that the index of the rank interleaving target was bad.
	 */
	IMC_DECODE_F_BAD_RIR_ILEAVE_TARGET,
	/*
	 * Indicates that the calculated DIMM represents an invalid DIMM that is
	 * beyond the number of supported DIMMS per channel on the platform.
	 */
	IMC_DECODE_F_BAD_DIMM_INDEX,
	/*
	 * Indicates that the specified DIMM is not preset; however, it is a
	 * valid DIMM number.
	 */
	IMC_DECODE_F_DIMM_NOT_PRESENT,
	/*
	 * Indicates that the specified rank on the DIMM is more than the number
	 * of ranks that the DIMM has.
	 */
	IMC_DECODE_F_BAD_DIMM_RANK,
	/*
	 * Indicates that the channel offset is larger than the system address,
	 * meaning that we would end up with an underflow if we continued. The
	 * equivalent is true for the rank address.
	 */
	IMC_DECODE_F_CHANOFF_UNDERFLOW,
	IMC_DECODE_F_RANKOFF_UNDERFLOW,
} imc_decode_failure_t;

/*
 * Decoder state tracking
 */
typedef struct imc_decode_state {
	imc_decode_failure_t	ids_fail;
	uint64_t		ids_fail_data;
	uint64_t		ids_pa;
	uint64_t		ids_chanaddr;
	uint64_t		ids_rankaddr;
	uint32_t		ids_nodeid;
	uint32_t		ids_tadid;
	uint32_t		ids_channelid;
	uint32_t		ids_physrankid;
	uint32_t		ids_dimmid;
	uint32_t		ids_rankid;
	const imc_socket_t	*ids_socket;
	const imc_sad_t		*ids_sad;
	const imc_sad_rule_t	*ids_sad_rule;
	const imc_tad_t		*ids_tad;
	const imc_tad_rule_t	*ids_tad_rule;
	const imc_mc_t		*ids_mc;
	const imc_channel_t	*ids_chan;
	const imc_rank_ileave_t	*ids_rir;
	const imc_dimm_t	*ids_dimm;
} imc_decode_state_t;

#ifdef	_KERNEL

/*
 * Functions needed for the stub drivers.
 */
extern int imc_attach_stub(dev_info_t *, ddi_attach_cmd_t);
extern int imc_detach_stub(dev_info_t *, ddi_detach_cmd_t);

/*
 * Decoder related functions
 */
extern void imc_decoder_init(imc_t *);

extern nvlist_t *imc_dump_decoder(imc_t *);
#else	/* !_KERNEL */
extern boolean_t imc_restore_decoder(nvlist_t *, imc_t *);
#endif	/* _KERNEL */

extern boolean_t imc_decode_pa(const imc_t *, uint64_t, imc_decode_state_t *);


#ifdef __cplusplus
}
#endif

#endif /* _INTEL_IMC_H */