mirror of https://github.com/torvalds/linux.git
Miscellaneous fixes:
- Fix AMD PCI root device caching regression that triggers
on certain firmware variants
- Fix the zen5_rdseed_microcode[] array to be NULL-terminated
- Add more AMD models to microcode signature checking
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-----BEGIN PGP SIGNATURE-----
iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmkPQyURHG1pbmdvQGtl
cm5lbC5vcmcACgkQEnMQ0APhK1gmBw/+NG6jg8ICxDRcwNSlSfEjOr8EWe7WrmcD
Y9gYGHi4LbG+8fZCqOZFBUSAePIBJUqcMsRk+CgAxDwZyiJt7jqaXTSpiRTPR9pa
IjI5FF5qhypTRk5/MgJObKgnmkJwduCuTrkU/9neeLSSZigiOQO1i3imM/KhCSvG
HGb0qwgDxBdc/uhuiK81hLVHs1CEBnNHoRl8u6gkkNXMFkzVx+5SGWN3BdRwHZuP
Ttw/B5XZBLYGY0Rs+AUgTnKWdR3DHfZafPnV4mHmAQ3Y5HI49bGxwUqpf+xkx6Mv
1t/UBPOLG2WlBlO+WJF27/yPit3ITo8yltEBKTsZxTtoXp8cG/qcnfwZnZ5At0/v
sW94Dg3H+pSsNBSEfDzeywdDpGequ6wcj2DxQDg7qNLSdoOwDARvJD0j21ckdNDq
HUf8dn8H6Sh+nqQLbWu8nnl6NZUmtaiw0bTsVQjQi8decnpKhbhyLlgSGA0GuWkY
QzT5mDZuf70N2v+hS03MDtIQvTfF5CbG6LIvUJnzZyge4CWh65JzkTmqGIgbYexV
CrxMFNY/G6PiTdf7IONG+/qCUiiCRtCFGGNSxkj5NAo0zyX0tInRA2CZHU6M+Dvk
T7+EOoPl2vPS9hgw9eeMk/0UgjbX8JZSX1pTAcRkSH75GlNqPl4ytxkH+QhvM8vd
xYqAjIBLA84=
=duTI
-----END PGP SIGNATURE-----
Merge tag 'x86-urgent-2025-11-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Ingo Molnar:
- Fix AMD PCI root device caching regression that triggers
on certain firmware variants
- Fix the zen5_rdseed_microcode[] array to be NULL-terminated
- Add more AMD models to microcode signature checking
* tag 'x86-urgent-2025-11-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/microcode/AMD: Add more known models to entry sign checking
x86/CPU/AMD: Add missing terminator for zen5_rdseed_microcode
x86/amd_node: Fix AMD root device caching
This commit is contained in:
commit
0d7bee10be
|
|
@ -23,7 +23,6 @@
|
|||
#define AMD_NODE0_PCI_SLOT 0x18
|
||||
|
||||
struct pci_dev *amd_node_get_func(u16 node, u8 func);
|
||||
struct pci_dev *amd_node_get_root(u16 node);
|
||||
|
||||
static inline u16 amd_num_nodes(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,62 +34,6 @@ struct pci_dev *amd_node_get_func(u16 node, u8 func)
|
|||
return pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(AMD_NODE0_PCI_SLOT + node, func));
|
||||
}
|
||||
|
||||
#define DF_BLK_INST_CNT 0x040
|
||||
#define DF_CFG_ADDR_CNTL_LEGACY 0x084
|
||||
#define DF_CFG_ADDR_CNTL_DF4 0xC04
|
||||
|
||||
#define DF_MAJOR_REVISION GENMASK(27, 24)
|
||||
|
||||
static u16 get_cfg_addr_cntl_offset(struct pci_dev *df_f0)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Revision fields added for DF4 and later.
|
||||
*
|
||||
* Major revision of '0' is found pre-DF4. Field is Read-as-Zero.
|
||||
*/
|
||||
if (pci_read_config_dword(df_f0, DF_BLK_INST_CNT, ®))
|
||||
return 0;
|
||||
|
||||
if (reg & DF_MAJOR_REVISION)
|
||||
return DF_CFG_ADDR_CNTL_DF4;
|
||||
|
||||
return DF_CFG_ADDR_CNTL_LEGACY;
|
||||
}
|
||||
|
||||
struct pci_dev *amd_node_get_root(u16 node)
|
||||
{
|
||||
struct pci_dev *root;
|
||||
u16 cntl_off;
|
||||
u8 bus;
|
||||
|
||||
if (!cpu_feature_enabled(X86_FEATURE_ZEN))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* D18F0xXXX [Config Address Control] (DF::CfgAddressCntl)
|
||||
* Bits [7:0] (SecBusNum) holds the bus number of the root device for
|
||||
* this Data Fabric instance. The segment, device, and function will be 0.
|
||||
*/
|
||||
struct pci_dev *df_f0 __free(pci_dev_put) = amd_node_get_func(node, 0);
|
||||
if (!df_f0)
|
||||
return NULL;
|
||||
|
||||
cntl_off = get_cfg_addr_cntl_offset(df_f0);
|
||||
if (!cntl_off)
|
||||
return NULL;
|
||||
|
||||
if (pci_read_config_byte(df_f0, cntl_off, &bus))
|
||||
return NULL;
|
||||
|
||||
/* Grab the pointer for the actual root device instance. */
|
||||
root = pci_get_domain_bus_and_slot(0, bus, 0);
|
||||
|
||||
pci_dbg(root, "is root for AMD node %u\n", node);
|
||||
return root;
|
||||
}
|
||||
|
||||
static struct pci_dev **amd_roots;
|
||||
|
||||
/* Protect the PCI config register pairs used for SMN. */
|
||||
|
|
@ -274,51 +218,21 @@ DEFINE_SHOW_STORE_ATTRIBUTE(smn_node);
|
|||
DEFINE_SHOW_STORE_ATTRIBUTE(smn_address);
|
||||
DEFINE_SHOW_STORE_ATTRIBUTE(smn_value);
|
||||
|
||||
static int amd_cache_roots(void)
|
||||
static struct pci_dev *get_next_root(struct pci_dev *root)
|
||||
{
|
||||
u16 node, num_nodes = amd_num_nodes();
|
||||
|
||||
amd_roots = kcalloc(num_nodes, sizeof(*amd_roots), GFP_KERNEL);
|
||||
if (!amd_roots)
|
||||
return -ENOMEM;
|
||||
|
||||
for (node = 0; node < num_nodes; node++)
|
||||
amd_roots[node] = amd_node_get_root(node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reserve_root_config_spaces(void)
|
||||
{
|
||||
struct pci_dev *root = NULL;
|
||||
struct pci_bus *bus = NULL;
|
||||
|
||||
while ((bus = pci_find_next_bus(bus))) {
|
||||
/* Root device is Device 0 Function 0 on each Primary Bus. */
|
||||
root = pci_get_slot(bus, 0);
|
||||
if (!root)
|
||||
while ((root = pci_get_class(PCI_CLASS_BRIDGE_HOST << 8, root))) {
|
||||
/* Root device is Device 0 Function 0. */
|
||||
if (root->devfn)
|
||||
continue;
|
||||
|
||||
if (root->vendor != PCI_VENDOR_ID_AMD &&
|
||||
root->vendor != PCI_VENDOR_ID_HYGON)
|
||||
continue;
|
||||
|
||||
pci_dbg(root, "Reserving PCI config space\n");
|
||||
|
||||
/*
|
||||
* There are a few SMN index/data pairs and other registers
|
||||
* that shouldn't be accessed by user space.
|
||||
* So reserve the entire PCI config space for simplicity rather
|
||||
* than covering specific registers piecemeal.
|
||||
*/
|
||||
if (!pci_request_config_region_exclusive(root, 0, PCI_CFG_SPACE_SIZE, NULL)) {
|
||||
pci_err(root, "Failed to reserve config space\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
smn_exclusive = true;
|
||||
return 0;
|
||||
return root;
|
||||
}
|
||||
|
||||
static bool enable_dfs;
|
||||
|
|
@ -332,7 +246,8 @@ __setup("amd_smn_debugfs_enable", amd_smn_enable_dfs);
|
|||
|
||||
static int __init amd_smn_init(void)
|
||||
{
|
||||
int err;
|
||||
u16 count, num_roots, roots_per_node, node, num_nodes;
|
||||
struct pci_dev *root;
|
||||
|
||||
if (!cpu_feature_enabled(X86_FEATURE_ZEN))
|
||||
return 0;
|
||||
|
|
@ -342,13 +257,48 @@ static int __init amd_smn_init(void)
|
|||
if (amd_roots)
|
||||
return 0;
|
||||
|
||||
err = amd_cache_roots();
|
||||
if (err)
|
||||
return err;
|
||||
num_roots = 0;
|
||||
root = NULL;
|
||||
while ((root = get_next_root(root))) {
|
||||
pci_dbg(root, "Reserving PCI config space\n");
|
||||
|
||||
err = reserve_root_config_spaces();
|
||||
if (err)
|
||||
return err;
|
||||
/*
|
||||
* There are a few SMN index/data pairs and other registers
|
||||
* that shouldn't be accessed by user space. So reserve the
|
||||
* entire PCI config space for simplicity rather than covering
|
||||
* specific registers piecemeal.
|
||||
*/
|
||||
if (!pci_request_config_region_exclusive(root, 0, PCI_CFG_SPACE_SIZE, NULL)) {
|
||||
pci_err(root, "Failed to reserve config space\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
num_roots++;
|
||||
}
|
||||
|
||||
pr_debug("Found %d AMD root devices\n", num_roots);
|
||||
|
||||
if (!num_roots)
|
||||
return -ENODEV;
|
||||
|
||||
num_nodes = amd_num_nodes();
|
||||
amd_roots = kcalloc(num_nodes, sizeof(*amd_roots), GFP_KERNEL);
|
||||
if (!amd_roots)
|
||||
return -ENOMEM;
|
||||
|
||||
roots_per_node = num_roots / num_nodes;
|
||||
|
||||
count = 0;
|
||||
node = 0;
|
||||
root = NULL;
|
||||
while (node < num_nodes && (root = get_next_root(root))) {
|
||||
/* Use one root for each node and skip the rest. */
|
||||
if (count++ % roots_per_node)
|
||||
continue;
|
||||
|
||||
pci_dbg(root, "is root for AMD node %u\n", node);
|
||||
amd_roots[node++] = root;
|
||||
}
|
||||
|
||||
if (enable_dfs) {
|
||||
debugfs_dir = debugfs_create_dir("amd_smn", arch_debugfs_dir);
|
||||
|
|
@ -358,6 +308,8 @@ static int __init amd_smn_init(void)
|
|||
debugfs_create_file("value", 0600, debugfs_dir, NULL, &smn_value_fops);
|
||||
}
|
||||
|
||||
smn_exclusive = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1038,6 +1038,7 @@ static void init_amd_zen4(struct cpuinfo_x86 *c)
|
|||
static const struct x86_cpu_id zen5_rdseed_microcode[] = {
|
||||
ZEN_MODEL_STEP_UCODE(0x1a, 0x02, 0x1, 0x0b00215a),
|
||||
ZEN_MODEL_STEP_UCODE(0x1a, 0x11, 0x0, 0x0b101054),
|
||||
{},
|
||||
};
|
||||
|
||||
static void init_amd_zen5(struct cpuinfo_x86 *c)
|
||||
|
|
|
|||
|
|
@ -220,10 +220,12 @@ static bool need_sha_check(u32 cur_rev)
|
|||
case 0xaa001: return cur_rev <= 0xaa00116; break;
|
||||
case 0xaa002: return cur_rev <= 0xaa00218; break;
|
||||
case 0xb0021: return cur_rev <= 0xb002146; break;
|
||||
case 0xb0081: return cur_rev <= 0xb008111; break;
|
||||
case 0xb1010: return cur_rev <= 0xb101046; break;
|
||||
case 0xb2040: return cur_rev <= 0xb204031; break;
|
||||
case 0xb4040: return cur_rev <= 0xb404031; break;
|
||||
case 0xb6000: return cur_rev <= 0xb600031; break;
|
||||
case 0xb6080: return cur_rev <= 0xb608031; break;
|
||||
case 0xb7000: return cur_rev <= 0xb700031; break;
|
||||
default: break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue