mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user