xref: /linux/drivers/ras/amd/atl/system.c (revision 453f0ae797328e675840466c80e5b268d7feb9ba)
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 	return df4_get_fabric_id_mask_registers();
131 }
132 
133 static int determine_df_rev_legacy(void)
134 {
135 	u32 fabric_id_mask0, fabric_id_mask1, fabric_id_mask2;
136 
137 	/*
138 	 * Check for DF3.5.
139 	 *
140 	 * Component ID Mask must be non-zero. Register D18F1x150 is
141 	 * reserved pre-DF3.5, so value will be Read-as-Zero.
142 	 */
143 
144 	/* Read D18F1x150 (SystemFabricIdMask0). */
145 	if (df_indirect_read_broadcast(0, 1, 0x150, &fabric_id_mask0))
146 		return -EINVAL;
147 
148 	if (FIELD_GET(DF4_COMPONENT_ID_MASK, fabric_id_mask0)) {
149 		df_cfg.rev = DF3p5;
150 
151 		/* Read D18F1x154 (SystemFabricIdMask1) */
152 		if (df_indirect_read_broadcast(0, 1, 0x154, &fabric_id_mask1))
153 			return -EINVAL;
154 
155 		/* Read D18F1x158 (SystemFabricIdMask2) */
156 		if (df_indirect_read_broadcast(0, 1, 0x158, &fabric_id_mask2))
157 			return -EINVAL;
158 
159 		df3p5_get_masks_shifts(fabric_id_mask0, fabric_id_mask1, fabric_id_mask2);
160 		return 0;
161 	}
162 
163 	/*
164 	 * Check for DF3.
165 	 *
166 	 * Component ID Mask must be non-zero. Field is Read-as-Zero on DF2.
167 	 */
168 
169 	/* Read D18F1x208 (SystemFabricIdMask). */
170 	if (df_indirect_read_broadcast(0, 1, 0x208, &fabric_id_mask0))
171 		return -EINVAL;
172 
173 	if (FIELD_GET(DF3_COMPONENT_ID_MASK, fabric_id_mask0)) {
174 		df_cfg.rev = DF3;
175 
176 		/* Read D18F1x20C (SystemFabricIdMask1) */
177 		if (df_indirect_read_broadcast(0, 1, 0x20C, &fabric_id_mask1))
178 			return -EINVAL;
179 
180 		df3_get_masks_shifts(fabric_id_mask0, fabric_id_mask1);
181 		return 0;
182 	}
183 
184 	/* Default to DF2. */
185 	df_cfg.rev = DF2;
186 	df2_get_masks_shifts(fabric_id_mask0);
187 	return 0;
188 }
189 
190 static int determine_df_rev(void)
191 {
192 	u32 reg;
193 	u8 rev;
194 
195 	if (df_cfg.rev != UNKNOWN)
196 		return 0;
197 
198 	/* Read D18F0x40 (FabricBlockInstanceCount). */
199 	if (df_indirect_read_broadcast(0, 0, 0x40, &reg))
200 		return -EINVAL;
201 
202 	/*
203 	 * Revision fields added for DF4 and later.
204 	 *
205 	 * Major revision of '0' is found pre-DF4. Field is Read-as-Zero.
206 	 */
207 	rev = FIELD_GET(DF_MAJOR_REVISION, reg);
208 	if (!rev)
209 		return determine_df_rev_legacy();
210 
211 	/*
212 	 * Fail out for major revisions other than '4'.
213 	 *
214 	 * Explicit support should be added for newer systems to avoid issues.
215 	 */
216 	if (rev == 4)
217 		return df4_determine_df_rev(reg);
218 
219 	return -EINVAL;
220 }
221 
222 static void get_num_maps(void)
223 {
224 	switch (df_cfg.rev) {
225 	case DF2:
226 	case DF3:
227 	case DF3p5:
228 		df_cfg.num_coh_st_maps	= 2;
229 		break;
230 	case DF4:
231 	case DF4p5:
232 		df_cfg.num_coh_st_maps	= 4;
233 		break;
234 	default:
235 		atl_debug_on_bad_df_rev();
236 	}
237 }
238 
239 static void apply_node_id_shift(void)
240 {
241 	if (df_cfg.rev == DF2)
242 		return;
243 
244 	df_cfg.die_id_shift		= df_cfg.node_id_shift;
245 	df_cfg.die_id_mask		<<= df_cfg.node_id_shift;
246 	df_cfg.socket_id_mask		<<= df_cfg.node_id_shift;
247 	df_cfg.socket_id_shift		+= df_cfg.node_id_shift;
248 }
249 
250 static void dump_df_cfg(void)
251 {
252 	pr_debug("rev=0x%x",				df_cfg.rev);
253 
254 	pr_debug("component_id_mask=0x%x",		df_cfg.component_id_mask);
255 	pr_debug("die_id_mask=0x%x",			df_cfg.die_id_mask);
256 	pr_debug("node_id_mask=0x%x",			df_cfg.node_id_mask);
257 	pr_debug("socket_id_mask=0x%x",			df_cfg.socket_id_mask);
258 
259 	pr_debug("die_id_shift=0x%x",			df_cfg.die_id_shift);
260 	pr_debug("node_id_shift=0x%x",			df_cfg.node_id_shift);
261 	pr_debug("socket_id_shift=0x%x",		df_cfg.socket_id_shift);
262 
263 	pr_debug("num_coh_st_maps=%u",			df_cfg.num_coh_st_maps);
264 
265 	pr_debug("flags.legacy_ficaa=%u",		df_cfg.flags.legacy_ficaa);
266 	pr_debug("flags.socket_id_shift_quirk=%u",	df_cfg.flags.socket_id_shift_quirk);
267 }
268 
269 int get_df_system_info(void)
270 {
271 	if (determine_df_rev()) {
272 		pr_warn("amd_atl: Failed to determine DF Revision");
273 		df_cfg.rev = UNKNOWN;
274 		return -EINVAL;
275 	}
276 
277 	apply_node_id_shift();
278 
279 	get_num_maps();
280 
281 	dump_df_cfg();
282 
283 	return 0;
284 }
285