#ifndef __AMD_ATL_INTERNAL_H__
#define __AMD_ATL_INTERNAL_H__
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/ras.h>
#include <asm/amd/nb.h>
#include <asm/amd/node.h>
#include "reg_fields.h"
#undef pr_fmt
#define pr_fmt(fmt) "amd_atl: " fmt
#define MAX_COH_ST_CHANNELS 32
#define DF_FUNC0_ID_ZEN4_SERVER 0x14AD1022
#define DF_FUNC0_ID_MI300 0x15281022
#define DF_DRAM_BASE_LIMIT_LSB 28
#define MI300_DRAM_LIMIT_LSB 20
#define INVALID_SPA ~0ULL
enum df_revisions {
UNKNOWN,
DF2,
DF3,
DF3p5,
DF4,
DF4p5,
};
enum intlv_modes {
NONE = 0x00,
NOHASH_2CHAN = 0x01,
NOHASH_4CHAN = 0x03,
NOHASH_8CHAN = 0x05,
DF3_6CHAN = 0x06,
NOHASH_16CHAN = 0x07,
NOHASH_32CHAN = 0x08,
DF3_COD4_2CHAN_HASH = 0x0C,
DF3_COD2_4CHAN_HASH = 0x0D,
DF3_COD1_8CHAN_HASH = 0x0E,
DF4_NPS4_2CHAN_HASH = 0x10,
DF4_NPS2_4CHAN_HASH = 0x11,
DF4_NPS1_8CHAN_HASH = 0x12,
DF4_NPS4_3CHAN_HASH = 0x13,
DF4_NPS2_6CHAN_HASH = 0x14,
DF4_NPS1_12CHAN_HASH = 0x15,
DF4_NPS2_5CHAN_HASH = 0x16,
DF4_NPS1_10CHAN_HASH = 0x17,
MI3_HASH_8CHAN = 0x18,
MI3_HASH_16CHAN = 0x19,
MI3_HASH_32CHAN = 0x1A,
DF2_2CHAN_HASH = 0x21,
DF4p5_NPS1_16CHAN_1K_HASH = 0x2C,
DF4p5_NPS0_24CHAN_1K_HASH = 0x2E,
DF4p5_NPS4_2CHAN_1K_HASH = 0x30,
DF4p5_NPS2_4CHAN_1K_HASH = 0x31,
DF4p5_NPS1_8CHAN_1K_HASH = 0x32,
DF4p5_NPS4_3CHAN_1K_HASH = 0x33,
DF4p5_NPS2_6CHAN_1K_HASH = 0x34,
DF4p5_NPS1_12CHAN_1K_HASH = 0x35,
DF4p5_NPS2_5CHAN_1K_HASH = 0x36,
DF4p5_NPS1_10CHAN_1K_HASH = 0x37,
DF4p5_NPS4_2CHAN_2K_HASH = 0x40,
DF4p5_NPS2_4CHAN_2K_HASH = 0x41,
DF4p5_NPS1_8CHAN_2K_HASH = 0x42,
DF4p5_NPS1_16CHAN_2K_HASH = 0x43,
DF4p5_NPS4_3CHAN_2K_HASH = 0x44,
DF4p5_NPS2_6CHAN_2K_HASH = 0x45,
DF4p5_NPS1_12CHAN_2K_HASH = 0x46,
DF4p5_NPS0_24CHAN_2K_HASH = 0x47,
DF4p5_NPS2_5CHAN_2K_HASH = 0x48,
DF4p5_NPS1_10CHAN_2K_HASH = 0x49,
};
struct df4p5_denorm_ctx {
u8 perm_shift;
u16 rehash_vector;
u8 mod_value;
u64 base_denorm_addr;
u64 div_addr;
u64 current_spa;
u64 resolved_spa;
u16 coh_st_fabric_id;
};
struct df_flags {
__u8 legacy_ficaa : 1,
socket_id_shift_quirk : 1,
heterogeneous : 1,
prm_only : 1,
__reserved_0 : 4;
};
struct df_config {
enum df_revisions rev;
u16 component_id_mask;
u16 die_id_mask;
u16 node_id_mask;
u16 socket_id_mask;
u8 node_id_shift;
u8 die_id_shift;
u8 socket_id_shift;
u8 num_coh_st_maps;
u32 dram_hole_base;
struct df_flags flags;
};
extern struct df_config df_cfg;
struct dram_addr_map {
enum intlv_modes intlv_mode;
u8 num;
u32 base;
u32 limit;
u32 ctl;
u32 intlv;
u8 remap_array[MAX_COH_ST_CHANNELS];
u8 np2_bits;
u8 intlv_bit_pos;
u8 num_intlv_chan;
u8 num_intlv_dies;
u8 num_intlv_sockets;
u8 total_intlv_chan;
u8 total_intlv_bits;
};
struct addr_ctx_inputs {
u64 norm_addr;
u8 socket_id;
u8 die_id;
u8 coh_st_inst_id;
};
struct addr_ctx {
u64 ret_addr;
struct addr_ctx_inputs inputs;
struct dram_addr_map map;
u8 node_id;
u16 inst_id;
u16 coh_st_fabric_id;
};
int df_indirect_read_instance(u16 node, u8 func, u16 reg, u8 instance_id, u32 *lo);
int df_indirect_read_broadcast(u16 node, u8 func, u16 reg, u32 *lo);
int get_df_system_info(void);
int determine_node_id(struct addr_ctx *ctx, u8 socket_num, u8 die_num);
int get_umc_info_mi300(void);
int get_address_map(struct addr_ctx *ctx);
int denormalize_address(struct addr_ctx *ctx);
int dehash_address(struct addr_ctx *ctx);
unsigned long norm_to_sys_addr(u8 socket_id, u8 die_id, u8 coh_st_inst_id, unsigned long addr);
unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
u64 add_base_and_hole(struct addr_ctx *ctx, u64 addr);
u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr);
extern const guid_t norm_to_sys_guid;
#ifdef CONFIG_AMD_ATL_PRM
unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 umc_bank_inst_id, unsigned long addr);
#else
static inline unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 umc_bank_inst_id,
unsigned long addr)
{
return -ENODEV;
}
#endif
static inline u64 expand_bits(u8 bit_num, u8 num_bits, u64 data)
{
u64 temp1, temp2;
if (!num_bits)
return data;
if (!bit_num) {
WARN_ON_ONCE(num_bits >= BITS_PER_LONG);
return data << num_bits;
}
WARN_ON_ONCE(bit_num >= BITS_PER_LONG);
temp1 = data & GENMASK_ULL(bit_num - 1, 0);
temp2 = data & GENMASK_ULL(63, bit_num);
temp2 <<= num_bits;
return temp1 | temp2;
}
static inline u64 remove_bits(u8 low_bit, u8 high_bit, u64 data)
{
u64 temp1, temp2;
WARN_ON_ONCE(high_bit >= BITS_PER_LONG);
WARN_ON_ONCE(low_bit >= BITS_PER_LONG);
WARN_ON_ONCE(low_bit > high_bit);
if (!low_bit)
return data >> (high_bit++);
temp1 = GENMASK_ULL(low_bit - 1, 0) & data;
temp2 = GENMASK_ULL(63, high_bit + 1) & data;
temp2 >>= high_bit - low_bit + 1;
return temp1 | temp2;
}
#define atl_debug(ctx, fmt, arg...) \
pr_debug("socket_id=%u die_id=%u coh_st_inst_id=%u norm_addr=0x%016llx: " fmt,\
(ctx)->inputs.socket_id, (ctx)->inputs.die_id,\
(ctx)->inputs.coh_st_inst_id, (ctx)->inputs.norm_addr, ##arg)
static inline void atl_debug_on_bad_df_rev(void)
{
pr_debug("Unrecognized DF rev: %u", df_cfg.rev);
}
static inline void atl_debug_on_bad_intlv_mode(struct addr_ctx *ctx)
{
atl_debug(ctx, "Unrecognized interleave mode: %u", ctx->map.intlv_mode);
}
#define MI300_UMC_MCA_COL GENMASK(5, 1)
#define MI300_UMC_MCA_ROW13 BIT(23)
#endif