xref: /illumos-gate/usr/src/common/mc/imc/imc_decode.c (revision eb00b1c8a31c2253a353644606388dff5b0e0275)
1*eb00b1c8SRobert Mustacchi /*
2*eb00b1c8SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*eb00b1c8SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*eb00b1c8SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*eb00b1c8SRobert Mustacchi  * 1.0 of the CDDL.
6*eb00b1c8SRobert Mustacchi  *
7*eb00b1c8SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*eb00b1c8SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*eb00b1c8SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*eb00b1c8SRobert Mustacchi  */
11*eb00b1c8SRobert Mustacchi 
12*eb00b1c8SRobert Mustacchi /*
13*eb00b1c8SRobert Mustacchi  * Copyright 2019 Joyent, Inc.
14*eb00b1c8SRobert Mustacchi  */
15*eb00b1c8SRobert Mustacchi 
16*eb00b1c8SRobert Mustacchi /*
17*eb00b1c8SRobert Mustacchi  * Memory decoding logic.
18*eb00b1c8SRobert Mustacchi  *
19*eb00b1c8SRobert Mustacchi  * This file is part of the 'imc' driver on x86. It supports taking a physical
20*eb00b1c8SRobert Mustacchi  * address and determining what the corresponding DIMM is. This is shared
21*eb00b1c8SRobert Mustacchi  * between the kernel and userland for easier testing.
22*eb00b1c8SRobert Mustacchi  *
23*eb00b1c8SRobert Mustacchi  * For more information about the different parts of the decoding process,
24*eb00b1c8SRobert Mustacchi  * please see the file 'uts/i86pc/io/imc/imc.c'.
25*eb00b1c8SRobert Mustacchi  */
26*eb00b1c8SRobert Mustacchi 
27*eb00b1c8SRobert Mustacchi #include <sys/sysmacros.h>
28*eb00b1c8SRobert Mustacchi 
29*eb00b1c8SRobert Mustacchi #ifndef _KERNEL
30*eb00b1c8SRobert Mustacchi #include <stdint.h>
31*eb00b1c8SRobert Mustacchi #include <strings.h>
32*eb00b1c8SRobert Mustacchi #define	BITX(u, h, l)	(((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
33*eb00b1c8SRobert Mustacchi #endif	/* !_KERNEL */
34*eb00b1c8SRobert Mustacchi 
35*eb00b1c8SRobert Mustacchi #include "imc.h"
36*eb00b1c8SRobert Mustacchi 
37*eb00b1c8SRobert Mustacchi /*
38*eb00b1c8SRobert Mustacchi  * Address ranges for decoding system addresses. There are three ranges that
39*eb00b1c8SRobert Mustacchi  * exist on x86, traditional DOS memory (hi 640 KiB), low memory, and high
40*eb00b1c8SRobert Mustacchi  * memory. Low memory always starts at 1 MiB and high memory always starts at 4
41*eb00b1c8SRobert Mustacchi  * GiB. The upper bounds of these ranges is based on registers on the system.
42*eb00b1c8SRobert Mustacchi  */
43*eb00b1c8SRobert Mustacchi #define	IMC_DECODE_CONV_BASE	0UL
44*eb00b1c8SRobert Mustacchi #define	IMC_DECODE_CONV_MAX	0x00009ffffULL	/* 640 KiB - 1 */
45*eb00b1c8SRobert Mustacchi #define	IMC_DECODE_LOW_BASE	0x000100000ULL	/* 1 M */
46*eb00b1c8SRobert Mustacchi #define	IMC_DECODE_HIGH_BASE	0x100000000ULL /* 4 GiB */
47*eb00b1c8SRobert Mustacchi 
48*eb00b1c8SRobert Mustacchi typedef struct imc_legacy_range {
49*eb00b1c8SRobert Mustacchi 	uint64_t	ilr_base;
50*eb00b1c8SRobert Mustacchi 	size_t		ilr_len;
51*eb00b1c8SRobert Mustacchi 	const char	*ilr_desc;
52*eb00b1c8SRobert Mustacchi } imc_legacy_range_t;
53*eb00b1c8SRobert Mustacchi 
54*eb00b1c8SRobert Mustacchi /*
55*eb00b1c8SRobert Mustacchi  * These represent regions of memory that are reserved for use and will not be
56*eb00b1c8SRobert Mustacchi  * decoded by DRAM.
57*eb00b1c8SRobert Mustacchi  */
58*eb00b1c8SRobert Mustacchi static imc_legacy_range_t imc_legacy_ranges[] = {
59*eb00b1c8SRobert Mustacchi 	{ 0x00000A0000ULL,	128 * 1024,	"VGA" },
60*eb00b1c8SRobert Mustacchi 	{ 0x00000C0000ULL,	256 * 1024,	"PAM" },
61*eb00b1c8SRobert Mustacchi 	{ 0x0000F00000ULL,	1024 * 1024,	"Reserved" },
62*eb00b1c8SRobert Mustacchi 	{ 0x00FE000000ULL,	32 * 1024 * 1024, "Unknown" },
63*eb00b1c8SRobert Mustacchi 	{ 0x00FF000000ULL,	16 * 1024 * 1024, "Firmware" },
64*eb00b1c8SRobert Mustacchi 	{ 0x00FED20000ULL,	384 * 1024,	"TXT" },
65*eb00b1c8SRobert Mustacchi 	{ 0x00FED00000ULL,	1024 * 1024,	"PCH" },
66*eb00b1c8SRobert Mustacchi 	{ 0x00FEC00000ULL,	1024 * 1024,	"IOAPIC" },
67*eb00b1c8SRobert Mustacchi 	{ 0x00FEB80000ULL,	512 * 1024,	"Reserved" },
68*eb00b1c8SRobert Mustacchi 	{ 0x00FEB00000ULL,	64 * 1024,	"Reserved" }
69*eb00b1c8SRobert Mustacchi };
70*eb00b1c8SRobert Mustacchi 
71*eb00b1c8SRobert Mustacchi /*
72*eb00b1c8SRobert Mustacchi  * Determine whether or not this address is in one of the reserved regions or if
73*eb00b1c8SRobert Mustacchi  * it falls outside of the explicit DRAM ranges.
74*eb00b1c8SRobert Mustacchi  */
75*eb00b1c8SRobert Mustacchi static boolean_t
imc_decode_addr_resvd(const imc_t * imc,imc_decode_state_t * dec)76*eb00b1c8SRobert Mustacchi imc_decode_addr_resvd(const imc_t *imc, imc_decode_state_t *dec)
77*eb00b1c8SRobert Mustacchi {
78*eb00b1c8SRobert Mustacchi 	uint_t i;
79*eb00b1c8SRobert Mustacchi 	const imc_sad_t *sad;
80*eb00b1c8SRobert Mustacchi 
81*eb00b1c8SRobert Mustacchi 	for (i = 0; i < ARRAY_SIZE(imc_legacy_ranges); i++) {
82*eb00b1c8SRobert Mustacchi 		uint64_t end = imc_legacy_ranges[i].ilr_base +
83*eb00b1c8SRobert Mustacchi 		    imc_legacy_ranges[i].ilr_len;
84*eb00b1c8SRobert Mustacchi 
85*eb00b1c8SRobert Mustacchi 		if (dec->ids_pa >= imc_legacy_ranges[i].ilr_base &&
86*eb00b1c8SRobert Mustacchi 		    dec->ids_pa < end) {
87*eb00b1c8SRobert Mustacchi 			dec->ids_fail = IMC_DECODE_F_LEGACY_RANGE;
88*eb00b1c8SRobert Mustacchi 			dec->ids_fail_data = i;
89*eb00b1c8SRobert Mustacchi 			return (B_TRUE);
90*eb00b1c8SRobert Mustacchi 		}
91*eb00b1c8SRobert Mustacchi 	}
92*eb00b1c8SRobert Mustacchi 
93*eb00b1c8SRobert Mustacchi 	/*
94*eb00b1c8SRobert Mustacchi 	 * For checking and determining whether or not we fit in DRAM, we need
95*eb00b1c8SRobert Mustacchi 	 * to check against the top of low memory and the top of high memory.
96*eb00b1c8SRobert Mustacchi 	 * While we technically have this information on a per-socket basis, we
97*eb00b1c8SRobert Mustacchi 	 * have to rely on the fact that both processors have the same
98*eb00b1c8SRobert Mustacchi 	 * information. A requirement which if not true, would lead to chaos
99*eb00b1c8SRobert Mustacchi 	 * depending on what socket we're running on.
100*eb00b1c8SRobert Mustacchi 	 */
101*eb00b1c8SRobert Mustacchi 	sad = &imc->imc_sockets[0].isock_sad;
102*eb00b1c8SRobert Mustacchi 	if (sad->isad_valid != IMC_SAD_V_VALID) {
103*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_BAD_SAD;
104*eb00b1c8SRobert Mustacchi 		return (B_TRUE);
105*eb00b1c8SRobert Mustacchi 	}
106*eb00b1c8SRobert Mustacchi 
107*eb00b1c8SRobert Mustacchi 	/*
108*eb00b1c8SRobert Mustacchi 	 * An address may fall into three ranges. It may fall into conventional
109*eb00b1c8SRobert Mustacchi 	 * memory. It may fall into low memory. It may fall into high memory.
110*eb00b1c8SRobert Mustacchi 	 * The conventional memory range is inclusive at the top. The others
111*eb00b1c8SRobert Mustacchi 	 * have been translated such that they are uniformly exclusive at the
112*eb00b1c8SRobert Mustacchi 	 * top. Because the bottom of conventional memory is at zero, the
113*eb00b1c8SRobert Mustacchi 	 * compiler will be angry if we compare against IMC_DECODE_CONV_BASE as
114*eb00b1c8SRobert Mustacchi 	 * it is always true.
115*eb00b1c8SRobert Mustacchi 	 */
116*eb00b1c8SRobert Mustacchi 	if (dec->ids_pa <= IMC_DECODE_CONV_MAX) {
117*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
118*eb00b1c8SRobert Mustacchi 	}
119*eb00b1c8SRobert Mustacchi 
120*eb00b1c8SRobert Mustacchi 	if (dec->ids_pa >= IMC_DECODE_LOW_BASE &&
121*eb00b1c8SRobert Mustacchi 	    dec->ids_pa < sad->isad_tolm) {
122*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
123*eb00b1c8SRobert Mustacchi 	}
124*eb00b1c8SRobert Mustacchi 
125*eb00b1c8SRobert Mustacchi 	if (dec->ids_pa >= IMC_DECODE_HIGH_BASE &&
126*eb00b1c8SRobert Mustacchi 	    dec->ids_pa < sad->isad_tohm) {
127*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
128*eb00b1c8SRobert Mustacchi 	}
129*eb00b1c8SRobert Mustacchi 
130*eb00b1c8SRobert Mustacchi 	/*
131*eb00b1c8SRobert Mustacchi 	 * Memory fell outside of the valid range. It's not for us.
132*eb00b1c8SRobert Mustacchi 	 */
133*eb00b1c8SRobert Mustacchi 	dec->ids_fail = IMC_DECODE_F_OUTSIDE_DRAM;
134*eb00b1c8SRobert Mustacchi 	return (B_TRUE);
135*eb00b1c8SRobert Mustacchi }
136*eb00b1c8SRobert Mustacchi 
137*eb00b1c8SRobert Mustacchi static uint_t
imc_decode_sad_interleave(const imc_sad_rule_t * rule,uint64_t pa)138*eb00b1c8SRobert Mustacchi imc_decode_sad_interleave(const imc_sad_rule_t *rule, uint64_t pa)
139*eb00b1c8SRobert Mustacchi {
140*eb00b1c8SRobert Mustacchi 	uint_t itgt = 0;
141*eb00b1c8SRobert Mustacchi 
142*eb00b1c8SRobert Mustacchi 	switch (rule->isr_imode) {
143*eb00b1c8SRobert Mustacchi 	case IMC_SAD_IMODE_8t6:
144*eb00b1c8SRobert Mustacchi 		if (rule->isr_a7mode) {
145*eb00b1c8SRobert Mustacchi 			itgt = BITX(pa, 9, 9);
146*eb00b1c8SRobert Mustacchi 			itgt |= (BITX(pa, 8, 7) << 1);
147*eb00b1c8SRobert Mustacchi 		} else {
148*eb00b1c8SRobert Mustacchi 			itgt = BITX(pa, 8, 6);
149*eb00b1c8SRobert Mustacchi 		}
150*eb00b1c8SRobert Mustacchi 		break;
151*eb00b1c8SRobert Mustacchi 	case IMC_SAD_IMODE_8t6XOR:
152*eb00b1c8SRobert Mustacchi 		if (rule->isr_a7mode) {
153*eb00b1c8SRobert Mustacchi 			itgt = BITX(pa, 9, 9);
154*eb00b1c8SRobert Mustacchi 			itgt |= (BITX(pa, 8, 7) << 1);
155*eb00b1c8SRobert Mustacchi 		} else {
156*eb00b1c8SRobert Mustacchi 			itgt = BITX(pa, 8, 6);
157*eb00b1c8SRobert Mustacchi 		}
158*eb00b1c8SRobert Mustacchi 		itgt ^= BITX(pa, 18, 16);
159*eb00b1c8SRobert Mustacchi 		break;
160*eb00b1c8SRobert Mustacchi 	case IMC_SAD_IMODE_10t8:
161*eb00b1c8SRobert Mustacchi 		itgt = BITX(pa, 10, 8);
162*eb00b1c8SRobert Mustacchi 		break;
163*eb00b1c8SRobert Mustacchi 	case IMC_SAD_IMODE_14t12:
164*eb00b1c8SRobert Mustacchi 		itgt = BITX(pa, 14, 12);
165*eb00b1c8SRobert Mustacchi 		break;
166*eb00b1c8SRobert Mustacchi 	case IMC_SAD_IMODE_32t30:
167*eb00b1c8SRobert Mustacchi 		itgt = BITX(pa, 32, 30);
168*eb00b1c8SRobert Mustacchi 		break;
169*eb00b1c8SRobert Mustacchi 	}
170*eb00b1c8SRobert Mustacchi 
171*eb00b1c8SRobert Mustacchi 	return (itgt);
172*eb00b1c8SRobert Mustacchi }
173*eb00b1c8SRobert Mustacchi 
174*eb00b1c8SRobert Mustacchi /*
175*eb00b1c8SRobert Mustacchi  * Use the system address decoder to try and find a valid SAD entry for this
176*eb00b1c8SRobert Mustacchi  * address. We always use socket zero's SAD as the SAD rules should be the same
177*eb00b1c8SRobert Mustacchi  * between the different sockets.
178*eb00b1c8SRobert Mustacchi  */
179*eb00b1c8SRobert Mustacchi static boolean_t
imc_decode_sad(const imc_t * imc,imc_decode_state_t * dec)180*eb00b1c8SRobert Mustacchi imc_decode_sad(const imc_t *imc, imc_decode_state_t *dec)
181*eb00b1c8SRobert Mustacchi {
182*eb00b1c8SRobert Mustacchi 	uint_t i, ileaveidx;
183*eb00b1c8SRobert Mustacchi 	uint8_t ileavetgt;
184*eb00b1c8SRobert Mustacchi 	uint32_t nodeid, tadid, channelid;
185*eb00b1c8SRobert Mustacchi 	uint64_t base;
186*eb00b1c8SRobert Mustacchi 	const imc_socket_t *socket = &imc->imc_sockets[0];
187*eb00b1c8SRobert Mustacchi 	const imc_sad_t *sad = &socket->isock_sad;
188*eb00b1c8SRobert Mustacchi 	const imc_sad_rule_t *rule;
189*eb00b1c8SRobert Mustacchi 	boolean_t loop = B_FALSE;
190*eb00b1c8SRobert Mustacchi 
191*eb00b1c8SRobert Mustacchi 	/*
192*eb00b1c8SRobert Mustacchi 	 * Note, all SAD rules have been adjusted so that they are uniformly
193*eb00b1c8SRobert Mustacchi 	 * exclusive.
194*eb00b1c8SRobert Mustacchi 	 */
195*eb00b1c8SRobert Mustacchi start:
196*eb00b1c8SRobert Mustacchi 	for (rule = NULL, i = 0, base = 0; i < sad->isad_nrules; i++) {
197*eb00b1c8SRobert Mustacchi 		rule = &sad->isad_rules[i];
198*eb00b1c8SRobert Mustacchi 
199*eb00b1c8SRobert Mustacchi 		if (rule->isr_enable && dec->ids_pa >= base &&
200*eb00b1c8SRobert Mustacchi 		    dec->ids_pa < rule->isr_limit) {
201*eb00b1c8SRobert Mustacchi 			break;
202*eb00b1c8SRobert Mustacchi 		}
203*eb00b1c8SRobert Mustacchi 
204*eb00b1c8SRobert Mustacchi 		base = rule->isr_limit;
205*eb00b1c8SRobert Mustacchi 	}
206*eb00b1c8SRobert Mustacchi 
207*eb00b1c8SRobert Mustacchi 	if (rule == NULL || i == sad->isad_nrules) {
208*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_NO_SAD_RULE;
209*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
210*eb00b1c8SRobert Mustacchi 	}
211*eb00b1c8SRobert Mustacchi 
212*eb00b1c8SRobert Mustacchi 	/*
213*eb00b1c8SRobert Mustacchi 	 * Store the SAD rule in the decode information for debugging's sake.
214*eb00b1c8SRobert Mustacchi 	 */
215*eb00b1c8SRobert Mustacchi 	dec->ids_sad = sad;
216*eb00b1c8SRobert Mustacchi 	dec->ids_sad_rule = rule;
217*eb00b1c8SRobert Mustacchi 
218*eb00b1c8SRobert Mustacchi 	/*
219*eb00b1c8SRobert Mustacchi 	 * We have found a SAD rule. We now need to transform that into the
220*eb00b1c8SRobert Mustacchi 	 * corresponding target based on its mode, etc. The way we do this
221*eb00b1c8SRobert Mustacchi 	 * varies based on the generation.
222*eb00b1c8SRobert Mustacchi 	 *
223*eb00b1c8SRobert Mustacchi 	 * The first thing we need to do is to figure out the target in the
224*eb00b1c8SRobert Mustacchi 	 * interleave list.
225*eb00b1c8SRobert Mustacchi 	 */
226*eb00b1c8SRobert Mustacchi 	ileaveidx = imc_decode_sad_interleave(rule, dec->ids_pa);
227*eb00b1c8SRobert Mustacchi 	if (ileaveidx >= rule->isr_ntargets) {
228*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_BAD_SAD_INTERLEAVE;
229*eb00b1c8SRobert Mustacchi 		dec->ids_fail_data = ileaveidx;
230*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
231*eb00b1c8SRobert Mustacchi 	}
232*eb00b1c8SRobert Mustacchi 	ileavetgt = rule->isr_targets[ileaveidx];
233*eb00b1c8SRobert Mustacchi 	if (imc->imc_gen >= IMC_GEN_SKYLAKE &&
234*eb00b1c8SRobert Mustacchi 	    IMC_SAD_ILEAVE_SKX_LOCAL(ileavetgt) == 0) {
235*eb00b1c8SRobert Mustacchi 		/*
236*eb00b1c8SRobert Mustacchi 		 * If we're in this case, the interleave rule said we had a
237*eb00b1c8SRobert Mustacchi 		 * remote target. That means we need to find the correct SAD
238*eb00b1c8SRobert Mustacchi 		 * based on the Node ID and then do all of this over again.
239*eb00b1c8SRobert Mustacchi 		 */
240*eb00b1c8SRobert Mustacchi 		nodeid = IMC_SAD_ILEAVE_SKX_TARGET(ileavetgt);
241*eb00b1c8SRobert Mustacchi 
242*eb00b1c8SRobert Mustacchi 		if (loop) {
243*eb00b1c8SRobert Mustacchi 			dec->ids_fail = IMC_DECODE_F_SAD_SEARCH_LOOP;
244*eb00b1c8SRobert Mustacchi 			return (B_FALSE);
245*eb00b1c8SRobert Mustacchi 		}
246*eb00b1c8SRobert Mustacchi 
247*eb00b1c8SRobert Mustacchi 		for (i = 0; i < imc->imc_nsockets; i++) {
248*eb00b1c8SRobert Mustacchi 			if (imc->imc_sockets[i].isock_valid ==
249*eb00b1c8SRobert Mustacchi 			    IMC_SOCKET_V_VALID &&
250*eb00b1c8SRobert Mustacchi 			    imc->imc_sockets[i].isock_nodeid == nodeid) {
251*eb00b1c8SRobert Mustacchi 				socket = &imc->imc_sockets[i];
252*eb00b1c8SRobert Mustacchi 				sad = &imc->imc_sockets[i].isock_sad;
253*eb00b1c8SRobert Mustacchi 				loop = B_TRUE;
254*eb00b1c8SRobert Mustacchi 				goto start;
255*eb00b1c8SRobert Mustacchi 			}
256*eb00b1c8SRobert Mustacchi 		}
257*eb00b1c8SRobert Mustacchi 
258*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_BAD_REMOTE_MC_ROUTE;
259*eb00b1c8SRobert Mustacchi 		dec->ids_fail_data = nodeid;
260*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
261*eb00b1c8SRobert Mustacchi 	}
262*eb00b1c8SRobert Mustacchi 
263*eb00b1c8SRobert Mustacchi 	/*
264*eb00b1c8SRobert Mustacchi 	 * On some platforms we need to derive the target channel based on the
265*eb00b1c8SRobert Mustacchi 	 * physical address and additional rules in the SAD. If we do, do that
266*eb00b1c8SRobert Mustacchi 	 * here. The idea is that this may overrule the memory channel route
267*eb00b1c8SRobert Mustacchi 	 * table target that was determined from the SAD rule.
268*eb00b1c8SRobert Mustacchi 	 */
269*eb00b1c8SRobert Mustacchi 	if (rule->isr_need_mod3) {
270*eb00b1c8SRobert Mustacchi 		uint64_t addr;
271*eb00b1c8SRobert Mustacchi 		uint8_t channel;
272*eb00b1c8SRobert Mustacchi 
273*eb00b1c8SRobert Mustacchi 		switch (rule->isr_mod_mode) {
274*eb00b1c8SRobert Mustacchi 		case IMC_SAD_MOD_MODE_45t6:
275*eb00b1c8SRobert Mustacchi 			addr = dec->ids_pa >> 6;
276*eb00b1c8SRobert Mustacchi 			break;
277*eb00b1c8SRobert Mustacchi 		case IMC_SAD_MOD_MODE_45t8:
278*eb00b1c8SRobert Mustacchi 			addr = dec->ids_pa >> 8;
279*eb00b1c8SRobert Mustacchi 			break;
280*eb00b1c8SRobert Mustacchi 		case IMC_SAD_MOD_MODE_45t12:
281*eb00b1c8SRobert Mustacchi 			addr = dec->ids_pa >> 12;
282*eb00b1c8SRobert Mustacchi 			break;
283*eb00b1c8SRobert Mustacchi 		default:
284*eb00b1c8SRobert Mustacchi 			dec->ids_fail = IMC_DECODE_F_SAD_BAD_MOD;
285*eb00b1c8SRobert Mustacchi 			return (B_FALSE);
286*eb00b1c8SRobert Mustacchi 		}
287*eb00b1c8SRobert Mustacchi 
288*eb00b1c8SRobert Mustacchi 		switch (rule->isr_mod_type) {
289*eb00b1c8SRobert Mustacchi 		case IMC_SAD_MOD_TYPE_MOD3:
290*eb00b1c8SRobert Mustacchi 			channel = (addr % 3) << 1;
291*eb00b1c8SRobert Mustacchi 			channel |= ileavetgt & 1;
292*eb00b1c8SRobert Mustacchi 			break;
293*eb00b1c8SRobert Mustacchi 		case IMC_SAD_MOD_TYPE_MOD2_01:
294*eb00b1c8SRobert Mustacchi 			channel = (addr % 2) << 1;
295*eb00b1c8SRobert Mustacchi 			channel |= ileavetgt & 1;
296*eb00b1c8SRobert Mustacchi 			break;
297*eb00b1c8SRobert Mustacchi 		case IMC_SAD_MOD_TYPE_MOD2_12:
298*eb00b1c8SRobert Mustacchi 			channel = (addr % 2) << 2;
299*eb00b1c8SRobert Mustacchi 			channel |= (~addr % 2) << 1;
300*eb00b1c8SRobert Mustacchi 			channel |= ileavetgt & 1;
301*eb00b1c8SRobert Mustacchi 			break;
302*eb00b1c8SRobert Mustacchi 		case IMC_SAD_MOD_TYPE_MOD2_02:
303*eb00b1c8SRobert Mustacchi 			channel = (addr % 2) << 2;
304*eb00b1c8SRobert Mustacchi 			channel |= ileavetgt & 1;
305*eb00b1c8SRobert Mustacchi 			break;
306*eb00b1c8SRobert Mustacchi 		default:
307*eb00b1c8SRobert Mustacchi 			dec->ids_fail = IMC_DECODE_F_SAD_BAD_MOD;
308*eb00b1c8SRobert Mustacchi 			return (B_FALSE);
309*eb00b1c8SRobert Mustacchi 		}
310*eb00b1c8SRobert Mustacchi 
311*eb00b1c8SRobert Mustacchi 		ileavetgt = channel;
312*eb00b1c8SRobert Mustacchi 	}
313*eb00b1c8SRobert Mustacchi 
314*eb00b1c8SRobert Mustacchi 	switch (imc->imc_gen) {
315*eb00b1c8SRobert Mustacchi 	case IMC_GEN_SANDY:
316*eb00b1c8SRobert Mustacchi 		/*
317*eb00b1c8SRobert Mustacchi 		 * Sandy Bridge systems only have a single home agent, so the
318*eb00b1c8SRobert Mustacchi 		 * interleave target is always the node id.
319*eb00b1c8SRobert Mustacchi 		 */
320*eb00b1c8SRobert Mustacchi 		nodeid = ileavetgt;
321*eb00b1c8SRobert Mustacchi 		tadid = 0;
322*eb00b1c8SRobert Mustacchi 		channelid = UINT32_MAX;
323*eb00b1c8SRobert Mustacchi 		break;
324*eb00b1c8SRobert Mustacchi 	case IMC_GEN_IVY:
325*eb00b1c8SRobert Mustacchi 	case IMC_GEN_HASWELL:
326*eb00b1c8SRobert Mustacchi 	case IMC_GEN_BROADWELL:
327*eb00b1c8SRobert Mustacchi 		/*
328*eb00b1c8SRobert Mustacchi 		 * On these generations, the interleave NodeID in the SAD
329*eb00b1c8SRobert Mustacchi 		 * encodes both the nodeid and the home agent ID that we care
330*eb00b1c8SRobert Mustacchi 		 * about.
331*eb00b1c8SRobert Mustacchi 		 */
332*eb00b1c8SRobert Mustacchi 		nodeid = IMC_NODEID_IVY_BRD_UPPER(ileavetgt) |
333*eb00b1c8SRobert Mustacchi 		    IMC_NODEID_IVY_BRD_LOWER(ileavetgt);
334*eb00b1c8SRobert Mustacchi 		tadid = IMC_NODEID_IVY_BRD_HA(ileavetgt);
335*eb00b1c8SRobert Mustacchi 		channelid = UINT32_MAX;
336*eb00b1c8SRobert Mustacchi 		break;
337*eb00b1c8SRobert Mustacchi 	case IMC_GEN_SKYLAKE:
338*eb00b1c8SRobert Mustacchi 		/*
339*eb00b1c8SRobert Mustacchi 		 * On Skylake generation systems we take the interleave target
340*eb00b1c8SRobert Mustacchi 		 * and use that to look up both the memory controller and the
341*eb00b1c8SRobert Mustacchi 		 * physical channel in the route table. The nodeid is already
342*eb00b1c8SRobert Mustacchi 		 * known because its SAD rules redirect us.
343*eb00b1c8SRobert Mustacchi 		 */
344*eb00b1c8SRobert Mustacchi 		nodeid = socket->isock_nodeid;
345*eb00b1c8SRobert Mustacchi 		if (ileavetgt > IMC_SAD_ILEAVE_SKX_MAX) {
346*eb00b1c8SRobert Mustacchi 			dec->ids_fail = IMC_DECODE_F_BAD_SAD_INTERLEAVE;
347*eb00b1c8SRobert Mustacchi 			dec->ids_fail_data = ileavetgt;
348*eb00b1c8SRobert Mustacchi 			return (B_FALSE);
349*eb00b1c8SRobert Mustacchi 		}
350*eb00b1c8SRobert Mustacchi 		ileavetgt = IMC_SAD_ILEAVE_SKX_TARGET(ileavetgt);
351*eb00b1c8SRobert Mustacchi 		if (ileavetgt > sad->isad_mcroute.ismc_nroutes) {
352*eb00b1c8SRobert Mustacchi 			dec->ids_fail = IMC_DECODE_F_BAD_SAD_INTERLEAVE;
353*eb00b1c8SRobert Mustacchi 			dec->ids_fail_data = ileavetgt;
354*eb00b1c8SRobert Mustacchi 			return (B_FALSE);
355*eb00b1c8SRobert Mustacchi 		}
356*eb00b1c8SRobert Mustacchi 		tadid = sad->isad_mcroute.ismc_mcroutes[ileavetgt].ismce_imc;
357*eb00b1c8SRobert Mustacchi 		channelid =
358*eb00b1c8SRobert Mustacchi 		    sad->isad_mcroute.ismc_mcroutes[ileavetgt].ismce_pchannel;
359*eb00b1c8SRobert Mustacchi 		break;
360*eb00b1c8SRobert Mustacchi 	default:
361*eb00b1c8SRobert Mustacchi 		nodeid = tadid = channelid = UINT32_MAX;
362*eb00b1c8SRobert Mustacchi 		break;
363*eb00b1c8SRobert Mustacchi 	}
364*eb00b1c8SRobert Mustacchi 
365*eb00b1c8SRobert Mustacchi 	/*
366*eb00b1c8SRobert Mustacchi 	 * Map to the correct socket based on the nodeid. Make sure that we have
367*eb00b1c8SRobert Mustacchi 	 * a valid TAD.
368*eb00b1c8SRobert Mustacchi 	 */
369*eb00b1c8SRobert Mustacchi 	dec->ids_socket = NULL;
370*eb00b1c8SRobert Mustacchi 	for (i = 0; i < imc->imc_nsockets; i++) {
371*eb00b1c8SRobert Mustacchi 		if (imc->imc_sockets[i].isock_nodeid == nodeid) {
372*eb00b1c8SRobert Mustacchi 			dec->ids_socket = &imc->imc_sockets[i];
373*eb00b1c8SRobert Mustacchi 			break;
374*eb00b1c8SRobert Mustacchi 		}
375*eb00b1c8SRobert Mustacchi 	}
376*eb00b1c8SRobert Mustacchi 	if (dec->ids_socket == NULL) {
377*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_SAD_BAD_SOCKET;
378*eb00b1c8SRobert Mustacchi 		dec->ids_fail_data = nodeid;
379*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
380*eb00b1c8SRobert Mustacchi 	}
381*eb00b1c8SRobert Mustacchi 
382*eb00b1c8SRobert Mustacchi 	if (tadid >= dec->ids_socket->isock_ntad) {
383*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_SAD_BAD_TAD;
384*eb00b1c8SRobert Mustacchi 		dec->ids_fail_data = tadid;
385*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
386*eb00b1c8SRobert Mustacchi 	}
387*eb00b1c8SRobert Mustacchi 
388*eb00b1c8SRobert Mustacchi 	dec->ids_nodeid = nodeid;
389*eb00b1c8SRobert Mustacchi 	dec->ids_tadid = tadid;
390*eb00b1c8SRobert Mustacchi 	dec->ids_channelid = channelid;
391*eb00b1c8SRobert Mustacchi 	dec->ids_tad = &dec->ids_socket->isock_tad[tadid];
392*eb00b1c8SRobert Mustacchi 	dec->ids_mc = &dec->ids_socket->isock_imcs[tadid];
393*eb00b1c8SRobert Mustacchi 
394*eb00b1c8SRobert Mustacchi 	return (B_TRUE);
395*eb00b1c8SRobert Mustacchi }
396*eb00b1c8SRobert Mustacchi 
397*eb00b1c8SRobert Mustacchi /*
398*eb00b1c8SRobert Mustacchi  * For Sandy Bridge through Broadwell we need to decode the memory channel that
399*eb00b1c8SRobert Mustacchi  * we're targeting. This is determined based on the number of ways that the
400*eb00b1c8SRobert Mustacchi  * socket and channel are supposed to be interleaved. The TAD has a target
401*eb00b1c8SRobert Mustacchi  * channel list sitting with the TAD rule. To figure out the appropriate index,
402*eb00b1c8SRobert Mustacchi  * the algorithm is roughly:
403*eb00b1c8SRobert Mustacchi  *
404*eb00b1c8SRobert Mustacchi  *    idx = [(dec->ids_pa >> 6) / socket-ways] % channel-ways
405*eb00b1c8SRobert Mustacchi  *
406*eb00b1c8SRobert Mustacchi  * The shift by six, comes from taking the number of bits that are in theory in
407*eb00b1c8SRobert Mustacchi  * the cache line size. Of course, if things were this simple, that'd be great.
408*eb00b1c8SRobert Mustacchi  * The first complication is a7mode / MCChanShiftUpEnable. When this is enabled,
409*eb00b1c8SRobert Mustacchi  * more cache lines are used for this. The next complication comes when the
410*eb00b1c8SRobert Mustacchi  * feature MCChanHashEn is enabled. This means that we have to hash the
411*eb00b1c8SRobert Mustacchi  * resulting address before we do the modulus based on the number of channel
412*eb00b1c8SRobert Mustacchi  * ways.
413*eb00b1c8SRobert Mustacchi  *
414*eb00b1c8SRobert Mustacchi  * The last, and most complicated problem is when the number of channel ways is
415*eb00b1c8SRobert Mustacchi  * set to three. When this is the case, the base address of the range may not
416*eb00b1c8SRobert Mustacchi  * actually start at index zero. The nominal solution is to use the offset
417*eb00b1c8SRobert Mustacchi  * that's programmed on a per-channel basis to offset the system address.
418*eb00b1c8SRobert Mustacchi  * However, to get that information we would have to know what channel we're on,
419*eb00b1c8SRobert Mustacchi  * which is what we're trying to figure out. Regretfully, proclaim that we can't
420*eb00b1c8SRobert Mustacchi  * in this case.
421*eb00b1c8SRobert Mustacchi  */
422*eb00b1c8SRobert Mustacchi static boolean_t
imc_decode_tad_channel(const imc_t * imc,imc_decode_state_t * dec)423*eb00b1c8SRobert Mustacchi imc_decode_tad_channel(const imc_t *imc, imc_decode_state_t *dec)
424*eb00b1c8SRobert Mustacchi {
425*eb00b1c8SRobert Mustacchi 	uint64_t index;
426*eb00b1c8SRobert Mustacchi 	const imc_tad_rule_t *rule = dec->ids_tad_rule;
427*eb00b1c8SRobert Mustacchi 
428*eb00b1c8SRobert Mustacchi 	index = dec->ids_pa >> 6;
429*eb00b1c8SRobert Mustacchi 	if ((dec->ids_tad->itad_flags & IMC_TAD_FLAG_CHANSHIFT) != 0) {
430*eb00b1c8SRobert Mustacchi 		index = index >> 1;
431*eb00b1c8SRobert Mustacchi 	}
432*eb00b1c8SRobert Mustacchi 
433*eb00b1c8SRobert Mustacchi 	/*
434*eb00b1c8SRobert Mustacchi 	 * When performing a socket way equals three comparison, this would not
435*eb00b1c8SRobert Mustacchi 	 * work.
436*eb00b1c8SRobert Mustacchi 	 */
437*eb00b1c8SRobert Mustacchi 	index = index / rule->itr_sock_way;
438*eb00b1c8SRobert Mustacchi 
439*eb00b1c8SRobert Mustacchi 	if ((dec->ids_tad->itad_flags & IMC_TAD_FLAG_CHANHASH) != 0) {
440*eb00b1c8SRobert Mustacchi 		uint_t i;
441*eb00b1c8SRobert Mustacchi 		for (i = 12; i < 28; i += 2) {
442*eb00b1c8SRobert Mustacchi 			uint64_t shift = (dec->ids_pa >> i) & 0x3;
443*eb00b1c8SRobert Mustacchi 			index ^= shift;
444*eb00b1c8SRobert Mustacchi 		}
445*eb00b1c8SRobert Mustacchi 	}
446*eb00b1c8SRobert Mustacchi 
447*eb00b1c8SRobert Mustacchi 	index %= rule->itr_chan_way;
448*eb00b1c8SRobert Mustacchi 	if (index >= rule->itr_ntargets) {
449*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_TAD_BAD_TARGET_INDEX;
450*eb00b1c8SRobert Mustacchi 		dec->ids_fail_data = index;
451*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
452*eb00b1c8SRobert Mustacchi 	}
453*eb00b1c8SRobert Mustacchi 
454*eb00b1c8SRobert Mustacchi 	dec->ids_channelid = rule->itr_targets[index];
455*eb00b1c8SRobert Mustacchi 	return (B_TRUE);
456*eb00b1c8SRobert Mustacchi }
457*eb00b1c8SRobert Mustacchi 
458*eb00b1c8SRobert Mustacchi static uint_t
imc_tad_gran_to_shift(const imc_tad_t * tad,imc_tad_gran_t gran)459*eb00b1c8SRobert Mustacchi imc_tad_gran_to_shift(const imc_tad_t *tad, imc_tad_gran_t gran)
460*eb00b1c8SRobert Mustacchi {
461*eb00b1c8SRobert Mustacchi 	uint_t shift = 0;
462*eb00b1c8SRobert Mustacchi 
463*eb00b1c8SRobert Mustacchi 	switch (gran) {
464*eb00b1c8SRobert Mustacchi 	case IMC_TAD_GRAN_64B:
465*eb00b1c8SRobert Mustacchi 		shift = 6;
466*eb00b1c8SRobert Mustacchi 		if ((tad->itad_flags & IMC_TAD_FLAG_CHANSHIFT) != 0) {
467*eb00b1c8SRobert Mustacchi 			shift++;
468*eb00b1c8SRobert Mustacchi 		}
469*eb00b1c8SRobert Mustacchi 		break;
470*eb00b1c8SRobert Mustacchi 	case IMC_TAD_GRAN_256B:
471*eb00b1c8SRobert Mustacchi 		shift = 8;
472*eb00b1c8SRobert Mustacchi 		break;
473*eb00b1c8SRobert Mustacchi 	case IMC_TAD_GRAN_4KB:
474*eb00b1c8SRobert Mustacchi 		shift = 12;
475*eb00b1c8SRobert Mustacchi 		break;
476*eb00b1c8SRobert Mustacchi 	case IMC_TAD_GRAN_1GB:
477*eb00b1c8SRobert Mustacchi 		shift = 30;
478*eb00b1c8SRobert Mustacchi 		break;
479*eb00b1c8SRobert Mustacchi 	}
480*eb00b1c8SRobert Mustacchi 
481*eb00b1c8SRobert Mustacchi 	return (shift);
482*eb00b1c8SRobert Mustacchi }
483*eb00b1c8SRobert Mustacchi 
484*eb00b1c8SRobert Mustacchi static boolean_t
imc_decode_tad(const imc_t * imc,imc_decode_state_t * dec)485*eb00b1c8SRobert Mustacchi imc_decode_tad(const imc_t *imc, imc_decode_state_t *dec)
486*eb00b1c8SRobert Mustacchi {
487*eb00b1c8SRobert Mustacchi 	uint_t i, tadruleno;
488*eb00b1c8SRobert Mustacchi 	uint_t sockshift, chanshift, sockmask, chanmask;
489*eb00b1c8SRobert Mustacchi 	uint64_t off, chanaddr;
490*eb00b1c8SRobert Mustacchi 	const imc_tad_t *tad = dec->ids_tad;
491*eb00b1c8SRobert Mustacchi 	const imc_mc_t *mc = dec->ids_mc;
492*eb00b1c8SRobert Mustacchi 	const imc_tad_rule_t *rule = NULL;
493*eb00b1c8SRobert Mustacchi 	const imc_channel_t *chan;
494*eb00b1c8SRobert Mustacchi 
495*eb00b1c8SRobert Mustacchi 	/*
496*eb00b1c8SRobert Mustacchi 	 * The first step in all of this is to determine which TAD rule applies
497*eb00b1c8SRobert Mustacchi 	 * for this address.
498*eb00b1c8SRobert Mustacchi 	 */
499*eb00b1c8SRobert Mustacchi 	for (i = 0; i < tad->itad_nrules; i++) {
500*eb00b1c8SRobert Mustacchi 		rule = &tad->itad_rules[i];
501*eb00b1c8SRobert Mustacchi 
502*eb00b1c8SRobert Mustacchi 		if (dec->ids_pa >= rule->itr_base &&
503*eb00b1c8SRobert Mustacchi 		    dec->ids_pa < rule->itr_limit) {
504*eb00b1c8SRobert Mustacchi 			break;
505*eb00b1c8SRobert Mustacchi 		}
506*eb00b1c8SRobert Mustacchi 	}
507*eb00b1c8SRobert Mustacchi 
508*eb00b1c8SRobert Mustacchi 	if (rule == NULL || i == tad->itad_nrules) {
509*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_NO_TAD_RULE;
510*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
511*eb00b1c8SRobert Mustacchi 	}
512*eb00b1c8SRobert Mustacchi 	tadruleno = i;
513*eb00b1c8SRobert Mustacchi 	dec->ids_tad_rule = rule;
514*eb00b1c8SRobert Mustacchi 
515*eb00b1c8SRobert Mustacchi 	/*
516*eb00b1c8SRobert Mustacchi 	 * Check if our TAD rule requires 3-way interleaving on the channel. We
517*eb00b1c8SRobert Mustacchi 	 * basically can't do that right now. For more information, see the
518*eb00b1c8SRobert Mustacchi 	 * comment above imc_decode_tad_channel().
519*eb00b1c8SRobert Mustacchi 	 */
520*eb00b1c8SRobert Mustacchi 	if (rule->itr_chan_way == 3) {
521*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_TAD_3_ILEAVE;
522*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
523*eb00b1c8SRobert Mustacchi 	}
524*eb00b1c8SRobert Mustacchi 
525*eb00b1c8SRobert Mustacchi 	/*
526*eb00b1c8SRobert Mustacchi 	 * On some platforms, we need to now calculate the channel index from
527*eb00b1c8SRobert Mustacchi 	 * this. The way that we calculate this is nominally straightforward,
528*eb00b1c8SRobert Mustacchi 	 * but complicated by a number of different issues.
529*eb00b1c8SRobert Mustacchi 	 */
530*eb00b1c8SRobert Mustacchi 	switch (imc->imc_gen) {
531*eb00b1c8SRobert Mustacchi 	case IMC_GEN_SANDY:
532*eb00b1c8SRobert Mustacchi 	case IMC_GEN_IVY:
533*eb00b1c8SRobert Mustacchi 	case IMC_GEN_HASWELL:
534*eb00b1c8SRobert Mustacchi 	case IMC_GEN_BROADWELL:
535*eb00b1c8SRobert Mustacchi 		if (!imc_decode_tad_channel(imc, dec)) {
536*eb00b1c8SRobert Mustacchi 			return (B_FALSE);
537*eb00b1c8SRobert Mustacchi 		}
538*eb00b1c8SRobert Mustacchi 		break;
539*eb00b1c8SRobert Mustacchi 	default:
540*eb00b1c8SRobert Mustacchi 		/*
541*eb00b1c8SRobert Mustacchi 		 * On Skylake and newer platforms we should have already decoded
542*eb00b1c8SRobert Mustacchi 		 * the target channel based on using the memory controller route
543*eb00b1c8SRobert Mustacchi 		 * table above.
544*eb00b1c8SRobert Mustacchi 		 */
545*eb00b1c8SRobert Mustacchi 		break;
546*eb00b1c8SRobert Mustacchi 	}
547*eb00b1c8SRobert Mustacchi 
548*eb00b1c8SRobert Mustacchi 	/*
549*eb00b1c8SRobert Mustacchi 	 * We initialize ids_channelid to UINT32_MAX, so this should make sure
550*eb00b1c8SRobert Mustacchi 	 * that we catch an incorrect channel as well.
551*eb00b1c8SRobert Mustacchi 	 */
552*eb00b1c8SRobert Mustacchi 	if (dec->ids_channelid >= mc->icn_nchannels) {
553*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_BAD_CHANNEL_ID;
554*eb00b1c8SRobert Mustacchi 		dec->ids_fail_data = dec->ids_channelid;
555*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
556*eb00b1c8SRobert Mustacchi 	}
557*eb00b1c8SRobert Mustacchi 	chan = &mc->icn_channels[dec->ids_channelid];
558*eb00b1c8SRobert Mustacchi 	dec->ids_chan = chan;
559*eb00b1c8SRobert Mustacchi 
560*eb00b1c8SRobert Mustacchi 	if (tadruleno >= chan->ich_ntad_offsets) {
561*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_BAD_CHANNEL_TAD_OFFSET;
562*eb00b1c8SRobert Mustacchi 		dec->ids_fail_data = tadruleno;
563*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
564*eb00b1c8SRobert Mustacchi 	}
565*eb00b1c8SRobert Mustacchi 
566*eb00b1c8SRobert Mustacchi 	/*
567*eb00b1c8SRobert Mustacchi 	 * Now we can go ahead and calculate the channel address, which is
568*eb00b1c8SRobert Mustacchi 	 * roughly equal to:
569*eb00b1c8SRobert Mustacchi 	 *
570*eb00b1c8SRobert Mustacchi 	 * chan_addr = (sys_addr - off) / (chan way * sock way).
571*eb00b1c8SRobert Mustacchi 	 *
572*eb00b1c8SRobert Mustacchi 	 * The catch is that we want to preserve the low bits where possible.
573*eb00b1c8SRobert Mustacchi 	 * The number of bits is based on the interleaving granularities, the
574*eb00b1c8SRobert Mustacchi 	 * way that's calculated is based on information in the TAD rule.
575*eb00b1c8SRobert Mustacchi 	 * However, if a7mode is enabled on Ivy Bridge through Broadwell, then
576*eb00b1c8SRobert Mustacchi 	 * we need to add one to that. So we will save the smallest number of
577*eb00b1c8SRobert Mustacchi 	 * bits that are left after interleaving.
578*eb00b1c8SRobert Mustacchi 	 *
579*eb00b1c8SRobert Mustacchi 	 * Because the interleaving occurs at different granularities, we need
580*eb00b1c8SRobert Mustacchi 	 * to break this into two discrete steps, one where we apply the socket
581*eb00b1c8SRobert Mustacchi 	 * interleaving and one where we apply the channel interleaving,
582*eb00b1c8SRobert Mustacchi 	 * shifting and dividing at each step.
583*eb00b1c8SRobert Mustacchi 	 */
584*eb00b1c8SRobert Mustacchi 	off = chan->ich_tad_offsets[tadruleno];
585*eb00b1c8SRobert Mustacchi 	if (off > dec->ids_pa) {
586*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_CHANOFF_UNDERFLOW;
587*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
588*eb00b1c8SRobert Mustacchi 	}
589*eb00b1c8SRobert Mustacchi 	chanshift = imc_tad_gran_to_shift(tad, rule->itr_chan_gran);
590*eb00b1c8SRobert Mustacchi 	sockshift = imc_tad_gran_to_shift(tad, rule->itr_sock_gran);
591*eb00b1c8SRobert Mustacchi 	chanmask = (1 << chanshift) - 1;
592*eb00b1c8SRobert Mustacchi 	sockmask = (1 << sockshift) - 1;
593*eb00b1c8SRobert Mustacchi 
594*eb00b1c8SRobert Mustacchi 	chanaddr = dec->ids_pa - off;
595*eb00b1c8SRobert Mustacchi 	chanaddr >>= sockshift;
596*eb00b1c8SRobert Mustacchi 	chanaddr /= rule->itr_sock_way;
597*eb00b1c8SRobert Mustacchi 	chanaddr <<= sockshift;
598*eb00b1c8SRobert Mustacchi 	chanaddr |= dec->ids_pa & sockmask;
599*eb00b1c8SRobert Mustacchi 	chanaddr >>= chanshift;
600*eb00b1c8SRobert Mustacchi 	chanaddr /= rule->itr_chan_way;
601*eb00b1c8SRobert Mustacchi 	chanaddr <<= chanshift;
602*eb00b1c8SRobert Mustacchi 	chanaddr |= dec->ids_pa & chanmask;
603*eb00b1c8SRobert Mustacchi 
604*eb00b1c8SRobert Mustacchi 	dec->ids_chanaddr = chanaddr;
605*eb00b1c8SRobert Mustacchi 
606*eb00b1c8SRobert Mustacchi 	return (B_TRUE);
607*eb00b1c8SRobert Mustacchi }
608*eb00b1c8SRobert Mustacchi 
609*eb00b1c8SRobert Mustacchi static boolean_t
imc_decode_rir(const imc_t * imc,imc_decode_state_t * dec)610*eb00b1c8SRobert Mustacchi imc_decode_rir(const imc_t *imc, imc_decode_state_t *dec)
611*eb00b1c8SRobert Mustacchi {
612*eb00b1c8SRobert Mustacchi 	const imc_mc_t *mc = dec->ids_mc;
613*eb00b1c8SRobert Mustacchi 	const imc_channel_t *chan = dec->ids_chan;
614*eb00b1c8SRobert Mustacchi 	const imc_rank_ileave_t *rir = NULL;
615*eb00b1c8SRobert Mustacchi 	const imc_rank_ileave_entry_t *rirtarg;
616*eb00b1c8SRobert Mustacchi 	const imc_dimm_t *dimm;
617*eb00b1c8SRobert Mustacchi 	uint32_t shift, index;
618*eb00b1c8SRobert Mustacchi 	uint_t i, dimmid, rankid;
619*eb00b1c8SRobert Mustacchi 	uint64_t mask, base, rankaddr;
620*eb00b1c8SRobert Mustacchi 
621*eb00b1c8SRobert Mustacchi 	if (mc->icn_closed) {
622*eb00b1c8SRobert Mustacchi 		shift = IMC_PAGE_BITS_CLOSED;
623*eb00b1c8SRobert Mustacchi 	} else {
624*eb00b1c8SRobert Mustacchi 		shift = IMC_PAGE_BITS_OPEN;
625*eb00b1c8SRobert Mustacchi 	}
626*eb00b1c8SRobert Mustacchi 	mask = (1UL << shift) - 1;
627*eb00b1c8SRobert Mustacchi 
628*eb00b1c8SRobert Mustacchi 	for (i = 0, base = 0; i < chan->ich_nrankileaves; i++) {
629*eb00b1c8SRobert Mustacchi 		rir = &chan->ich_rankileaves[i];
630*eb00b1c8SRobert Mustacchi 		if (rir->irle_enabled && dec->ids_chanaddr >= base &&
631*eb00b1c8SRobert Mustacchi 		    dec->ids_chanaddr < rir->irle_limit) {
632*eb00b1c8SRobert Mustacchi 			break;
633*eb00b1c8SRobert Mustacchi 		}
634*eb00b1c8SRobert Mustacchi 
635*eb00b1c8SRobert Mustacchi 		base = rir->irle_limit;
636*eb00b1c8SRobert Mustacchi 	}
637*eb00b1c8SRobert Mustacchi 
638*eb00b1c8SRobert Mustacchi 	if (rir == NULL || i == chan->ich_nrankileaves) {
639*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_NO_RIR_RULE;
640*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
641*eb00b1c8SRobert Mustacchi 	}
642*eb00b1c8SRobert Mustacchi 	dec->ids_rir = rir;
643*eb00b1c8SRobert Mustacchi 
644*eb00b1c8SRobert Mustacchi 	/*
645*eb00b1c8SRobert Mustacchi 	 * Determine the index of the rule that we care about. This is done by
646*eb00b1c8SRobert Mustacchi 	 * shifting the address based on the open and closed page bits and then
647*eb00b1c8SRobert Mustacchi 	 * just modding it by the number of ways in question.
648*eb00b1c8SRobert Mustacchi 	 */
649*eb00b1c8SRobert Mustacchi 	index = (dec->ids_chanaddr >> shift) % rir->irle_nways;
650*eb00b1c8SRobert Mustacchi 	if (index >= rir->irle_nentries) {
651*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_BAD_RIR_ILEAVE_TARGET;
652*eb00b1c8SRobert Mustacchi 		dec->ids_fail_data = index;
653*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
654*eb00b1c8SRobert Mustacchi 	}
655*eb00b1c8SRobert Mustacchi 	rirtarg = &rir->irle_entries[index];
656*eb00b1c8SRobert Mustacchi 
657*eb00b1c8SRobert Mustacchi 	/*
658*eb00b1c8SRobert Mustacchi 	 * The rank interleaving register has information about a physical rank
659*eb00b1c8SRobert Mustacchi 	 * target. This is within the notion of the physical chip selects that
660*eb00b1c8SRobert Mustacchi 	 * exist. While the memory controller only has eight actual chip
661*eb00b1c8SRobert Mustacchi 	 * selects, the physical values that are programmed depend a bit on the
662*eb00b1c8SRobert Mustacchi 	 * underlying hardware. Effectively, in this ID space, each DIMM has
663*eb00b1c8SRobert Mustacchi 	 * four ranks associated with it. Even when we only have two ranks with
664*eb00b1c8SRobert Mustacchi 	 * each physical channel, they'll be programmed so we can simply do the
665*eb00b1c8SRobert Mustacchi 	 * following match:
666*eb00b1c8SRobert Mustacchi 	 *
667*eb00b1c8SRobert Mustacchi 	 * DIMM = rank id / 4
668*eb00b1c8SRobert Mustacchi 	 * RANK = rank id % 4
669*eb00b1c8SRobert Mustacchi 	 */
670*eb00b1c8SRobert Mustacchi 	dec->ids_physrankid = rirtarg->irle_target;
671*eb00b1c8SRobert Mustacchi 	dimmid = dec->ids_physrankid / 4;
672*eb00b1c8SRobert Mustacchi 	rankid = dec->ids_physrankid % 4;
673*eb00b1c8SRobert Mustacchi 
674*eb00b1c8SRobert Mustacchi 	if (dimmid >= chan->ich_ndimms) {
675*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_BAD_DIMM_INDEX;
676*eb00b1c8SRobert Mustacchi 		dec->ids_fail_data = dimmid;
677*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
678*eb00b1c8SRobert Mustacchi 	}
679*eb00b1c8SRobert Mustacchi 
680*eb00b1c8SRobert Mustacchi 	dimm = &chan->ich_dimms[dimmid];
681*eb00b1c8SRobert Mustacchi 	if (!dimm->idimm_present) {
682*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_DIMM_NOT_PRESENT;
683*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
684*eb00b1c8SRobert Mustacchi 	}
685*eb00b1c8SRobert Mustacchi 	dec->ids_dimmid = dimmid;
686*eb00b1c8SRobert Mustacchi 	dec->ids_dimm = dimm;
687*eb00b1c8SRobert Mustacchi 
688*eb00b1c8SRobert Mustacchi 	if (rankid >= dimm->idimm_nranks) {
689*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_BAD_DIMM_RANK;
690*eb00b1c8SRobert Mustacchi 		dec->ids_fail_data = rankid;
691*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
692*eb00b1c8SRobert Mustacchi 	}
693*eb00b1c8SRobert Mustacchi 	dec->ids_rankid = rankid;
694*eb00b1c8SRobert Mustacchi 
695*eb00b1c8SRobert Mustacchi 	/*
696*eb00b1c8SRobert Mustacchi 	 * Calculate the rank address. We need to divide the address by the
697*eb00b1c8SRobert Mustacchi 	 * number of rank ways and then or in the lower bits.
698*eb00b1c8SRobert Mustacchi 	 */
699*eb00b1c8SRobert Mustacchi 	rankaddr = dec->ids_chanaddr;
700*eb00b1c8SRobert Mustacchi 	rankaddr >>= shift;
701*eb00b1c8SRobert Mustacchi 	rankaddr /= rir->irle_nways;
702*eb00b1c8SRobert Mustacchi 	rankaddr <<= shift;
703*eb00b1c8SRobert Mustacchi 	rankaddr |= dec->ids_chanaddr & mask;
704*eb00b1c8SRobert Mustacchi 
705*eb00b1c8SRobert Mustacchi 	if (rirtarg->irle_offset > rankaddr) {
706*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_RANKOFF_UNDERFLOW;
707*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
708*eb00b1c8SRobert Mustacchi 	}
709*eb00b1c8SRobert Mustacchi 	rankaddr -= rirtarg->irle_offset;
710*eb00b1c8SRobert Mustacchi 	dec->ids_rankaddr = rankaddr;
711*eb00b1c8SRobert Mustacchi 
712*eb00b1c8SRobert Mustacchi 	return (B_TRUE);
713*eb00b1c8SRobert Mustacchi }
714*eb00b1c8SRobert Mustacchi 
715*eb00b1c8SRobert Mustacchi boolean_t
imc_decode_pa(const imc_t * imc,uint64_t pa,imc_decode_state_t * dec)716*eb00b1c8SRobert Mustacchi imc_decode_pa(const imc_t *imc, uint64_t pa, imc_decode_state_t *dec)
717*eb00b1c8SRobert Mustacchi {
718*eb00b1c8SRobert Mustacchi 	bzero(dec, sizeof (*dec));
719*eb00b1c8SRobert Mustacchi 	dec->ids_pa = pa;
720*eb00b1c8SRobert Mustacchi 	dec->ids_nodeid = dec->ids_tadid = dec->ids_channelid = UINT32_MAX;
721*eb00b1c8SRobert Mustacchi 
722*eb00b1c8SRobert Mustacchi 	/*
723*eb00b1c8SRobert Mustacchi 	 * We need to rely on socket zero's information. Make sure that it both
724*eb00b1c8SRobert Mustacchi 	 * exists and is considered valid.
725*eb00b1c8SRobert Mustacchi 	 */
726*eb00b1c8SRobert Mustacchi 	if (imc->imc_nsockets < 1 ||
727*eb00b1c8SRobert Mustacchi 	    imc->imc_sockets[0].isock_valid != IMC_SOCKET_V_VALID) {
728*eb00b1c8SRobert Mustacchi 		dec->ids_fail = IMC_DECODE_F_BAD_SOCKET;
729*eb00b1c8SRobert Mustacchi 		dec->ids_fail_data = 0;
730*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
731*eb00b1c8SRobert Mustacchi 	}
732*eb00b1c8SRobert Mustacchi 
733*eb00b1c8SRobert Mustacchi 	/*
734*eb00b1c8SRobert Mustacchi 	 * First, we need to make sure that the PA we've been given actually is
735*eb00b1c8SRobert Mustacchi 	 * meant to target a DRAM address. This address may fall to MMIO, MMCFG,
736*eb00b1c8SRobert Mustacchi 	 * be an address that's outside of DRAM, or belong to a legacy address
737*eb00b1c8SRobert Mustacchi 	 * range that is interposed.
738*eb00b1c8SRobert Mustacchi 	 */
739*eb00b1c8SRobert Mustacchi 	if (imc_decode_addr_resvd(imc, dec)) {
740*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
741*eb00b1c8SRobert Mustacchi 	}
742*eb00b1c8SRobert Mustacchi 
743*eb00b1c8SRobert Mustacchi 	/*
744*eb00b1c8SRobert Mustacchi 	 * Now that we have this data, we want to go through and look at the
745*eb00b1c8SRobert Mustacchi 	 * SAD. The SAD will point us to a specific socket and an IMC / home
746*eb00b1c8SRobert Mustacchi 	 * agent on that socket which will tell us which TAD we need to use.
747*eb00b1c8SRobert Mustacchi 	 */
748*eb00b1c8SRobert Mustacchi 	if (!imc_decode_sad(imc, dec)) {
749*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
750*eb00b1c8SRobert Mustacchi 	}
751*eb00b1c8SRobert Mustacchi 
752*eb00b1c8SRobert Mustacchi 	/*
753*eb00b1c8SRobert Mustacchi 	 * The decoded SAD information has pointed us a TAD. We need to use this
754*eb00b1c8SRobert Mustacchi 	 * to point us to the corresponding memory channel and the corresponding
755*eb00b1c8SRobert Mustacchi 	 * address on the channel.
756*eb00b1c8SRobert Mustacchi 	 */
757*eb00b1c8SRobert Mustacchi 	if (!imc_decode_tad(imc, dec)) {
758*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
759*eb00b1c8SRobert Mustacchi 	}
760*eb00b1c8SRobert Mustacchi 
761*eb00b1c8SRobert Mustacchi 	/*
762*eb00b1c8SRobert Mustacchi 	 * Use the rank interleaving data to determine which DIMM this is, the
763*eb00b1c8SRobert Mustacchi 	 * relevant rank, and the rank address.
764*eb00b1c8SRobert Mustacchi 	 */
765*eb00b1c8SRobert Mustacchi 	if (!imc_decode_rir(imc, dec)) {
766*eb00b1c8SRobert Mustacchi 		return (B_FALSE);
767*eb00b1c8SRobert Mustacchi 	}
768*eb00b1c8SRobert Mustacchi 
769*eb00b1c8SRobert Mustacchi 	return (B_TRUE);
770*eb00b1c8SRobert Mustacchi }
771