Commit 95d057f5 authored by Yazen Ghannam's avatar Yazen Ghannam Committed by Borislav Petkov

x86/MCE/AMD: Don't cache block addresses on SMCA systems

On legacy systems, the addresses of the MCA_MISC* registers need to be
recursively discovered based on a Block Pointer field in the registers.

On Scalable MCA systems, the register space is fixed, and particular
addresses can be derived by regular offsets for bank and register type.
This fixed address space includes the MCA_MISC* registers.

MCA_MISC0 is always available for each MCA bank. MCA_MISC1 through
MCA_MISC4 are considered available if MCA_MISC0[BlkPtr]=1.

Cache the value of MCA_MISC0[BlkPtr] for each bank and per CPU. This
needs to be done only during init. The values should be saved per CPU
to accommodate heterogeneous SMCA systems.

Redo smca_get_block_address() to directly return the block addresses.
Signed-off-by: default avatarYazen Ghannam <yazen.ghannam@amd.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "linux-edac@vger.kernel.org" <linux-edac@vger.kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Tony Luck <tony.luck@intel.com>
Cc: "x86@kernel.org" <x86@kernel.org>
Link: https://lkml.kernel.org/r/20190607201752.221446-4-Yazen.Ghannam@amd.com
parent b4914508
...@@ -101,11 +101,6 @@ static struct smca_bank_name smca_names[] = { ...@@ -101,11 +101,6 @@ static struct smca_bank_name smca_names[] = {
[SMCA_PCIE] = { "pcie", "PCI Express Unit" }, [SMCA_PCIE] = { "pcie", "PCI Express Unit" },
}; };
static u32 smca_bank_addrs[MAX_NR_BANKS][NR_BLOCKS] __ro_after_init =
{
[0 ... MAX_NR_BANKS - 1] = { [0 ... NR_BLOCKS - 1] = -1 }
};
static const char *smca_get_name(enum smca_bank_types t) static const char *smca_get_name(enum smca_bank_types t)
{ {
if (t >= N_SMCA_BANK_TYPES) if (t >= N_SMCA_BANK_TYPES)
...@@ -199,6 +194,9 @@ static char buf_mcatype[MAX_MCATYPE_NAME_LEN]; ...@@ -199,6 +194,9 @@ static char buf_mcatype[MAX_MCATYPE_NAME_LEN];
static DEFINE_PER_CPU(struct threshold_bank **, threshold_banks); static DEFINE_PER_CPU(struct threshold_bank **, threshold_banks);
static DEFINE_PER_CPU(unsigned int, bank_map); /* see which banks are on */ static DEFINE_PER_CPU(unsigned int, bank_map); /* see which banks are on */
/* Map of banks that have more than MCA_MISC0 available. */
static DEFINE_PER_CPU(u32, smca_misc_banks_map);
static void amd_threshold_interrupt(void); static void amd_threshold_interrupt(void);
static void amd_deferred_error_interrupt(void); static void amd_deferred_error_interrupt(void);
...@@ -208,6 +206,28 @@ static void default_deferred_error_interrupt(void) ...@@ -208,6 +206,28 @@ static void default_deferred_error_interrupt(void)
} }
void (*deferred_error_int_vector)(void) = default_deferred_error_interrupt; void (*deferred_error_int_vector)(void) = default_deferred_error_interrupt;
static void smca_set_misc_banks_map(unsigned int bank, unsigned int cpu)
{
u32 low, high;
/*
* For SMCA enabled processors, BLKPTR field of the first MISC register
* (MCx_MISC0) indicates presence of additional MISC regs set (MISC1-4).
*/
if (rdmsr_safe(MSR_AMD64_SMCA_MCx_CONFIG(bank), &low, &high))
return;
if (!(low & MCI_CONFIG_MCAX))
return;
if (rdmsr_safe(MSR_AMD64_SMCA_MCx_MISC(bank), &low, &high))
return;
if (low & MASK_BLKPTR_LO)
per_cpu(smca_misc_banks_map, cpu) |= BIT(bank);
}
static void smca_configure(unsigned int bank, unsigned int cpu) static void smca_configure(unsigned int bank, unsigned int cpu)
{ {
unsigned int i, hwid_mcatype; unsigned int i, hwid_mcatype;
...@@ -245,6 +265,8 @@ static void smca_configure(unsigned int bank, unsigned int cpu) ...@@ -245,6 +265,8 @@ static void smca_configure(unsigned int bank, unsigned int cpu)
wrmsr(smca_config, low, high); wrmsr(smca_config, low, high);
} }
smca_set_misc_banks_map(bank, cpu);
/* Return early if this bank was already initialized. */ /* Return early if this bank was already initialized. */
if (smca_banks[bank].hwid) if (smca_banks[bank].hwid)
return; return;
...@@ -455,42 +477,21 @@ static void deferred_error_interrupt_enable(struct cpuinfo_x86 *c) ...@@ -455,42 +477,21 @@ static void deferred_error_interrupt_enable(struct cpuinfo_x86 *c)
wrmsr(MSR_CU_DEF_ERR, low, high); wrmsr(MSR_CU_DEF_ERR, low, high);
} }
static u32 smca_get_block_address(unsigned int bank, unsigned int block) static u32 smca_get_block_address(unsigned int bank, unsigned int block,
unsigned int cpu)
{ {
u32 low, high;
u32 addr = 0;
if (smca_get_bank_type(bank) == SMCA_RESERVED)
return addr;
if (!block) if (!block)
return MSR_AMD64_SMCA_MCx_MISC(bank); return MSR_AMD64_SMCA_MCx_MISC(bank);
/* Check our cache first: */ if (!(per_cpu(smca_misc_banks_map, cpu) & BIT(bank)))
if (smca_bank_addrs[bank][block] != -1) return 0;
return smca_bank_addrs[bank][block];
/*
* For SMCA enabled processors, BLKPTR field of the first MISC register
* (MCx_MISC0) indicates presence of additional MISC regs set (MISC1-4).
*/
if (rdmsr_safe(MSR_AMD64_SMCA_MCx_CONFIG(bank), &low, &high))
goto out;
if (!(low & MCI_CONFIG_MCAX))
goto out;
if (!rdmsr_safe(MSR_AMD64_SMCA_MCx_MISC(bank), &low, &high) &&
(low & MASK_BLKPTR_LO))
addr = MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1);
out: return MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1);
smca_bank_addrs[bank][block] = addr;
return addr;
} }
static u32 get_block_address(u32 current_addr, u32 low, u32 high, static u32 get_block_address(u32 current_addr, u32 low, u32 high,
unsigned int bank, unsigned int block) unsigned int bank, unsigned int block,
unsigned int cpu)
{ {
u32 addr = 0, offset = 0; u32 addr = 0, offset = 0;
...@@ -498,7 +499,7 @@ static u32 get_block_address(u32 current_addr, u32 low, u32 high, ...@@ -498,7 +499,7 @@ static u32 get_block_address(u32 current_addr, u32 low, u32 high,
return addr; return addr;
if (mce_flags.smca) if (mce_flags.smca)
return smca_get_block_address(bank, block); return smca_get_block_address(bank, block, cpu);
/* Fall back to method we used for older processors: */ /* Fall back to method we used for older processors: */
switch (block) { switch (block) {
...@@ -637,7 +638,7 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) ...@@ -637,7 +638,7 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
disable_err_thresholding(c, bank); disable_err_thresholding(c, bank);
for (block = 0; block < NR_BLOCKS; ++block) { for (block = 0; block < NR_BLOCKS; ++block) {
address = get_block_address(address, low, high, bank, block); address = get_block_address(address, low, high, bank, block, cpu);
if (!address) if (!address)
break; break;
...@@ -1254,7 +1255,7 @@ static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank, ...@@ -1254,7 +1255,7 @@ static int allocate_threshold_blocks(unsigned int cpu, unsigned int bank,
if (err) if (err)
goto out_free; goto out_free;
recurse: recurse:
address = get_block_address(address, low, high, bank, ++block); address = get_block_address(address, low, high, bank, ++block, cpu);
if (!address) if (!address)
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment