// SPDX-License-Identifier: GPL-2.0-or-later /* * AMD Address Translation Library * * umc.c : Unified Memory Controller (UMC) topology helpers * * Copyright (c) 2023, Advanced Micro Devices, Inc. * All Rights Reserved. * * Author: Yazen Ghannam */ #include "internal.h" /* * MI300 has a fixed, model-specific mapping between a UMC instance and * its related Data Fabric Coherent Station instance. * * The MCA_IPID_UMC[InstanceId] field holds a unique identifier for the * UMC instance within a Node. Use this to find the appropriate Coherent * Station ID. * * Redundant bits were removed from the map below. */ static const u16 umc_coh_st_map[32] = { 0x393, 0x293, 0x193, 0x093, 0x392, 0x292, 0x192, 0x092, 0x391, 0x291, 0x191, 0x091, 0x390, 0x290, 0x190, 0x090, 0x793, 0x693, 0x593, 0x493, 0x792, 0x692, 0x592, 0x492, 0x791, 0x691, 0x591, 0x491, 0x790, 0x690, 0x590, 0x490, }; #define UMC_ID_MI300 GENMASK(23, 12) static u8 get_coh_st_inst_id_mi300(struct atl_err *err) { u16 umc_id = FIELD_GET(UMC_ID_MI300, err->ipid); u8 i; for (i = 0; i < ARRAY_SIZE(umc_coh_st_map); i++) { if (umc_id == umc_coh_st_map[i]) break; } WARN_ON_ONCE(i >= ARRAY_SIZE(umc_coh_st_map)); return i; } /* XOR the bits in @val. */ static u16 bitwise_xor_bits(u16 val) { u16 tmp = 0; u8 i; for (i = 0; i < 16; i++) tmp ^= (val >> i) & 0x1; return tmp; } struct xor_bits { bool xor_enable; u16 col_xor; u32 row_xor; }; #define NUM_BANK_BITS 4 static struct { /* UMC::CH::AddrHashBank */ struct xor_bits bank[NUM_BANK_BITS]; /* UMC::CH::AddrHashPC */ struct xor_bits pc; /* UMC::CH::AddrHashPC2 */ u8 bank_xor; } addr_hash; #define MI300_UMC_CH_BASE 0x90000 #define MI300_ADDR_HASH_BANK0 (MI300_UMC_CH_BASE + 0xC8) #define MI300_ADDR_HASH_PC (MI300_UMC_CH_BASE + 0xE0) #define MI300_ADDR_HASH_PC2 (MI300_UMC_CH_BASE + 0xE4) #define ADDR_HASH_XOR_EN BIT(0) #define ADDR_HASH_COL_XOR GENMASK(13, 1) #define ADDR_HASH_ROW_XOR GENMASK(31, 14) #define ADDR_HASH_BANK_XOR GENMASK(5, 0) /* * Read UMC::CH::AddrHash{Bank,PC,PC2} registers to get XOR bits used * for hashing. Do this during module init, since the values will not * change during run time. * * These registers are instantiated for each UMC across each AMD Node. * However, they should be identically programmed due to the fixed hardware * design of MI300 systems. So read the values from Node 0 UMC 0 and keep a * single global structure for simplicity. */ int get_addr_hash_mi300(void) { u32 temp; int ret; u8 i; for (i = 0; i < NUM_BANK_BITS; i++) { ret = amd_smn_read(0, MI300_ADDR_HASH_BANK0 + (i * 4), &temp); if (ret) return ret; addr_hash.bank[i].xor_enable = FIELD_GET(ADDR_HASH_XOR_EN, temp); addr_hash.bank[i].col_xor = FIELD_GET(ADDR_HASH_COL_XOR, temp); addr_hash.bank[i].row_xor = FIELD_GET(ADDR_HASH_ROW_XOR, temp); } ret = amd_smn_read(0, MI300_ADDR_HASH_PC, &temp); if (ret) return ret; addr_hash.pc.xor_enable = FIELD_GET(ADDR_HASH_XOR_EN, temp); addr_hash.pc.col_xor = FIELD_GET(ADDR_HASH_COL_XOR, temp); addr_hash.pc.row_xor = FIELD_GET(ADDR_HASH_ROW_XOR, temp); ret = amd_smn_read(0, MI300_ADDR_HASH_PC2, &temp); if (ret) return ret; addr_hash.bank_xor = FIELD_GET(ADDR_HASH_BANK_XOR, temp); return 0; } /* * MI300 systems report a DRAM address in MCA_ADDR for DRAM ECC errors. This must * be converted to the intermediate normalized address (NA) before translating to a * system physical address. * * The DRAM address includes bank, row, and column. Also included are bits for * pseudochannel (PC) and stack ID (SID). * * Abbreviations: (S)tack ID, (P)seudochannel, (R)ow, (B)ank, (C)olumn, (Z)ero * * The MCA address format is as follows: * MCA_ADDR[27:0] = {S[1:0], P[0], R[14:0], B[3:0], C[4:0], Z[0]} * * The normalized address format is fixed in hardware and is as follows: * NA[30:0] = {S[1:0], R[13:0], C4, B[1:0], B[3:2], C[3:2], P, C[1:0], Z[4:0]} * * Additionally, the PC and Bank bits may be hashed. This must be accounted for before * reconstructing the normalized address. */ #define MI300_UMC_MCA_COL GENMASK(5, 1) #define MI300_UMC_MCA_BANK GENMASK(9, 6) #define MI300_UMC_MCA_ROW GENMASK(24, 10) #define MI300_UMC_MCA_PC BIT(25) #define MI300_UMC_MCA_SID GENMASK(27, 26) #define MI300_NA_COL_1_0 GENMASK(6, 5) #define MI300_NA_PC BIT(7) #define MI300_NA_COL_3_2 GENMASK(9, 8) #define MI300_NA_BANK_3_2 GENMASK(11, 10) #define MI300_NA_BANK_1_0 GENMASK(13, 12) #define MI300_NA_COL_4 BIT(14) #define MI300_NA_ROW GENMASK(28, 15) #define MI300_NA_SID GENMASK(30, 29) static unsigned long convert_dram_to_norm_addr_mi300(unsigned long addr) { u16 i, col, row, bank, pc, sid, temp; col = FIELD_GET(MI300_UMC_MCA_COL, addr); bank = FIELD_GET(MI300_UMC_MCA_BANK, addr); row = FIELD_GET(MI300_UMC_MCA_ROW, addr); pc = FIELD_GET(MI300_UMC_MCA_PC, addr); sid = FIELD_GET(MI300_UMC_MCA_SID, addr); /* Calculate hash for each Bank bit. */ for (i = 0; i < NUM_BANK_BITS; i++) { if (!addr_hash.bank[i].xor_enable) continue; temp = bitwise_xor_bits(col & addr_hash.bank[i].col_xor); temp ^= bitwise_xor_bits(row & addr_hash.bank[i].row_xor); bank ^= temp << i; } /* Calculate hash for PC bit. */ if (addr_hash.pc.xor_enable) { /* Bits SID[1:0] act as Bank[6:5] for PC hash, so apply them here. */ bank |= sid << 5; temp = bitwise_xor_bits(col & addr_hash.pc.col_xor); temp ^= bitwise_xor_bits(row & addr_hash.pc.row_xor); temp ^= bitwise_xor_bits(bank & addr_hash.bank_xor); pc ^= temp; /* Drop SID bits for the sake of debug printing later. */ bank &= 0x1F; } /* Reconstruct the normalized address starting with NA[4:0] = 0 */ addr = 0; /* NA[6:5] = Column[1:0] */ temp = col & 0x3; addr |= FIELD_PREP(MI300_NA_COL_1_0, temp); /* NA[7] = PC */ addr |= FIELD_PREP(MI300_NA_PC, pc); /* NA[9:8] = Column[3:2] */ temp = (col >> 2) & 0x3; addr |= FIELD_PREP(MI300_NA_COL_3_2, temp); /* NA[11:10] = Bank[3:2] */ temp = (bank >> 2) & 0x3; addr |= FIELD_PREP(MI300_NA_BANK_3_2, temp); /* NA[13:12] = Bank[1:0] */ temp = bank & 0x3; addr |= FIELD_PREP(MI300_NA_BANK_1_0, temp); /* NA[14] = Column[4] */ temp = (col >> 4) & 0x1; addr |= FIELD_PREP(MI300_NA_COL_4, temp); /* NA[28:15] = Row[13:0] */ addr |= FIELD_PREP(MI300_NA_ROW, row); /* NA[30:29] = SID[1:0] */ addr |= FIELD_PREP(MI300_NA_SID, sid); pr_debug("Addr=0x%016lx", addr); pr_debug("Bank=%u Row=%u Column=%u PC=%u SID=%u", bank, row, col, pc, sid); return addr; } /* * When a DRAM ECC error occurs on MI300 systems, it is recommended to retire * all memory within that DRAM row. This applies to the memory with a DRAM * bank. * * To find the memory addresses, loop through permutations of the DRAM column * bits and find the System Physical address of each. The column bits are used * to calculate the intermediate Normalized address, so all permutations should * be checked. * * See amd_atl::convert_dram_to_norm_addr_mi300() for MI300 address formats. */ #define MI300_NUM_COL BIT(HWEIGHT(MI300_UMC_MCA_COL)) static void retire_row_mi300(struct atl_err *a_err) { unsigned long addr; struct page *p; u8 col; for (col = 0; col < MI300_NUM_COL; col++) { a_err->addr &= ~MI300_UMC_MCA_COL; a_err->addr |= FIELD_PREP(MI300_UMC_MCA_COL, col); addr = amd_convert_umc_mca_addr_to_sys_addr(a_err); if (IS_ERR_VALUE(addr)) continue; addr = PHYS_PFN(addr); /* * Skip invalid or already poisoned pages to avoid unnecessary * error messages from memory_failure(). */ p = pfn_to_online_page(addr); if (!p) continue; if (PageHWPoison(p)) continue; memory_failure(addr, 0); } } void amd_retire_dram_row(struct atl_err *a_err) { if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous) return retire_row_mi300(a_err); } EXPORT_SYMBOL_GPL(amd_retire_dram_row); static unsigned long get_addr(unsigned long addr) { if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous) return convert_dram_to_norm_addr_mi300(addr); return addr; } #define MCA_IPID_INST_ID_HI GENMASK_ULL(47, 44) static u8 get_die_id(struct atl_err *err) { /* * AMD Node ID is provided in MCA_IPID[InstanceIdHi], and this * needs to be divided by 4 to get the internal Die ID. */ if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous) { u8 node_id = FIELD_GET(MCA_IPID_INST_ID_HI, err->ipid); return node_id >> 2; } /* * For CPUs, this is the AMD Node ID modulo the number * of AMD Nodes per socket. */ return topology_amd_node_id(err->cpu) % topology_amd_nodes_per_pkg(); } #define UMC_CHANNEL_NUM GENMASK(31, 20) static u8 get_coh_st_inst_id(struct atl_err *err) { if (df_cfg.rev == DF4p5 && df_cfg.flags.heterogeneous) return get_coh_st_inst_id_mi300(err); return FIELD_GET(UMC_CHANNEL_NUM, err->ipid); } unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err) { u8 socket_id = topology_physical_package_id(err->cpu); u8 coh_st_inst_id = get_coh_st_inst_id(err); unsigned long addr = get_addr(err->addr); u8 die_id = get_die_id(err); pr_debug("socket_id=0x%x die_id=0x%x coh_st_inst_id=0x%x addr=0x%016lx", socket_id, die_id, coh_st_inst_id, addr); return norm_to_sys_addr(socket_id, die_id, coh_st_inst_id, addr); }