Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Mario Limonciello and committed by
Borislav Petkov (AMD)
d6caeafa 7dd57db4

+107 -100
+1
MAINTAINERS
··· 1122 1122 F: drivers/i2c/busses/i2c-amd-asf-plat.c 1123 1123 1124 1124 AMD NODE DRIVER 1125 + M: Mario Limonciello <mario.limonciello@amd.com> 1125 1126 M: Yazen Ghannam <yazen.ghannam@amd.com> 1126 1127 L: linux-kernel@vger.kernel.org 1127 1128 S: Supported
-3
arch/x86/include/asm/amd_nb.h
··· 21 21 extern int amd_get_subcaches(int); 22 22 extern int amd_set_subcaches(int, unsigned long); 23 23 24 - int __must_check amd_smn_read(u16 node, u32 address, u32 *value); 25 - int __must_check amd_smn_write(u16 node, u32 address, u32 value); 26 - 27 24 struct amd_l3_cache { 28 25 unsigned indices; 29 26 u8 subcaches[4];
+3
arch/x86/include/asm/amd_node.h
··· 30 30 return topology_amd_nodes_per_pkg() * topology_max_packages(); 31 31 } 32 32 33 + int __must_check amd_smn_read(u16 node, u32 address, u32 *value); 34 + int __must_check amd_smn_write(u16 node, u32 address, u32 value); 35 + 33 36 #endif /*_ASM_X86_AMD_NODE_H_*/
-89
arch/x86/kernel/amd_nb.c
··· 15 15 #include <linux/pci_ids.h> 16 16 #include <asm/amd_nb.h> 17 17 18 - /* Protect the PCI config register pairs used for SMN. */ 19 - static DEFINE_MUTEX(smn_mutex); 20 - 21 18 static u32 *flush_words; 22 19 23 20 static const struct pci_device_id amd_nb_misc_ids[] = { ··· 55 58 return (node < amd_northbridges.num) ? &amd_northbridges.nb[node] : NULL; 56 59 } 57 60 EXPORT_SYMBOL_GPL(node_to_amd_nb); 58 - 59 - /* 60 - * SMN accesses may fail in ways that are difficult to detect here in the called 61 - * functions amd_smn_read() and amd_smn_write(). Therefore, callers must do 62 - * their own checking based on what behavior they expect. 63 - * 64 - * For SMN reads, the returned value may be zero if the register is Read-as-Zero. 65 - * Or it may be a "PCI Error Response", e.g. all 0xFFs. The "PCI Error Response" 66 - * can be checked here, and a proper error code can be returned. 67 - * 68 - * But the Read-as-Zero response cannot be verified here. A value of 0 may be 69 - * correct in some cases, so callers must check that this correct is for the 70 - * register/fields they need. 71 - * 72 - * For SMN writes, success can be determined through a "write and read back" 73 - * However, this is not robust when done here. 74 - * 75 - * Possible issues: 76 - * 77 - * 1) Bits that are "Write-1-to-Clear". In this case, the read value should 78 - * *not* match the write value. 79 - * 80 - * 2) Bits that are "Read-as-Zero"/"Writes-Ignored". This information cannot be 81 - * known here. 82 - * 83 - * 3) Bits that are "Reserved / Set to 1". Ditto above. 84 - * 85 - * Callers of amd_smn_write() should do the "write and read back" check 86 - * themselves, if needed. 87 - * 88 - * For #1, they can see if their target bits got cleared. 89 - * 90 - * For #2 and #3, they can check if their target bits got set as intended. 91 - * 92 - * This matches what is done for RDMSR/WRMSR. As long as there's no #GP, then 93 - * the operation is considered a success, and the caller does their own 94 - * checking. 95 - */ 96 - static int __amd_smn_rw(u16 node, u32 address, u32 *value, bool write) 97 - { 98 - struct pci_dev *root; 99 - int err = -ENODEV; 100 - 101 - if (node >= amd_northbridges.num) 102 - goto out; 103 - 104 - root = node_to_amd_nb(node)->root; 105 - if (!root) 106 - goto out; 107 - 108 - mutex_lock(&smn_mutex); 109 - 110 - err = pci_write_config_dword(root, 0x60, address); 111 - if (err) { 112 - pr_warn("Error programming SMN address 0x%x.\n", address); 113 - goto out_unlock; 114 - } 115 - 116 - err = (write ? pci_write_config_dword(root, 0x64, *value) 117 - : pci_read_config_dword(root, 0x64, value)); 118 - 119 - out_unlock: 120 - mutex_unlock(&smn_mutex); 121 - 122 - out: 123 - return err; 124 - } 125 - 126 - int __must_check amd_smn_read(u16 node, u32 address, u32 *value) 127 - { 128 - int err = __amd_smn_rw(node, address, value, false); 129 - 130 - if (PCI_POSSIBLE_ERROR(*value)) { 131 - err = -ENODEV; 132 - *value = 0; 133 - } 134 - 135 - return err; 136 - } 137 - EXPORT_SYMBOL_GPL(amd_smn_read); 138 - 139 - int __must_check amd_smn_write(u16 node, u32 address, u32 value) 140 - { 141 - return __amd_smn_rw(node, address, &value, true); 142 - } 143 - EXPORT_SYMBOL_GPL(amd_smn_write); 144 61 145 62 static int amd_cache_northbridges(void) 146 63 {
+90
arch/x86/kernel/amd_node.c
··· 8 8 * Author: Yazen Ghannam <Yazen.Ghannam@amd.com> 9 9 */ 10 10 11 + #include <asm/amd_nb.h> 11 12 #include <asm/amd_node.h> 12 13 13 14 /* ··· 89 88 pci_dbg(root, "is root for AMD node %u\n", node); 90 89 return root; 91 90 } 91 + 92 + /* Protect the PCI config register pairs used for SMN. */ 93 + static DEFINE_MUTEX(smn_mutex); 94 + 95 + /* 96 + * SMN accesses may fail in ways that are difficult to detect here in the called 97 + * functions amd_smn_read() and amd_smn_write(). Therefore, callers must do 98 + * their own checking based on what behavior they expect. 99 + * 100 + * For SMN reads, the returned value may be zero if the register is Read-as-Zero. 101 + * Or it may be a "PCI Error Response", e.g. all 0xFFs. The "PCI Error Response" 102 + * can be checked here, and a proper error code can be returned. 103 + * 104 + * But the Read-as-Zero response cannot be verified here. A value of 0 may be 105 + * correct in some cases, so callers must check that this correct is for the 106 + * register/fields they need. 107 + * 108 + * For SMN writes, success can be determined through a "write and read back" 109 + * However, this is not robust when done here. 110 + * 111 + * Possible issues: 112 + * 113 + * 1) Bits that are "Write-1-to-Clear". In this case, the read value should 114 + * *not* match the write value. 115 + * 116 + * 2) Bits that are "Read-as-Zero"/"Writes-Ignored". This information cannot be 117 + * known here. 118 + * 119 + * 3) Bits that are "Reserved / Set to 1". Ditto above. 120 + * 121 + * Callers of amd_smn_write() should do the "write and read back" check 122 + * themselves, if needed. 123 + * 124 + * For #1, they can see if their target bits got cleared. 125 + * 126 + * For #2 and #3, they can check if their target bits got set as intended. 127 + * 128 + * This matches what is done for RDMSR/WRMSR. As long as there's no #GP, then 129 + * the operation is considered a success, and the caller does their own 130 + * checking. 131 + */ 132 + static int __amd_smn_rw(u16 node, u32 address, u32 *value, bool write) 133 + { 134 + struct pci_dev *root; 135 + int err = -ENODEV; 136 + 137 + if (node >= amd_nb_num()) 138 + goto out; 139 + 140 + root = node_to_amd_nb(node)->root; 141 + if (!root) 142 + goto out; 143 + 144 + mutex_lock(&smn_mutex); 145 + 146 + err = pci_write_config_dword(root, 0x60, address); 147 + if (err) { 148 + pr_warn("Error programming SMN address 0x%x.\n", address); 149 + goto out_unlock; 150 + } 151 + 152 + err = (write ? pci_write_config_dword(root, 0x64, *value) 153 + : pci_read_config_dword(root, 0x64, value)); 154 + 155 + out_unlock: 156 + mutex_unlock(&smn_mutex); 157 + 158 + out: 159 + return err; 160 + } 161 + 162 + int __must_check amd_smn_read(u16 node, u32 address, u32 *value) 163 + { 164 + int err = __amd_smn_rw(node, address, value, false); 165 + 166 + if (PCI_POSSIBLE_ERROR(*value)) { 167 + err = -ENODEV; 168 + *value = 0; 169 + } 170 + 171 + return err; 172 + } 173 + EXPORT_SYMBOL_GPL(amd_smn_read); 174 + 175 + int __must_check amd_smn_write(u16 node, u32 address, u32 value) 176 + { 177 + return __amd_smn_rw(node, address, &value, true); 178 + } 179 + EXPORT_SYMBOL_GPL(amd_smn_write);
+2 -2
arch/x86/pci/fixup.c
··· 9 9 #include <linux/pci.h> 10 10 #include <linux/suspend.h> 11 11 #include <linux/vgaarb.h> 12 - #include <asm/amd_nb.h> 12 + #include <asm/amd_node.h> 13 13 #include <asm/hpet.h> 14 14 #include <asm/pci_x86.h> 15 15 ··· 828 828 829 829 #endif 830 830 831 - #ifdef CONFIG_AMD_NB 831 + #ifdef CONFIG_AMD_NODE 832 832 833 833 #define AMD_15B8_RCC_DEV2_EPF0_STRAP2 0x10136008 834 834 #define AMD_15B8_RCC_DEV2_EPF0_STRAP2_NO_SOFT_RESET_DEV2_F0_MASK 0x00000080L
+1
drivers/edac/Kconfig
··· 78 78 config EDAC_AMD64 79 79 tristate "AMD64 (Opteron, Athlon64)" 80 80 depends on AMD_NB && EDAC_DECODE_MCE 81 + depends on AMD_NODE 81 82 imply AMD_ATL 82 83 help 83 84 Support for error detection and correction of DRAM ECC errors on
+1
drivers/edac/amd64_edac.c
··· 2 2 #include <linux/ras.h> 3 3 #include "amd64_edac.h" 4 4 #include <asm/amd_nb.h> 5 + #include <asm/amd_node.h> 5 6 6 7 static struct edac_pci_ctl_info *pci_ctl; 7 8
+1 -1
drivers/hwmon/Kconfig
··· 324 324 325 325 config SENSORS_K10TEMP 326 326 tristate "AMD Family 10h+ temperature sensor" 327 - depends on X86 && PCI && AMD_NB 327 + depends on X86 && PCI && AMD_NODE 328 328 help 329 329 If you say yes here you get support for the temperature 330 330 sensor(s) inside your CPU. Supported are later revisions of
+1 -1
drivers/hwmon/k10temp.c
··· 20 20 #include <linux/module.h> 21 21 #include <linux/pci.h> 22 22 #include <linux/pci_ids.h> 23 - #include <asm/amd_nb.h> 23 + #include <asm/amd_node.h> 24 24 #include <asm/processor.h> 25 25 26 26 MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor");
+1 -1
drivers/platform/x86/amd/pmc/Kconfig
··· 5 5 6 6 config AMD_PMC 7 7 tristate "AMD SoC PMC driver" 8 - depends on ACPI && PCI && RTC_CLASS && AMD_NB 8 + depends on ACPI && PCI && RTC_CLASS && AMD_NODE 9 9 depends on SUSPEND 10 10 select SERIO 11 11 help
+2 -1
drivers/platform/x86/amd/pmc/pmc.c
··· 10 10 11 11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 12 13 - #include <asm/amd_nb.h> 14 13 #include <linux/acpi.h> 15 14 #include <linux/bitfield.h> 16 15 #include <linux/bits.h> ··· 26 27 #include <linux/suspend.h> 27 28 #include <linux/seq_file.h> 28 29 #include <linux/uaccess.h> 30 + 31 + #include <asm/amd_node.h> 29 32 30 33 #include "pmc.h" 31 34
+1 -1
drivers/platform/x86/amd/pmf/Kconfig
··· 7 7 tristate "AMD Platform Management Framework" 8 8 depends on ACPI && PCI 9 9 depends on POWER_SUPPLY 10 - depends on AMD_NB 10 + depends on AMD_NODE 11 11 select ACPI_PLATFORM_PROFILE 12 12 depends on TEE && AMDTEE 13 13 depends on AMD_SFH_HID
+1 -1
drivers/platform/x86/amd/pmf/core.c
··· 8 8 * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> 9 9 */ 10 10 11 - #include <asm/amd_nb.h> 12 11 #include <linux/debugfs.h> 13 12 #include <linux/iopoll.h> 14 13 #include <linux/module.h> 15 14 #include <linux/pci.h> 16 15 #include <linux/platform_device.h> 17 16 #include <linux/power_supply.h> 17 + #include <asm/amd_node.h> 18 18 #include "pmf.h" 19 19 20 20 /* PMF-SMU communication registers */
+1
drivers/ras/amd/atl/Kconfig
··· 10 10 config AMD_ATL 11 11 tristate "AMD Address Translation Library" 12 12 depends on AMD_NB && X86_64 && RAS 13 + depends on AMD_NODE 13 14 depends on MEMORY_FAILURE 14 15 default N 15 16 help
+1
drivers/ras/amd/atl/internal.h
··· 18 18 #include <linux/ras.h> 19 19 20 20 #include <asm/amd_nb.h> 21 + #include <asm/amd_node.h> 21 22 22 23 #include "reg_fields.h" 23 24