From 27600805e62f800bacf990354632eae4e487d34c Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Thu, 3 Sep 2026 10:43:25 -0500 Subject: x86/amd_node: Fix PCI device reference counting in amd_smn_init() The local "root" pointer is a temporary variable used during the device search. Therefore, refcount related to the search iterators should be cleaned up after the search is complete. Use the __free() cleanup macro to ensure the refcount is decremented when the temporary pointer goes out of scope. Additionally, increment the refcount when caching a root pointer. This ensures the in-use refcount is separate from the temporary search refcounting. Finally, drop the redundant "root = NULL" before the second search loop. The pci_get_class() iterator always decrements the refcount of its "from" argument, so the first loop can only fall through with "root" already NULL. Fixes: 0a4b61d9c2e4 ("x86/amd_node: Fix AMD root device caching") Closes: https://sashiko.dev/#/patchset/20260806160159.230453-1-jason.andryuk%40amd.com Reported-by: Sashiko Assisted-by: LLM Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Mario Limonciello (AMD) Cc: Link: https://patch.msgid.link/20260903154325.74343-1-yazen.ghannam@amd.com --- drivers/base/regmap/regmap-raw-ram.c | 144 +++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 drivers/base/regmap/regmap-raw-ram.c (limited to 'drivers/base/regmap/regmap-raw-ram.c') diff --git a/drivers/base/regmap/regmap-raw-ram.c b/drivers/base/regmap/regmap-raw-ram.c new file mode 100644 index 000000000..60d6e95cd --- /dev/null +++ b/drivers/base/regmap/regmap-raw-ram.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Register map access API - Memory region with raw access +// +// This is intended for testing only +// +// Copyright (c) 2023, Arm Ltd + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +static unsigned int decode_reg(enum regmap_endian endian, const void *reg) +{ + const u16 *r = reg; + + if (endian == REGMAP_ENDIAN_BIG) + return be16_to_cpu(*r); + else + return le16_to_cpu(*r); +} + +static int regmap_raw_ram_gather_write(void *context, + const void *reg, size_t reg_len, + const void *val, size_t val_len) +{ + struct regmap_ram_data *data = context; + unsigned int r; + u16 *our_buf = (u16 *)data->vals; + int i; + + if (reg_len != 2) + return -EINVAL; + if (val_len % 2) + return -EINVAL; + + r = decode_reg(data->reg_endian, reg); + if (data->noinc_reg && data->noinc_reg(data, r)) { + memcpy(&our_buf[r], val + val_len - 2, 2); + data->written[r] = true; + } else { + memcpy(&our_buf[r], val, val_len); + + for (i = 0; i < val_len / 2; i++) + data->written[r + i] = true; + } + + return 0; +} + +static int regmap_raw_ram_write(void *context, const void *data, size_t count) +{ + return regmap_raw_ram_gather_write(context, data, 2, + data + 2, count - 2); +} + +static int regmap_raw_ram_read(void *context, + const void *reg, size_t reg_len, + void *val, size_t val_len) +{ + struct regmap_ram_data *data = context; + unsigned int r; + u16 *our_buf = (u16 *)data->vals; + int i; + + if (reg_len != 2) + return -EINVAL; + if (val_len % 2) + return -EINVAL; + + r = decode_reg(data->reg_endian, reg); + if (data->noinc_reg && data->noinc_reg(data, r)) { + for (i = 0; i < val_len; i += 2) + memcpy(val + i, &our_buf[r], 2); + data->read[r] = true; + } else { + memcpy(val, &our_buf[r], val_len); + + for (i = 0; i < val_len / 2; i++) + data->read[r + i] = true; + } + + return 0; +} + +static void regmap_raw_ram_free_context(void *context) +{ + struct regmap_ram_data *data = context; + + kfree(data->vals); + kfree(data->read); + kfree(data->written); + kfree(data); +} + +static const struct regmap_bus regmap_raw_ram = { + .fast_io = true, + .write = regmap_raw_ram_write, + .gather_write = regmap_raw_ram_gather_write, + .read = regmap_raw_ram_read, + .free_context = regmap_raw_ram_free_context, +}; + +struct regmap *__regmap_init_raw_ram(struct device *dev, + const struct regmap_config *config, + struct regmap_ram_data *data, + struct lock_class_key *lock_key, + const char *lock_name) +{ + struct regmap *map; + + if (config->reg_bits != 16) + return ERR_PTR(-EINVAL); + + if (!config->max_register) { + pr_crit("No max_register specified for RAM regmap\n"); + return ERR_PTR(-EINVAL); + } + + data->read = kzalloc_objs(bool, config->max_register + 1); + if (!data->read) + return ERR_PTR(-ENOMEM); + + data->written = kzalloc_objs(bool, config->max_register + 1); + if (!data->written) + return ERR_PTR(-ENOMEM); + + data->reg_endian = config->reg_format_endian; + + map = __regmap_init(dev, ®map_raw_ram, data, config, + lock_key, lock_name); + + return map; +} +EXPORT_SYMBOL_GPL(__regmap_init_raw_ram); + +MODULE_DESCRIPTION("Register map access API - Memory region with raw access"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3.1