1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * AMD Address Translation Library
4 *
5 * map.c : Functions to read and decode DRAM address maps
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
df2_get_intlv_mode(struct addr_ctx * ctx)15 static int df2_get_intlv_mode(struct addr_ctx *ctx)
16 {
17 ctx->map.intlv_mode = FIELD_GET(DF2_INTLV_NUM_CHAN, ctx->map.base);
18
19 if (ctx->map.intlv_mode == 8)
20 ctx->map.intlv_mode = DF2_2CHAN_HASH;
21
22 if (ctx->map.intlv_mode != NONE &&
23 ctx->map.intlv_mode != NOHASH_2CHAN &&
24 ctx->map.intlv_mode != DF2_2CHAN_HASH)
25 return -EINVAL;
26
27 return 0;
28 }
29
df3_get_intlv_mode(struct addr_ctx * ctx)30 static int df3_get_intlv_mode(struct addr_ctx *ctx)
31 {
32 ctx->map.intlv_mode = FIELD_GET(DF3_INTLV_NUM_CHAN, ctx->map.base);
33 return 0;
34 }
35
df3p5_get_intlv_mode(struct addr_ctx * ctx)36 static int df3p5_get_intlv_mode(struct addr_ctx *ctx)
37 {
38 ctx->map.intlv_mode = FIELD_GET(DF3p5_INTLV_NUM_CHAN, ctx->map.base);
39
40 if (ctx->map.intlv_mode == DF3_6CHAN)
41 return -EINVAL;
42
43 return 0;
44 }
45
df4_get_intlv_mode(struct addr_ctx * ctx)46 static int df4_get_intlv_mode(struct addr_ctx *ctx)
47 {
48 ctx->map.intlv_mode = FIELD_GET(DF4_INTLV_NUM_CHAN, ctx->map.intlv);
49
50 if (ctx->map.intlv_mode == DF3_COD4_2CHAN_HASH ||
51 ctx->map.intlv_mode == DF3_COD2_4CHAN_HASH ||
52 ctx->map.intlv_mode == DF3_COD1_8CHAN_HASH ||
53 ctx->map.intlv_mode == DF3_6CHAN)
54 return -EINVAL;
55
56 return 0;
57 }
58
df4p5_get_intlv_mode(struct addr_ctx * ctx)59 static int df4p5_get_intlv_mode(struct addr_ctx *ctx)
60 {
61 ctx->map.intlv_mode = FIELD_GET(DF4p5_INTLV_NUM_CHAN, ctx->map.intlv);
62
63 if (ctx->map.intlv_mode <= NOHASH_32CHAN)
64 return 0;
65
66 if (ctx->map.intlv_mode >= MI3_HASH_8CHAN &&
67 ctx->map.intlv_mode <= MI3_HASH_32CHAN)
68 return 0;
69
70 /*
71 * Modes matching the ranges above are returned as-is.
72 *
73 * All other modes are "fixed up" by adding 20h to make a unique value.
74 */
75 ctx->map.intlv_mode += 0x20;
76
77 return 0;
78 }
79
get_intlv_mode(struct addr_ctx * ctx)80 static int get_intlv_mode(struct addr_ctx *ctx)
81 {
82 int ret;
83
84 switch (df_cfg.rev) {
85 case DF2:
86 ret = df2_get_intlv_mode(ctx);
87 break;
88 case DF3:
89 ret = df3_get_intlv_mode(ctx);
90 break;
91 case DF3p5:
92 ret = df3p5_get_intlv_mode(ctx);
93 break;
94 case DF4:
95 ret = df4_get_intlv_mode(ctx);
96 break;
97 case DF4p5:
98 ret = df4p5_get_intlv_mode(ctx);
99 break;
100 default:
101 ret = -EINVAL;
102 }
103
104 if (ret)
105 atl_debug_on_bad_df_rev();
106
107 return ret;
108 }
109
get_hi_addr_offset(u32 reg_dram_offset)110 static u64 get_hi_addr_offset(u32 reg_dram_offset)
111 {
112 u8 shift = DF_DRAM_BASE_LIMIT_LSB;
113 u64 hi_addr_offset;
114
115 switch (df_cfg.rev) {
116 case DF2:
117 hi_addr_offset = FIELD_GET(DF2_HI_ADDR_OFFSET, reg_dram_offset);
118 break;
119 case DF3:
120 case DF3p5:
121 hi_addr_offset = FIELD_GET(DF3_HI_ADDR_OFFSET, reg_dram_offset);
122 break;
123 case DF4:
124 case DF4p5:
125 hi_addr_offset = FIELD_GET(DF4_HI_ADDR_OFFSET, reg_dram_offset);
126 break;
127 default:
128 hi_addr_offset = 0;
129 atl_debug_on_bad_df_rev();
130 }
131
132 if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous)
133 shift = MI300_DRAM_LIMIT_LSB;
134
135 return hi_addr_offset << shift;
136 }
137
138 /*
139 * Returns: 0 if offset is disabled.
140 * 1 if offset is enabled.
141 * -EINVAL on error.
142 */
get_dram_offset(struct addr_ctx * ctx,u64 * norm_offset)143 static int get_dram_offset(struct addr_ctx *ctx, u64 *norm_offset)
144 {
145 u32 reg_dram_offset;
146 u8 map_num;
147
148 /* Should not be called for map 0. */
149 if (!ctx->map.num) {
150 atl_debug(ctx, "Trying to find DRAM offset for map 0");
151 return -EINVAL;
152 }
153
154 /*
155 * DramOffset registers don't exist for map 0, so the base register
156 * actually refers to map 1.
157 * Adjust the map_num for the register offsets.
158 */
159 map_num = ctx->map.num - 1;
160
161 if (df_cfg.rev >= DF4) {
162 /* Read D18F7x140 (DramOffset) */
163 if (df_indirect_read_instance(ctx->node_id, 7, 0x140 + (4 * map_num),
164 ctx->inst_id, ®_dram_offset))
165 return -EINVAL;
166
167 } else {
168 /* Read D18F0x1B4 (DramOffset) */
169 if (df_indirect_read_instance(ctx->node_id, 0, 0x1B4 + (4 * map_num),
170 ctx->inst_id, ®_dram_offset))
171 return -EINVAL;
172 }
173
174 if (!FIELD_GET(DF_HI_ADDR_OFFSET_EN, reg_dram_offset))
175 return 0;
176
177 *norm_offset = get_hi_addr_offset(reg_dram_offset);
178
179 return 1;
180 }
181
df3_6ch_get_dram_addr_map(struct addr_ctx * ctx)182 static int df3_6ch_get_dram_addr_map(struct addr_ctx *ctx)
183 {
184 u16 dst_fabric_id = FIELD_GET(DF3_DST_FABRIC_ID, ctx->map.limit);
185 u8 i, j, shift = 4, mask = 0xF;
186 u32 reg, offset = 0x60;
187 u16 dst_node_id;
188
189 /* Get Socket 1 register. */
190 if (dst_fabric_id & df_cfg.socket_id_mask)
191 offset = 0x68;
192
193 /* Read D18F0x06{0,8} (DF::Skt0CsTargetRemap0)/(DF::Skt0CsTargetRemap1) */
194 if (df_indirect_read_broadcast(ctx->node_id, 0, offset, ®))
195 return -EINVAL;
196
197 /* Save 8 remap entries. */
198 for (i = 0, j = 0; i < 8; i++, j++)
199 ctx->map.remap_array[i] = (reg >> (j * shift)) & mask;
200
201 dst_node_id = dst_fabric_id & df_cfg.node_id_mask;
202 dst_node_id >>= df_cfg.node_id_shift;
203
204 /* Read D18F2x090 (DF::Np2ChannelConfig) */
205 if (df_indirect_read_broadcast(dst_node_id, 2, 0x90, ®))
206 return -EINVAL;
207
208 ctx->map.np2_bits = FIELD_GET(DF_LOG2_ADDR_64K_SPACE0, reg);
209 return 0;
210 }
211
df2_get_dram_addr_map(struct addr_ctx * ctx)212 static int df2_get_dram_addr_map(struct addr_ctx *ctx)
213 {
214 /* Read D18F0x110 (DramBaseAddress). */
215 if (df_indirect_read_instance(ctx->node_id, 0, 0x110 + (8 * ctx->map.num),
216 ctx->inst_id, &ctx->map.base))
217 return -EINVAL;
218
219 /* Read D18F0x114 (DramLimitAddress). */
220 if (df_indirect_read_instance(ctx->node_id, 0, 0x114 + (8 * ctx->map.num),
221 ctx->inst_id, &ctx->map.limit))
222 return -EINVAL;
223
224 return 0;
225 }
226
df3_get_dram_addr_map(struct addr_ctx * ctx)227 static int df3_get_dram_addr_map(struct addr_ctx *ctx)
228 {
229 if (df2_get_dram_addr_map(ctx))
230 return -EINVAL;
231
232 /* Read D18F0x3F8 (DfGlobalCtl). */
233 if (df_indirect_read_instance(ctx->node_id, 0, 0x3F8,
234 ctx->inst_id, &ctx->map.ctl))
235 return -EINVAL;
236
237 return 0;
238 }
239
df4_get_dram_addr_map(struct addr_ctx * ctx)240 static int df4_get_dram_addr_map(struct addr_ctx *ctx)
241 {
242 u8 remap_sel, i, j, shift = 4, mask = 0xF;
243 u32 remap_reg;
244
245 /* Read D18F7xE00 (DramBaseAddress). */
246 if (df_indirect_read_instance(ctx->node_id, 7, 0xE00 + (16 * ctx->map.num),
247 ctx->inst_id, &ctx->map.base))
248 return -EINVAL;
249
250 /* Read D18F7xE04 (DramLimitAddress). */
251 if (df_indirect_read_instance(ctx->node_id, 7, 0xE04 + (16 * ctx->map.num),
252 ctx->inst_id, &ctx->map.limit))
253 return -EINVAL;
254
255 /* Read D18F7xE08 (DramAddressCtl). */
256 if (df_indirect_read_instance(ctx->node_id, 7, 0xE08 + (16 * ctx->map.num),
257 ctx->inst_id, &ctx->map.ctl))
258 return -EINVAL;
259
260 /* Read D18F7xE0C (DramAddressIntlv). */
261 if (df_indirect_read_instance(ctx->node_id, 7, 0xE0C + (16 * ctx->map.num),
262 ctx->inst_id, &ctx->map.intlv))
263 return -EINVAL;
264
265 /* Check if Remap Enable bit is valid. */
266 if (!FIELD_GET(DF4_REMAP_EN, ctx->map.ctl))
267 return 0;
268
269 /* Fill with bogus values, because '0' is a valid value. */
270 memset(&ctx->map.remap_array, 0xFF, sizeof(ctx->map.remap_array));
271
272 /* Get Remap registers. */
273 remap_sel = FIELD_GET(DF4_REMAP_SEL, ctx->map.ctl);
274
275 /* Read D18F7x180 (CsTargetRemap0A). */
276 if (df_indirect_read_instance(ctx->node_id, 7, 0x180 + (8 * remap_sel),
277 ctx->inst_id, &remap_reg))
278 return -EINVAL;
279
280 /* Save first 8 remap entries. */
281 for (i = 0, j = 0; i < 8; i++, j++)
282 ctx->map.remap_array[i] = (remap_reg >> (j * shift)) & mask;
283
284 /* Read D18F7x184 (CsTargetRemap0B). */
285 if (df_indirect_read_instance(ctx->node_id, 7, 0x184 + (8 * remap_sel),
286 ctx->inst_id, &remap_reg))
287 return -EINVAL;
288
289 /* Save next 8 remap entries. */
290 for (i = 8, j = 0; i < 16; i++, j++)
291 ctx->map.remap_array[i] = (remap_reg >> (j * shift)) & mask;
292
293 return 0;
294 }
295
df4p5_get_dram_addr_map(struct addr_ctx * ctx)296 static int df4p5_get_dram_addr_map(struct addr_ctx *ctx)
297 {
298 u8 remap_sel, i, j, shift = 5, mask = 0x1F;
299 u32 remap_reg;
300
301 /* Read D18F7x200 (DramBaseAddress). */
302 if (df_indirect_read_instance(ctx->node_id, 7, 0x200 + (16 * ctx->map.num),
303 ctx->inst_id, &ctx->map.base))
304 return -EINVAL;
305
306 /* Read D18F7x204 (DramLimitAddress). */
307 if (df_indirect_read_instance(ctx->node_id, 7, 0x204 + (16 * ctx->map.num),
308 ctx->inst_id, &ctx->map.limit))
309 return -EINVAL;
310
311 /* Read D18F7x208 (DramAddressCtl). */
312 if (df_indirect_read_instance(ctx->node_id, 7, 0x208 + (16 * ctx->map.num),
313 ctx->inst_id, &ctx->map.ctl))
314 return -EINVAL;
315
316 /* Read D18F7x20C (DramAddressIntlv). */
317 if (df_indirect_read_instance(ctx->node_id, 7, 0x20C + (16 * ctx->map.num),
318 ctx->inst_id, &ctx->map.intlv))
319 return -EINVAL;
320
321 /* Check if Remap Enable bit is valid. */
322 if (!FIELD_GET(DF4_REMAP_EN, ctx->map.ctl))
323 return 0;
324
325 /* Fill with bogus values, because '0' is a valid value. */
326 memset(&ctx->map.remap_array, 0xFF, sizeof(ctx->map.remap_array));
327
328 /* Get Remap registers. */
329 remap_sel = FIELD_GET(DF4p5_REMAP_SEL, ctx->map.ctl);
330
331 /* Read D18F7x180 (CsTargetRemap0A). */
332 if (df_indirect_read_instance(ctx->node_id, 7, 0x180 + (24 * remap_sel),
333 ctx->inst_id, &remap_reg))
334 return -EINVAL;
335
336 /* Save first 6 remap entries. */
337 for (i = 0, j = 0; i < 6; i++, j++)
338 ctx->map.remap_array[i] = (remap_reg >> (j * shift)) & mask;
339
340 /* Read D18F7x184 (CsTargetRemap0B). */
341 if (df_indirect_read_instance(ctx->node_id, 7, 0x184 + (24 * remap_sel),
342 ctx->inst_id, &remap_reg))
343 return -EINVAL;
344
345 /* Save next 6 remap entries. */
346 for (i = 6, j = 0; i < 12; i++, j++)
347 ctx->map.remap_array[i] = (remap_reg >> (j * shift)) & mask;
348
349 /* Read D18F7x188 (CsTargetRemap0C). */
350 if (df_indirect_read_instance(ctx->node_id, 7, 0x188 + (24 * remap_sel),
351 ctx->inst_id, &remap_reg))
352 return -EINVAL;
353
354 /* Save next 6 remap entries. */
355 for (i = 12, j = 0; i < 18; i++, j++)
356 ctx->map.remap_array[i] = (remap_reg >> (j * shift)) & mask;
357
358 return 0;
359 }
360
get_dram_addr_map(struct addr_ctx * ctx)361 static int get_dram_addr_map(struct addr_ctx *ctx)
362 {
363 switch (df_cfg.rev) {
364 case DF2: return df2_get_dram_addr_map(ctx);
365 case DF3:
366 case DF3p5: return df3_get_dram_addr_map(ctx);
367 case DF4: return df4_get_dram_addr_map(ctx);
368 case DF4p5: return df4p5_get_dram_addr_map(ctx);
369 default:
370 atl_debug_on_bad_df_rev();
371 return -EINVAL;
372 }
373 }
374
get_coh_st_fabric_id(struct addr_ctx * ctx)375 static int get_coh_st_fabric_id(struct addr_ctx *ctx)
376 {
377 u32 reg;
378
379 /*
380 * On MI300 systems, the Coherent Station Fabric ID is derived
381 * later. And it does not depend on the register value.
382 */
383 if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous)
384 return 0;
385
386 /* Read D18F0x50 (FabricBlockInstanceInformation3). */
387 if (df_indirect_read_instance(ctx->node_id, 0, 0x50, ctx->inst_id, ®))
388 return -EINVAL;
389
390 if (df_cfg.rev < DF4p5)
391 ctx->coh_st_fabric_id = FIELD_GET(DF2_COH_ST_FABRIC_ID, reg);
392 else
393 ctx->coh_st_fabric_id = FIELD_GET(DF4p5_COH_ST_FABRIC_ID, reg);
394
395 return 0;
396 }
397
find_normalized_offset(struct addr_ctx * ctx,u64 * norm_offset)398 static int find_normalized_offset(struct addr_ctx *ctx, u64 *norm_offset)
399 {
400 u64 last_offset = 0;
401 int ret;
402
403 for (ctx->map.num = 1; ctx->map.num < df_cfg.num_coh_st_maps; ctx->map.num++) {
404 ret = get_dram_offset(ctx, norm_offset);
405 if (ret < 0)
406 return ret;
407
408 /* Continue search if this map's offset is not enabled. */
409 if (!ret)
410 continue;
411
412 /* Enabled offsets should never be 0. */
413 if (*norm_offset == 0) {
414 atl_debug(ctx, "Enabled map %u offset is 0", ctx->map.num);
415 return -EINVAL;
416 }
417
418 /* Offsets should always increase from one map to the next. */
419 if (*norm_offset <= last_offset) {
420 atl_debug(ctx, "Map %u offset (0x%016llx) <= previous (0x%016llx)",
421 ctx->map.num, *norm_offset, last_offset);
422 return -EINVAL;
423 }
424
425 /* Match if this map's offset is less than the current calculated address. */
426 if (ctx->ret_addr >= *norm_offset)
427 break;
428
429 last_offset = *norm_offset;
430 }
431
432 /*
433 * Finished search without finding a match.
434 * Reset to map 0 and no offset.
435 */
436 if (ctx->map.num >= df_cfg.num_coh_st_maps) {
437 ctx->map.num = 0;
438 *norm_offset = 0;
439 }
440
441 return 0;
442 }
443
valid_map(struct addr_ctx * ctx)444 static bool valid_map(struct addr_ctx *ctx)
445 {
446 if (df_cfg.rev >= DF4)
447 return FIELD_GET(DF_ADDR_RANGE_VAL, ctx->map.ctl);
448 else
449 return FIELD_GET(DF_ADDR_RANGE_VAL, ctx->map.base);
450 }
451
get_address_map_common(struct addr_ctx * ctx)452 static int get_address_map_common(struct addr_ctx *ctx)
453 {
454 u64 norm_offset = 0;
455
456 if (get_coh_st_fabric_id(ctx))
457 return -EINVAL;
458
459 if (find_normalized_offset(ctx, &norm_offset))
460 return -EINVAL;
461
462 if (get_dram_addr_map(ctx))
463 return -EINVAL;
464
465 if (!valid_map(ctx))
466 return -EINVAL;
467
468 ctx->ret_addr -= norm_offset;
469
470 return 0;
471 }
472
get_num_intlv_chan(struct addr_ctx * ctx)473 static u8 get_num_intlv_chan(struct addr_ctx *ctx)
474 {
475 switch (ctx->map.intlv_mode) {
476 case NONE:
477 return 1;
478 case NOHASH_2CHAN:
479 case DF2_2CHAN_HASH:
480 case DF3_COD4_2CHAN_HASH:
481 case DF4_NPS4_2CHAN_HASH:
482 case DF4p5_NPS4_2CHAN_1K_HASH:
483 case DF4p5_NPS4_2CHAN_2K_HASH:
484 return 2;
485 case DF4_NPS4_3CHAN_HASH:
486 case DF4p5_NPS4_3CHAN_1K_HASH:
487 case DF4p5_NPS4_3CHAN_2K_HASH:
488 return 3;
489 case NOHASH_4CHAN:
490 case DF3_COD2_4CHAN_HASH:
491 case DF4_NPS2_4CHAN_HASH:
492 case DF4p5_NPS2_4CHAN_1K_HASH:
493 case DF4p5_NPS2_4CHAN_2K_HASH:
494 return 4;
495 case DF4_NPS2_5CHAN_HASH:
496 case DF4p5_NPS2_5CHAN_1K_HASH:
497 case DF4p5_NPS2_5CHAN_2K_HASH:
498 return 5;
499 case DF3_6CHAN:
500 case DF4_NPS2_6CHAN_HASH:
501 case DF4p5_NPS2_6CHAN_1K_HASH:
502 case DF4p5_NPS2_6CHAN_2K_HASH:
503 return 6;
504 case NOHASH_8CHAN:
505 case DF3_COD1_8CHAN_HASH:
506 case DF4_NPS1_8CHAN_HASH:
507 case MI3_HASH_8CHAN:
508 case DF4p5_NPS1_8CHAN_1K_HASH:
509 case DF4p5_NPS1_8CHAN_2K_HASH:
510 return 8;
511 case DF4_NPS1_10CHAN_HASH:
512 case DF4p5_NPS1_10CHAN_1K_HASH:
513 case DF4p5_NPS1_10CHAN_2K_HASH:
514 return 10;
515 case DF4_NPS1_12CHAN_HASH:
516 case DF4p5_NPS1_12CHAN_1K_HASH:
517 case DF4p5_NPS1_12CHAN_2K_HASH:
518 return 12;
519 case NOHASH_16CHAN:
520 case MI3_HASH_16CHAN:
521 case DF4p5_NPS1_16CHAN_1K_HASH:
522 case DF4p5_NPS1_16CHAN_2K_HASH:
523 return 16;
524 case DF4p5_NPS0_24CHAN_1K_HASH:
525 case DF4p5_NPS0_24CHAN_2K_HASH:
526 return 24;
527 case NOHASH_32CHAN:
528 case MI3_HASH_32CHAN:
529 return 32;
530 default:
531 atl_debug_on_bad_intlv_mode(ctx);
532 return 0;
533 }
534 }
535
calculate_intlv_bits(struct addr_ctx * ctx)536 static void calculate_intlv_bits(struct addr_ctx *ctx)
537 {
538 ctx->map.num_intlv_chan = get_num_intlv_chan(ctx);
539
540 ctx->map.total_intlv_chan = ctx->map.num_intlv_chan;
541 ctx->map.total_intlv_chan *= ctx->map.num_intlv_dies;
542 ctx->map.total_intlv_chan *= ctx->map.num_intlv_sockets;
543
544 /*
545 * Get the number of bits needed to cover this many channels.
546 * order_base_2() rounds up automatically.
547 */
548 ctx->map.total_intlv_bits = order_base_2(ctx->map.total_intlv_chan);
549 }
550
get_intlv_bit_pos(struct addr_ctx * ctx)551 static u8 get_intlv_bit_pos(struct addr_ctx *ctx)
552 {
553 u8 addr_sel = 0;
554
555 switch (df_cfg.rev) {
556 case DF2:
557 addr_sel = FIELD_GET(DF2_INTLV_ADDR_SEL, ctx->map.base);
558 break;
559 case DF3:
560 case DF3p5:
561 addr_sel = FIELD_GET(DF3_INTLV_ADDR_SEL, ctx->map.base);
562 break;
563 case DF4:
564 case DF4p5:
565 addr_sel = FIELD_GET(DF4_INTLV_ADDR_SEL, ctx->map.intlv);
566 break;
567 default:
568 atl_debug_on_bad_df_rev();
569 break;
570 }
571
572 /* Add '8' to get the 'interleave bit position'. */
573 return addr_sel + 8;
574 }
575
get_num_intlv_dies(struct addr_ctx * ctx)576 static u8 get_num_intlv_dies(struct addr_ctx *ctx)
577 {
578 u8 dies = 0;
579
580 switch (df_cfg.rev) {
581 case DF2:
582 dies = FIELD_GET(DF2_INTLV_NUM_DIES, ctx->map.limit);
583 break;
584 case DF3:
585 dies = FIELD_GET(DF3_INTLV_NUM_DIES, ctx->map.base);
586 break;
587 case DF3p5:
588 dies = FIELD_GET(DF3p5_INTLV_NUM_DIES, ctx->map.base);
589 break;
590 case DF4:
591 case DF4p5:
592 dies = FIELD_GET(DF4_INTLV_NUM_DIES, ctx->map.intlv);
593 break;
594 default:
595 atl_debug_on_bad_df_rev();
596 break;
597 }
598
599 /* Register value is log2, e.g. 0 -> 1 die, 1 -> 2 dies, etc. */
600 return 1 << dies;
601 }
602
get_num_intlv_sockets(struct addr_ctx * ctx)603 static u8 get_num_intlv_sockets(struct addr_ctx *ctx)
604 {
605 u8 sockets = 0;
606
607 switch (df_cfg.rev) {
608 case DF2:
609 sockets = FIELD_GET(DF2_INTLV_NUM_SOCKETS, ctx->map.limit);
610 break;
611 case DF3:
612 case DF3p5:
613 sockets = FIELD_GET(DF2_INTLV_NUM_SOCKETS, ctx->map.base);
614 break;
615 case DF4:
616 case DF4p5:
617 sockets = FIELD_GET(DF4_INTLV_NUM_SOCKETS, ctx->map.intlv);
618 break;
619 default:
620 atl_debug_on_bad_df_rev();
621 break;
622 }
623
624 /* Register value is log2, e.g. 0 -> 1 sockets, 1 -> 2 sockets, etc. */
625 return 1 << sockets;
626 }
627
get_global_map_data(struct addr_ctx * ctx)628 static int get_global_map_data(struct addr_ctx *ctx)
629 {
630 if (get_intlv_mode(ctx))
631 return -EINVAL;
632
633 if (ctx->map.intlv_mode == DF3_6CHAN &&
634 df3_6ch_get_dram_addr_map(ctx))
635 return -EINVAL;
636
637 ctx->map.intlv_bit_pos = get_intlv_bit_pos(ctx);
638 ctx->map.num_intlv_dies = get_num_intlv_dies(ctx);
639 ctx->map.num_intlv_sockets = get_num_intlv_sockets(ctx);
640 calculate_intlv_bits(ctx);
641
642 return 0;
643 }
644
645 /*
646 * Verify the interleave bits are correct in the different interleaving
647 * settings.
648 *
649 * If @num_intlv_dies and/or @num_intlv_sockets are 1, it means the
650 * respective interleaving is disabled.
651 */
map_bits_valid(struct addr_ctx * ctx,u8 bit1,u8 bit2,u8 num_intlv_dies,u8 num_intlv_sockets)652 static inline bool map_bits_valid(struct addr_ctx *ctx, u8 bit1, u8 bit2,
653 u8 num_intlv_dies, u8 num_intlv_sockets)
654 {
655 if (!(ctx->map.intlv_bit_pos == bit1 || ctx->map.intlv_bit_pos == bit2)) {
656 pr_debug("Invalid interleave bit: %u", ctx->map.intlv_bit_pos);
657 return false;
658 }
659
660 if (ctx->map.num_intlv_dies > num_intlv_dies) {
661 pr_debug("Invalid number of interleave dies: %u", ctx->map.num_intlv_dies);
662 return false;
663 }
664
665 if (ctx->map.num_intlv_sockets > num_intlv_sockets) {
666 pr_debug("Invalid number of interleave sockets: %u", ctx->map.num_intlv_sockets);
667 return false;
668 }
669
670 return true;
671 }
672
validate_address_map(struct addr_ctx * ctx)673 static int validate_address_map(struct addr_ctx *ctx)
674 {
675 switch (ctx->map.intlv_mode) {
676 case DF2_2CHAN_HASH:
677 case DF3_COD4_2CHAN_HASH:
678 case DF3_COD2_4CHAN_HASH:
679 case DF3_COD1_8CHAN_HASH:
680 if (!map_bits_valid(ctx, 8, 9, 1, 1))
681 goto err;
682 break;
683
684 case DF4_NPS4_2CHAN_HASH:
685 case DF4_NPS2_4CHAN_HASH:
686 case DF4_NPS1_8CHAN_HASH:
687 case DF4p5_NPS4_2CHAN_1K_HASH:
688 case DF4p5_NPS4_2CHAN_2K_HASH:
689 case DF4p5_NPS2_4CHAN_1K_HASH:
690 case DF4p5_NPS2_4CHAN_2K_HASH:
691 case DF4p5_NPS1_8CHAN_1K_HASH:
692 case DF4p5_NPS1_8CHAN_2K_HASH:
693 case DF4p5_NPS1_16CHAN_1K_HASH:
694 case DF4p5_NPS1_16CHAN_2K_HASH:
695 if (!map_bits_valid(ctx, 8, 8, 1, 2))
696 goto err;
697 break;
698
699 case DF4p5_NPS4_3CHAN_1K_HASH:
700 case DF4p5_NPS4_3CHAN_2K_HASH:
701 case DF4p5_NPS2_5CHAN_1K_HASH:
702 case DF4p5_NPS2_5CHAN_2K_HASH:
703 case DF4p5_NPS2_6CHAN_1K_HASH:
704 case DF4p5_NPS2_6CHAN_2K_HASH:
705 case DF4p5_NPS1_10CHAN_1K_HASH:
706 case DF4p5_NPS1_10CHAN_2K_HASH:
707 case DF4p5_NPS1_12CHAN_1K_HASH:
708 case DF4p5_NPS1_12CHAN_2K_HASH:
709 if (ctx->map.num_intlv_sockets != 1 || !map_bits_valid(ctx, 8, 0, 1, 1))
710 goto err;
711 break;
712
713 case DF4p5_NPS0_24CHAN_1K_HASH:
714 case DF4p5_NPS0_24CHAN_2K_HASH:
715 if (ctx->map.num_intlv_sockets < 2 || !map_bits_valid(ctx, 8, 0, 1, 2))
716 goto err;
717 break;
718
719 case MI3_HASH_8CHAN:
720 case MI3_HASH_16CHAN:
721 case MI3_HASH_32CHAN:
722 if (!map_bits_valid(ctx, 8, 8, 4, 1))
723 goto err;
724 break;
725
726 /* Nothing to do for modes that don't need special validation checks. */
727 default:
728 break;
729 }
730
731 return 0;
732
733 err:
734 atl_debug(ctx, "Inconsistent address map");
735 return -EINVAL;
736 }
737
dump_address_map(struct dram_addr_map * map)738 static void dump_address_map(struct dram_addr_map *map)
739 {
740 u8 i;
741
742 pr_debug("intlv_mode=0x%x", map->intlv_mode);
743 pr_debug("num=0x%x", map->num);
744 pr_debug("base=0x%x", map->base);
745 pr_debug("limit=0x%x", map->limit);
746 pr_debug("ctl=0x%x", map->ctl);
747 pr_debug("intlv=0x%x", map->intlv);
748
749 for (i = 0; i < MAX_COH_ST_CHANNELS; i++)
750 pr_debug("remap_array[%u]=0x%x", i, map->remap_array[i]);
751
752 pr_debug("intlv_bit_pos=%u", map->intlv_bit_pos);
753 pr_debug("num_intlv_chan=%u", map->num_intlv_chan);
754 pr_debug("num_intlv_dies=%u", map->num_intlv_dies);
755 pr_debug("num_intlv_sockets=%u", map->num_intlv_sockets);
756 pr_debug("total_intlv_chan=%u", map->total_intlv_chan);
757 pr_debug("total_intlv_bits=%u", map->total_intlv_bits);
758 }
759
get_address_map(struct addr_ctx * ctx)760 int get_address_map(struct addr_ctx *ctx)
761 {
762 int ret;
763
764 ret = get_address_map_common(ctx);
765 if (ret)
766 return ret;
767
768 ret = get_global_map_data(ctx);
769 if (ret)
770 return ret;
771
772 dump_address_map(&ctx->map);
773
774 ret = validate_address_map(ctx);
775 if (ret)
776 return ret;
777
778 return ret;
779 }
780