xref: /linux/drivers/ras/amd/atl/system.c (revision ba437905b4fbf0ee1686c175069239a1cc292558)
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 void get_num_maps(void)
227 {
228 	switch (df_cfg.rev) {
229 	case DF2:
230 	case DF3:
231 	case DF3p5:
232 		df_cfg.num_coh_st_maps	= 2;
233 		break;
234 	case DF4:
235 	case DF4p5:
236 		df_cfg.num_coh_st_maps	= 4;
237 		break;
238 	default:
239 		atl_debug_on_bad_df_rev();
240 	}
241 }
242 
243 static void apply_node_id_shift(void)
244 {
245 	if (df_cfg.rev == DF2)
246 		return;
247 
248 	df_cfg.die_id_shift		= df_cfg.node_id_shift;
249 	df_cfg.die_id_mask		<<= df_cfg.node_id_shift;
250 	df_cfg.socket_id_mask		<<= df_cfg.node_id_shift;
251 	df_cfg.socket_id_shift		+= df_cfg.node_id_shift;
252 }
253 
254 static void dump_df_cfg(void)
255 {
256 	pr_debug("rev=0x%x",				df_cfg.rev);
257 
258 	pr_debug("component_id_mask=0x%x",		df_cfg.component_id_mask);
259 	pr_debug("die_id_mask=0x%x",			df_cfg.die_id_mask);
260 	pr_debug("node_id_mask=0x%x",			df_cfg.node_id_mask);
261 	pr_debug("socket_id_mask=0x%x",			df_cfg.socket_id_mask);
262 
263 	pr_debug("die_id_shift=0x%x",			df_cfg.die_id_shift);
264 	pr_debug("node_id_shift=0x%x",			df_cfg.node_id_shift);
265 	pr_debug("socket_id_shift=0x%x",		df_cfg.socket_id_shift);
266 
267 	pr_debug("num_coh_st_maps=%u",			df_cfg.num_coh_st_maps);
268 
269 	pr_debug("flags.legacy_ficaa=%u",		df_cfg.flags.legacy_ficaa);
270 	pr_debug("flags.socket_id_shift_quirk=%u",	df_cfg.flags.socket_id_shift_quirk);
271 }
272 
273 int get_df_system_info(void)
274 {
275 	if (determine_df_rev()) {
276 		pr_warn("amd_atl: Failed to determine DF Revision");
277 		df_cfg.rev = UNKNOWN;
278 		return -EINVAL;
279 	}
280 
281 	apply_node_id_shift();
282 
283 	get_num_maps();
284 
285 	dump_df_cfg();
286 
287 	return 0;
288 }
289