// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AMD Address Translation Library
*
* denormalize.c : Functions to account for interleaving bits
*
* Copyright (c) 2023, Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
*/
#include "internal.h"
/*
* Returns the Destination Fabric ID. This is the first (lowest)
* COH_ST Fabric ID used within a DRAM Address map.
*/
static u16 get_dst_fabric_id(struct addr_ctx *ctx)
{
switch (df_cfg.rev) {
case DF2: return FIELD_GET(DF2_DST_FABRIC_ID, ctx->map.limit);
case DF3: return FIELD_GET(DF3_DST_FABRIC_ID, ctx->map.limit);
case DF3p5: return FIELD_GET(DF3p5_DST_FABRIC_ID, ctx->map.limit);
case DF4: return FIELD_GET(DF4_DST_FABRIC_ID, ctx->map.ctl);
case DF4p5: return FIELD_GET(DF4p5_DST_FABRIC_ID, ctx->map.ctl);
default:
atl_debug_on_bad_df_rev();
return 0;
}
}
/*
* Make a contiguous gap in address for N bits starting at bit P.
*
* Example:
* address bits: [20:0]
* # of interleave bits (n): 3
* starting interleave bit (p): 8
*
* expanded address bits: [20+n : n+p][n+p-1 : p][p-1 : 0]
* [23 : 11][10 : 8][7 : 0]
*/
static u64 make_space_for_coh_st_id_at_intlv_bit(struct addr_ctx *ctx)
{
return expand_bits(ctx->map.intlv_bit_pos,
ctx->map.total_intlv_bits,
ctx->ret_addr);
}
/*
* Make two gaps in address for N bits.
* First gap is a single bit at bit P.
* Second gap is the remaining N-1 bits at bit 12.
*
* Example:
* address bits: [20:0]
* # of interleave bits (n): 3
* starting interleave bit (p): 8
*
* First gap
* expanded address bits: [20+1 : p+1][p][p-1 : 0]
* [21 : 9][8][7 : 0]
*
* Second gap uses result from first.
* r = n - 1; remaining interleave bits
* expanded address bits: [21+r : 12+r][12+r-1: 12][11 : 0]
* [23 : 14][13 : 12][11 : 0]
*/
static u64 make_space_for_coh_st_id_split_2_1(struct addr_ctx *ctx)
{
/* Make a single space at the interleave bit. */
u64 denorm_addr = expand_bits(ctx->map.intlv_bit_pos, 1, ctx->ret_addr);
/* Done if there's only a single interleave bit. */
if (ctx->map.total_intlv_bits <= 1)
return denorm_addr;
/* Make spaces for the remaining interleave bits starting at bit 12. */
return expand_bits(12, ctx->map.total_intlv_bits - 1, denorm_addr);
}
/*
* Make space for CS ID at bits [14:8] as follows:
*
* 8 channels -> bits [10:8]
* 16 channels -> bits [11:8]
* 32 channels -> bits [14,11:8]
*
* 1 die -> N/A
* 2 dies -> bit [12]
* 4 dies -> bits [13:12]
*/
static u64 make_space_for_coh_st_id_mi300(struct addr_ctx *ctx)
{
u8 num_intlv_bits = ilog2(ctx->map.num_intlv_chan);
u64 denorm_addr;
if (ctx->map.intlv_bit_pos != 8) {
pr_debug("Invalid interleave bit: %u", ctx->map.intlv_bit_pos);
return ~0ULL;
}
/* Channel bits. Covers up to 4 bits at [11:8]. */
denorm_addr = expand_bits(8, min(num_intlv_bits, 4), ctx->ret_addr);
/* Die bits. Always starts at [12]. */
denorm_addr = expand_bits(12, ilog2(ctx->map.num_intlv_dies), denorm_addr);
/* Additional channel bit at [14]. */
if (num_intlv_bits > 4)
denorm_addr = expand_bits(14, 1, denorm_addr);
return denorm_addr;
}
/*
* Take the current calculated address and shift enough bits in the middle
* to make a gap where the interleave bits will be inserted.
*/
static u64 make_space_for_coh_st_id(struct addr_ctx *ctx)
{
switch (ctx->map.intlv_mode) {
case NOHASH_2CHAN:
case NOHASH_4CHAN:
case NOHASH_8CHAN:
case NOHASH_16CHAN:
case NOHASH_32CHAN:
case