Skip to content

Commit dc52439

Browse files
yghannambp3tk0v
authored andcommitted
x86/amd_nb: Enhance SMN access error checking
AMD Zen-based systems use a System Management Network (SMN) that provides access to implementation-specific registers. SMN accesses are done indirectly through an index/data pair in PCI config space. The accesses can fail for a variety of reasons. Include code comments to describe some possible scenarios. Require error checking for callers of amd_smn_read() and amd_smn_write(). This is needed because many error conditions cannot be checked by these functions. [ bp: Touchup comment. ] Signed-off-by: Yazen Ghannam <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Reviewed-by: Mario Limonciello <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent c2d79cc commit dc52439

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

arch/x86/include/asm/amd_nb.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ extern int amd_numa_init(void);
2121
extern int amd_get_subcaches(int);
2222
extern int amd_set_subcaches(int, unsigned long);
2323

24-
extern int amd_smn_read(u16 node, u32 address, u32 *value);
25-
extern int amd_smn_write(u16 node, u32 address, u32 value);
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);
2626

2727
struct amd_l3_cache {
2828
unsigned indices;

arch/x86/kernel/amd_nb.c

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,43 @@ static struct pci_dev *next_northbridge(struct pci_dev *dev,
180180
return dev;
181181
}
182182

183+
/*
184+
* SMN accesses may fail in ways that are difficult to detect here in the called
185+
* functions amd_smn_read() and amd_smn_write(). Therefore, callers must do
186+
* their own checking based on what behavior they expect.
187+
*
188+
* For SMN reads, the returned value may be zero if the register is Read-as-Zero.
189+
* Or it may be a "PCI Error Response", e.g. all 0xFFs. The "PCI Error Response"
190+
* can be checked here, and a proper error code can be returned.
191+
*
192+
* But the Read-as-Zero response cannot be verified here. A value of 0 may be
193+
* correct in some cases, so callers must check that this correct is for the
194+
* register/fields they need.
195+
*
196+
* For SMN writes, success can be determined through a "write and read back"
197+
* However, this is not robust when done here.
198+
*
199+
* Possible issues:
200+
*
201+
* 1) Bits that are "Write-1-to-Clear". In this case, the read value should
202+
* *not* match the write value.
203+
*
204+
* 2) Bits that are "Read-as-Zero"/"Writes-Ignored". This information cannot be
205+
* known here.
206+
*
207+
* 3) Bits that are "Reserved / Set to 1". Ditto above.
208+
*
209+
* Callers of amd_smn_write() should do the "write and read back" check
210+
* themselves, if needed.
211+
*
212+
* For #1, they can see if their target bits got cleared.
213+
*
214+
* For #2 and #3, they can check if their target bits got set as intended.
215+
*
216+
* This matches what is done for RDMSR/WRMSR. As long as there's no #GP, then
217+
* the operation is considered a success, and the caller does their own
218+
* checking.
219+
*/
183220
static int __amd_smn_rw(u16 node, u32 address, u32 *value, bool write)
184221
{
185222
struct pci_dev *root;
@@ -202,9 +239,6 @@ static int __amd_smn_rw(u16 node, u32 address, u32 *value, bool write)
202239

203240
err = (write ? pci_write_config_dword(root, 0x64, *value)
204241
: pci_read_config_dword(root, 0x64, value));
205-
if (err)
206-
pr_warn("Error %s SMN address 0x%x.\n",
207-
(write ? "writing to" : "reading from"), address);
208242

209243
out_unlock:
210244
mutex_unlock(&smn_mutex);
@@ -213,7 +247,7 @@ static int __amd_smn_rw(u16 node, u32 address, u32 *value, bool write)
213247
return err;
214248
}
215249

216-
int amd_smn_read(u16 node, u32 address, u32 *value)
250+
int __must_check amd_smn_read(u16 node, u32 address, u32 *value)
217251
{
218252
int err = __amd_smn_rw(node, address, value, false);
219253

@@ -226,7 +260,7 @@ int amd_smn_read(u16 node, u32 address, u32 *value)
226260
}
227261
EXPORT_SYMBOL_GPL(amd_smn_read);
228262

229-
int amd_smn_write(u16 node, u32 address, u32 value)
263+
int __must_check amd_smn_write(u16 node, u32 address, u32 value)
230264
{
231265
return __amd_smn_rw(node, address, &value, true);
232266
}

0 commit comments

Comments
 (0)