x86/amd_nb: Move SMN access code to a new amd_node driver
SMN access was bolted into amd_nb mostly as convenience. This has limitations though that require incurring tech debt to keep it working. Move SMN access to the newly introduced AMD Node driver. Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Acked-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> # pdx86 Acked-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> # PMF, PMC Link: https://lore.kernel.org/r/20241206161210.163701-11-yazen.ghannam@amd.com
This commit is contained in:
parent
7dd57db495
commit
d6caeafaa3
16 changed files with 107 additions and 100 deletions
|
@ -1122,6 +1122,7 @@ S: Supported
|
|||
F: drivers/i2c/busses/i2c-amd-asf-plat.c
|
||||
|
||||
AMD NODE DRIVER
|
||||
M: Mario Limonciello <mario.limonciello@amd.com>
|
||||
M: Yazen Ghannam <yazen.ghannam@amd.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
|
|
|
@ -21,9 +21,6 @@ extern int amd_numa_init(void);
|
|||
extern int amd_get_subcaches(int);
|
||||
extern int amd_set_subcaches(int, unsigned long);
|
||||
|
||||
int __must_check amd_smn_read(u16 node, u32 address, u32 *value);
|
||||
int __must_check amd_smn_write(u16 node, u32 address, u32 value);
|
||||
|
||||
struct amd_l3_cache {
|
||||
unsigned indices;
|
||||
u8 subcaches[4];
|
||||
|
|
|
@ -30,4 +30,7 @@ static inline u16 amd_num_nodes(void)
|
|||
return topology_amd_nodes_per_pkg() * topology_max_packages();
|
||||
}
|
||||
|
||||
int __must_check amd_smn_read(u16 node, u32 address, u32 *value);
|
||||
int __must_check amd_smn_write(u16 node, u32 address, u32 value);
|
||||
|
||||
#endif /*_ASM_X86_AMD_NODE_H_*/
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
#include <linux/pci_ids.h>
|
||||
#include <asm/amd_nb.h>
|
||||
|
||||
/* Protect the PCI config register pairs used for SMN. */
|
||||
static DEFINE_MUTEX(smn_mutex);
|
||||
|
||||
static u32 *flush_words;
|
||||
|
||||
static const struct pci_device_id amd_nb_misc_ids[] = {
|
||||
|
@ -59,92 +56,6 @@ struct amd_northbridge *node_to_amd_nb(int node)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(node_to_amd_nb);
|
||||
|
||||
/*
|
||||
* SMN accesses may fail in ways that are difficult to detect here in the called
|
||||
* functions amd_smn_read() and amd_smn_write(). Therefore, callers must do
|
||||
* their own checking based on what behavior they expect.
|
||||
*
|
||||
* For SMN reads, the returned value may be zero if the register is Read-as-Zero.
|
||||
* Or it may be a "PCI Error Response", e.g. all 0xFFs. The "PCI Error Response"
|
||||
* can be checked here, and a proper error code can be returned.
|
||||
*
|
||||
* But the Read-as-Zero response cannot be verified here. A value of 0 may be
|
||||
* correct in some cases, so callers must check that this correct is for the
|
||||
* register/fields they need.
|
||||
*
|
||||
* For SMN writes, success can be determined through a "write and read back"
|
||||
* However, this is not robust when done here.
|
||||
*
|
||||
* Possible issues:
|
||||
*
|
||||
* 1) Bits that are "Write-1-to-Clear". In this case, the read value should
|
||||
* *not* match the write value.
|
||||
*
|
||||
* 2) Bits that are "Read-as-Zero"/"Writes-Ignored". This information cannot be
|
||||
* known here.
|
||||
*
|
||||
* 3) Bits that are "Reserved / Set to 1". Ditto above.
|
||||
*
|
||||
* Callers of amd_smn_write() should do the "write and read back" check
|
||||
* themselves, if needed.
|
||||
*
|
||||
* For #1, they can see if their target bits got cleared.
|
||||
*
|
||||
* For #2 and #3, they can check if their target bits got set as intended.
|
||||
*
|
||||
* This matches what is done for RDMSR/WRMSR. As long as there's no #GP, then
|
||||
* the operation is considered a success, and the caller does their own
|
||||
* checking.
|
||||
*/
|
||||
static int __amd_smn_rw(u16 node, u32 address, u32 *value, bool write)
|
||||
{
|
||||
struct pci_dev *root;
|
||||
int err = -ENODEV;
|
||||
|
||||
if (node >= amd_northbridges.num)
|
||||
goto out;
|
||||
|
||||
root = node_to_amd_nb(node)->root;
|
||||
if (!root)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&smn_mutex);
|
||||
|
||||
err = pci_write_config_dword(root, 0x60, address);
|
||||
if (err) {
|
||||
pr_warn("Error programming SMN address 0x%x.\n", address);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
err = (write ? pci_write_config_dword(root, 0x64, *value)
|
||||
: pci_read_config_dword(root, 0x64, value));
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&smn_mutex);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int __must_check amd_smn_read(u16 node, u32 address, u32 *value)
|
||||
{
|
||||
int err = __amd_smn_rw(node, address, value, false);
|
||||
|
||||
if (PCI_POSSIBLE_ERROR(*value)) {
|
||||
err = -ENODEV;
|
||||
*value = 0;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_smn_read);
|
||||
|
||||
int __must_check amd_smn_write(u16 node, u32 address, u32 value)
|
||||
{
|
||||
return __amd_smn_rw(node, address, &value, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_smn_write);
|
||||
|
||||
static int amd_cache_northbridges(void)
|
||||
{
|
||||
struct amd_northbridge *nb;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
|
||||
*/
|
||||
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd_node.h>
|
||||
|
||||
/*
|
||||
|
@ -88,3 +89,92 @@ struct pci_dev *amd_node_get_root(u16 node)
|
|||
pci_dbg(root, "is root for AMD node %u\n", node);
|
||||
return root;
|
||||
}
|
||||
|
||||
/* Protect the PCI config register pairs used for SMN. */
|
||||
static DEFINE_MUTEX(smn_mutex);
|
||||
|
||||
/*
|
||||
* SMN accesses may fail in ways that are difficult to detect here in the called
|
||||
* functions amd_smn_read() and amd_smn_write(). Therefore, callers must do
|
||||
* their own checking based on what behavior they expect.
|
||||
*
|
||||
* For SMN reads, the returned value may be zero if the register is Read-as-Zero.
|
||||
* Or it may be a "PCI Error Response", e.g. all 0xFFs. The "PCI Error Response"
|
||||
* can be checked here, and a proper error code can be returned.
|
||||
*
|
||||
* But the Read-as-Zero response cannot be verified here. A value of 0 may be
|
||||
* correct in some cases, so callers must check that this correct is for the
|
||||
* register/fields they need.
|
||||
*
|
||||
* For SMN writes, success can be determined through a "write and read back"
|
||||
* However, this is not robust when done here.
|
||||
*
|
||||
* Possible issues:
|
||||
*
|
||||
* 1) Bits that are "Write-1-to-Clear". In this case, the read value should
|
||||
* *not* match the write value.
|
||||
*
|
||||
* 2) Bits that are "Read-as-Zero"/"Writes-Ignored". This information cannot be
|
||||
* known here.
|
||||
*
|
||||
* 3) Bits that are "Reserved / Set to 1". Ditto above.
|
||||
*
|
||||
* Callers of amd_smn_write() should do the "write and read back" check
|
||||
* themselves, if needed.
|
||||
*
|
||||
* For #1, they can see if their target bits got cleared.
|
||||
*
|
||||
* For #2 and #3, they can check if their target bits got set as intended.
|
||||
*
|
||||
* This matches what is done for RDMSR/WRMSR. As long as there's no #GP, then
|
||||
* the operation is considered a success, and the caller does their own
|
||||
* checking.
|
||||
*/
|
||||
static int __amd_smn_rw(u16 node, u32 address, u32 *value, bool write)
|
||||
{
|
||||
struct pci_dev *root;
|
||||
int err = -ENODEV;
|
||||
|
||||
if (node >= amd_nb_num())
|
||||
goto out;
|
||||
|
||||
root = node_to_amd_nb(node)->root;
|
||||
if (!root)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&smn_mutex);
|
||||
|
||||
err = pci_write_config_dword(root, 0x60, address);
|
||||
if (err) {
|
||||
pr_warn("Error programming SMN address 0x%x.\n", address);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
err = (write ? pci_write_config_dword(root, 0x64, *value)
|
||||
: pci_read_config_dword(root, 0x64, value));
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&smn_mutex);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int __must_check amd_smn_read(u16 node, u32 address, u32 *value)
|
||||
{
|
||||
int err = __amd_smn_rw(node, address, value, false);
|
||||
|
||||
if (PCI_POSSIBLE_ERROR(*value)) {
|
||||
err = -ENODEV;
|
||||
*value = 0;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_smn_read);
|
||||
|
||||
int __must_check amd_smn_write(u16 node, u32 address, u32 value)
|
||||
{
|
||||
return __amd_smn_rw(node, address, &value, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_smn_write);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/vgaarb.h>
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/hpet.h>
|
||||
#include <asm/pci_x86.h>
|
||||
|
||||
|
@ -828,7 +828,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7910, rs690_fix_64bit_dma);
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AMD_NB
|
||||
#ifdef CONFIG_AMD_NODE
|
||||
|
||||
#define AMD_15B8_RCC_DEV2_EPF0_STRAP2 0x10136008
|
||||
#define AMD_15B8_RCC_DEV2_EPF0_STRAP2_NO_SOFT_RESET_DEV2_F0_MASK 0x00000080L
|
||||
|
|
|
@ -78,6 +78,7 @@ config EDAC_GHES
|
|||
config EDAC_AMD64
|
||||
tristate "AMD64 (Opteron, Athlon64)"
|
||||
depends on AMD_NB && EDAC_DECODE_MCE
|
||||
depends on AMD_NODE
|
||||
imply AMD_ATL
|
||||
help
|
||||
Support for error detection and correction of DRAM ECC errors on
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <linux/ras.h>
|
||||
#include "amd64_edac.h"
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd_node.h>
|
||||
|
||||
static struct edac_pci_ctl_info *pci_ctl;
|
||||
|
||||
|
|
|
@ -324,7 +324,7 @@ config SENSORS_K8TEMP
|
|||
|
||||
config SENSORS_K10TEMP
|
||||
tristate "AMD Family 10h+ temperature sensor"
|
||||
depends on X86 && PCI && AMD_NB
|
||||
depends on X86 && PCI && AMD_NODE
|
||||
help
|
||||
If you say yes here you get support for the temperature
|
||||
sensor(s) inside your CPU. Supported are later revisions of
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor");
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
config AMD_PMC
|
||||
tristate "AMD SoC PMC driver"
|
||||
depends on ACPI && PCI && RTC_CLASS && AMD_NB
|
||||
depends on ACPI && PCI && RTC_CLASS && AMD_NODE
|
||||
depends on SUSPEND
|
||||
select SERIO
|
||||
help
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <asm/amd_nb.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
|
@ -28,6 +27,8 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
/* SMU communication registers */
|
||||
|
|
|
@ -7,7 +7,7 @@ config AMD_PMF
|
|||
tristate "AMD Platform Management Framework"
|
||||
depends on ACPI && PCI
|
||||
depends on POWER_SUPPLY
|
||||
depends on AMD_NB
|
||||
depends on AMD_NODE
|
||||
select ACPI_PLATFORM_PROFILE
|
||||
depends on TEE && AMDTEE
|
||||
depends on AMD_SFH_HID
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
* Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
|
||||
*/
|
||||
|
||||
#include <asm/amd_nb.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <asm/amd_node.h>
|
||||
#include "pmf.h"
|
||||
|
||||
/* PMF-SMU communication registers */
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
config AMD_ATL
|
||||
tristate "AMD Address Translation Library"
|
||||
depends on AMD_NB && X86_64 && RAS
|
||||
depends on AMD_NODE
|
||||
depends on MEMORY_FAILURE
|
||||
default N
|
||||
help
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/ras.h>
|
||||
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd_node.h>
|
||||
|
||||
#include "reg_fields.h"
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue