xref: /linux/drivers/ras/amd/atl/system.c (revision ee057c8c194b9283f4137b253b70e292693a39f0)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * AMD Address Translation Library
4  *
5  * system.c : Functions to read and save system-wide data
6  *
7  * Copyright (c) 2023, Advanced Micro Devices, Inc.
8  * All Rights Reserved.
9  *
10  * Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
11  */
12 
13 #include "internal.h"
14 
15 int determine_node_id(struct addr_ctx *ctx, u8 socket_id, u8 die_id)
16 {
17 	u16 socket_id_bits, die_id_bits;
18 
19 	if (socket_id > 0 && df_cfg.socket_id_mask == 0) {
20 		atl_debug(ctx, "Invalid socket inputs: socket_id=%u socket_id_mask=0x%x",
21 			  socket_id, df_cfg.socket_id_mask);
22 		return -EINVAL;
23 	}
24 
25 	/* Do each step independently to avoid shift out-of-bounds issues. */
26 	socket_id_bits =	socket_id;
27 	socket_id_bits <<=	df_cfg.socket_id_shift;
28 	socket_id_bits &=	df_cfg.socket_id_mask;
29 
30 	if (die_id > 0 && df_cfg.die_id_mask == 0) {
31 		atl_debug(ctx, "Invalid die inputs: die_id=%u die_id_mask=0x%x",
32 			  die_id, df_cfg.die_id_mask);
33 		return -EINVAL;
34 	}
35 
36 	/* Do each step independently to avoid shift out-of-bounds issues. */
37 	die_id_bits =		die_id;
38 	die_id_bits <<=		df_cfg.die_id_shift;
39 	die_id_bits &=		df_cfg.die_id_mask;
40 
41 	ctx->node_id = (socket_id_bits | die_id_bits) >> df_cfg.node_id_shift;
42 	return 0;
43 }
44 
45 static void df2_get_masks_shifts(u32 mask0)
46 {
47 	df_cfg.socket_id_shift		= FIELD_GET(DF2_SOCKET_ID_SHIFT, mask0);
48 	df_cfg.socket_id_mask		= FIELD_GET(DF2_SOCKET_ID_MASK, mask0);
49 	df_cfg.die_id_shift		= FIELD_GET(DF2_DIE_ID_SHIFT, mask0);
50 	df_cfg.die_id_mask		= FIELD_GET(DF2_DIE_ID_MASK, mask0);
51 	df_cfg.node_id_shift		= df_cfg.die_id_shift;
52 	df_cfg.node_id_mask		= df_cfg.socket_id_mask | df_cfg.die_id_mask;
53 	df_cfg.component_id_mask	= ~df_cfg.node_id_mask;
54 }
55 
56 static void df3_get_masks_shifts(u32 mask0, u32 mask1)
57 {
58 	df_cfg.component_id_mask	= FIELD_GET(DF3_COMPONENT_ID_MASK, mask0);
59 	df_cfg.node_id_mask		= FIELD_GET(DF3_NODE_ID_MASK, mask0);
60 
61 	df_cfg.node_id_shift		= FIELD_GET(DF3_NODE_ID_SHIFT, mask1);
62 	df_cfg.socket_id_shift		= FIELD_GET(DF3_SOCKET_ID_SHIFT, mask1);
63 	df_cfg.socket_id_mask		= FIELD_GET(DF3_SOCKET_ID_MASK, mask1);
64 	df_cfg.die_id_mask		= FIELD_GET(DF3_DIE_ID_MASK, mask1);
65 }
66 
67 static void df3p5_get_masks_shifts(u32 mask0, u32 mask1, u32 mask2)
68 {
69 	df_cfg.component_id_mask	= FIELD_GET(DF4_COMPONENT_ID_MASK, mask0);
70 	df_cfg.node_id_mask		= FIELD_GET(DF4_NODE_ID_MASK, mask0);
71 
72 	df_cfg.node_id_shift		= FIELD_GET(DF3_NODE_ID_SHIFT, mask1);
73 	df_cfg.socket_id_shift		= FIELD_GET(DF4_SOCKET_ID_SHIFT, mask1);
74 
75 	df_cfg.socket_id_mask		= FIELD_GET(DF4_SOCKET_ID_MASK, mask2);
76 	df_cfg.die_id_mask		= FIELD_GET(DF4_DIE_ID_MASK, mask2);
77 }
78 
79 static void df4_get_masks_shifts(u32 mask0, u32 mask1, u32 mask2)
80 {
81 	df3p5_get_masks_shifts(mask0, mask1, mask2);
82 
83 	if (!(df_cfg.flags.socket_id_shift_quirk && df_cfg.socket_id_shift == 1))
84 		return;
85 
86 	df_cfg.socket_id_shift	= 0;
87 	df_cfg.socket_id_mask	= 1;
88 	df_cfg.die_id_shift	= 0;
89 	df_cfg.die_id_mask	= 0;
90 	df_cfg.node_id_shift	= 8;
91 	df_cfg.node_id_mask	= 0x100;
92 }
93 
94 static int df4_get_fabric_id_mask_registers(void)
95 {
96 	u32 mask0, mask1, mask2;
97 
98 	/* Read D18F4x1B0 (SystemFabricIdMask0) */
99 	if (df_indirect_read_broadcast(0, 4, 0x1B0, &mask0))
100 		return -EINVAL;
101 
102 	/* Read D18F4x1B4 (SystemFabricIdMask1) */
103 	if (df_indirect_read_broadcast(0, 4, 0x1B4, &mask1))
104 		return -EINVAL;
105 
106 	/* Read D18F4x1B8 (SystemFabricIdMask2) */
107 	if (df_indirect_read_broadcast(0, 4, 0x1B8, &mask2))
108 		return -EINVAL;
109 
110 	df4_get_masks_shifts(mask0, mask1, mask2);
111 	return 0;
112 }
113 
114 static int df4_determine_df_rev(u32 reg)
115 {
116 	df_cfg.rev = FIELD_GET(DF_MINOR_REVISION, reg) < 5 ? DF4 : DF4p5;
117 
118 	/* Check for special cases or quirks based on Device/Vendor IDs.*/
119 
120 	/* Read D18F0x000 (DeviceVendorId0) */
121 	if (df_indirect_read_broadcast(0, 0, 0, &reg))
122 		return -EINVAL;
123 
124 	if (reg == DF_FUNC0_ID_ZEN4_SERVER)
125 		df_cfg.flags.socket_id_shift_quirk = 1;
126 
127 	if (reg == DF_FUNC0_ID_MI300) {
128 		df_cfg.flags.heterogeneous = 1;
129 
130 		if (get_umc_info_mi300())
131 			return -EINVAL;
132 	}
133 
134 	return df4_get_fabric_id_mask_registers();
135 }
136 
137 static int determine_df_rev_legacy(void)
138 {
139 	u32 fabric_id_mask0, fabric_id_mask1, fabric_id_mask2;
140 
141 	/*
142 	 * Check for DF3.5.
143 	 *
144 	 * Component ID Mask must be non-zero. Register D18F1x150 is
145 	 * reserved pre-DF3.5, so value will be Read-as-Zero.
146 	 */
147 
148 	/* Read D18F1x150 (SystemFabricIdMask0). */
149 	if (df_indirect_read_broadcast(0, 1, 0x150, &fabric_id_mask0))
150 		return -EINVAL;
151 
152 	if (FIELD_GET(DF4_COMPONENT_ID_MASK, fabric_id_mask0)) {
153 		df_cfg.rev = DF3p5;
154 
155 		/* Read D18F1x154 (SystemFabricIdMask1) */
156 		if (df_indirect_read_broadcast(0, 1, 0x154, &fabric_id_mask1))
157 			return -EINVAL;
158 
159 		/* Read D18F1x158 (SystemFabricIdMask2) */
160 		if (df_indirect_read_broadcast(0, 1, 0x158, &fabric_id_mask2))
161 			return -EINVAL;
162 
163 		df3p5_get_masks_shifts(fabric_id_mask0, fabric_id_mask1, fabric_id_mask2);
164 		return 0;
165 	}
166 
167 	/*
168 	 * Check for DF3.
169 	 *
170 	 * Component ID Mask must be non-zero. Field is Read-as-Zero on DF2.
171 	 */
172 
173 	/* Read D18F1x208 (SystemFabricIdMask). */
174 	if (df_indirect_read_broadcast(0, 1, 0x208, &fabric_id_mask0))
175 		return -EINVAL;
176 
177 	if (FIELD_GET(DF3_COMPONENT_ID_MASK, fabric_id_mask0)) {
178 		df_cfg.rev = DF3;
179 
180 		/* Read D18F1x20C (SystemFabricIdMask1) */
181 		if (df_indirect_read_broadcast(0, 1, 0x20C, &fabric_id_mask1))
182 			return -EINVAL;
183 
184 		df3_get_masks_shifts(fabric_id_mask0, fabric_id_mask1);
185 		return 0;
186 	}
187 
188 	/* Default to DF2. */
189 	df_cfg.rev = DF2;
190 	df2_get_masks_shifts(fabric_id_mask0);
191 	return 0;
192 }
193 
194 static int determine_df_rev(void)
195 {
196 	u32 reg;
197 	u8 rev;
198 
199 	if (df_cfg.rev != UNKNOWN)
200 		return 0;
201 
202 	/* Read D18F0x40 (FabricBlockInstanceCount). */
203 	if (df_indirect_read_broadcast(0, 0, 0x40, &reg))
204 		return -EINVAL;
205 
206 	/*
207 	 * Revision fields added for DF4 and later.
208 	 *
209 	 * Major revision of '0' is found pre-DF4. Field is Read-as-Zero.
210 	 */
211 	rev = FIELD_GET(DF_MAJOR_REVISION, reg);
212 	if (!rev)
213 		return determine_df_rev_legacy();
214 
215 	/*
216 	 * Fail out for major revisions other than '4'.
217 	 *
218 	 * Explicit support should be added for newer systems to avoid issues.
219 	 */
220 	if (rev == 4)
221 		return df4_determine_df_rev(reg);
222 
223 	return -EINVAL;
224 }
225 
226 static int get_dram_hole_base(void)
227 {
228 	u8 func = 0;
229 
230 	if (df_cfg.rev >= DF4)
231 		func = 7;
232 
233 	if (df_indirect_read_broadcast(0, func, 0x104, &df_cfg.dram_hole_base))
234 		return -EINVAL;
235 
236 	df_cfg.dram_hole_base &= DF_DRAM_HOLE_BASE_MASK;
237 
238 	return 0;
239 }
240 
241 static void get_num_maps(void)
242 {
243 	switch (df_cfg.rev) {
244 	case DF2:
245 	case DF3:
246 	case DF3p5:
247 		df_cfg.num_coh_st_maps	= 2;
248 		break;
249 	case DF4:
250 	case DF4p5:
251 		df_cfg.num_coh_st_maps	= 4;
252 		break;
253 	default:
254 		atl_debug_on_bad_df_rev();
255 	}
256 }
257 
258 static void apply_node_id_shift(void)
259 {
260 	if (df_cfg.rev == DF2)
261 		return;
262 
263 	df_cfg.die_id_shift		= df_cfg.node_id_shift;
264 	df_cfg.die_id_mask		<<= df_cfg.node_id_shift;
265 	df_cfg.socket_id_mask		<<= df_cfg.node_id_shift;
266 	df_cfg.socket_id_shift		+= df_cfg.node_id_shift;
267 }
268 
269 static void dump_df_cfg(void)
270 {
271 	pr_debug("rev=0x%x",				df_cfg.rev);
272 
273 	pr_debug("component_id_mask=0x%x",		df_cfg.component_id_mask);
274 	pr_debug("die_id_mask=0x%x",			df_cfg.die_id_mask);
275 	pr_debug("node_id_mask=0x%x",			df_cfg.node_id_mask);
276 	pr_debug("socket_id_mask=0x%x",			df_cfg.socket_id_mask);
277 
278 	pr_debug("die_id_shift=0x%x",			df_cfg.die_id_shift);
279 	pr_debug("node_id_shift=0x%x",			df_cfg.node_id_shift);
280 	pr_debug("socket_id_shift=0x%x",		df_cfg.socket_id_shift);
281 
282 	pr_debug("num_coh_st_maps=%u",			df_cfg.num_coh_st_maps);
283 
284 	pr_debug("dram_hole_base=0x%x",			df_cfg.dram_hole_base);
285 	pr_debug("flags.legacy_ficaa=%u",		df_cfg.flags.legacy_ficaa);
286 	pr_debug("flags.socket_id_shift_quirk=%u",	df_cfg.flags.socket_id_shift_quirk);
287 }
288 
289 int get_df_system_info(void)
290 {
291 	if (determine_df_rev()) {
292 		pr_warn("Failed to determine DF Revision");
293 		df_cfg.rev = UNKNOWN;
294 		return -EINVAL;
295 	}
296 
297 	apply_node_id_shift();
298 
299 	get_num_maps();
300 
301 	if (get_dram_hole_base())
302 		pr_warn("Failed to read DRAM hole base");
303 
304 	dump_df_cfg();
305 
306 	return 0;
307 }
308