Merge tag 'zonefs-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal...
[sfrench/cifs-2.6.git] / drivers / ras / amd / atl / system.c
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_addr_hash_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 }