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/ssb/pcihost_wrapper.c | 130 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 drivers/ssb/pcihost_wrapper.c (limited to 'drivers/ssb/pcihost_wrapper.c') diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c new file mode 100644 index 000000000..5b6b5e0e4 --- /dev/null +++ b/drivers/ssb/pcihost_wrapper.c @@ -0,0 +1,130 @@ +/* + * Sonics Silicon Backplane + * PCI Hostdevice wrapper + * + * Copyright (c) 2005 Martin Langer + * Copyright (c) 2005 Stefano Brivio + * Copyright (c) 2005 Danny van Dyk + * Copyright (c) 2005 Andreas Jaggi + * Copyright (c) 2005-2007 Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include +#include +#include + + +#ifdef CONFIG_PM_SLEEP +static int ssb_pcihost_suspend(struct device *d) +{ + struct pci_dev *dev = to_pci_dev(d); + struct ssb_bus *ssb = pci_get_drvdata(dev); + int err; + + err = ssb_bus_suspend(ssb); + if (err) + return err; + pci_save_state(dev); + pci_disable_device(dev); + + /* if there is a wakeup enabled child device on ssb bus, + enable pci wakeup posibility. */ + device_set_wakeup_enable(d, d->power.wakeup_path); + + pci_prepare_to_sleep(dev); + + return 0; +} + +static int ssb_pcihost_resume(struct device *d) +{ + struct pci_dev *dev = to_pci_dev(d); + struct ssb_bus *ssb = pci_get_drvdata(dev); + int err; + + pci_back_from_sleep(dev); + err = pci_enable_device(dev); + if (err) + return err; + pci_restore_state(dev); + err = ssb_bus_resume(ssb); + if (err) + return err; + + return 0; +} + +static const struct dev_pm_ops ssb_pcihost_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ssb_pcihost_suspend, ssb_pcihost_resume) +}; + +#endif /* CONFIG_PM_SLEEP */ + +static int ssb_pcihost_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct ssb_bus *ssb; + int err = -ENOMEM; + u32 val; + + ssb = kzalloc_obj(*ssb); + if (!ssb) + goto out; + err = pci_enable_device(dev); + if (err) + goto err_kfree_ssb; + err = pci_request_regions(dev, dev_driver_string(&dev->dev)); + if (err) + goto err_pci_disable; + pci_set_master(dev); + + /* Disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_read_config_dword(dev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(dev, 0x40, val & 0xffff00ff); + + err = ssb_bus_pcibus_register(ssb, dev); + if (err) + goto err_pci_release_regions; + + pci_set_drvdata(dev, ssb); + +out: + return err; + +err_pci_release_regions: + pci_release_regions(dev); +err_pci_disable: + pci_disable_device(dev); +err_kfree_ssb: + kfree(ssb); + return err; +} + +static void ssb_pcihost_remove(struct pci_dev *dev) +{ + struct ssb_bus *ssb = pci_get_drvdata(dev); + + ssb_bus_unregister(ssb); + pci_release_regions(dev); + pci_disable_device(dev); + kfree(ssb); + pci_set_drvdata(dev, NULL); +} + +int ssb_pcihost_register(struct pci_driver *driver) +{ + driver->probe = ssb_pcihost_probe; + driver->remove = ssb_pcihost_remove; +#ifdef CONFIG_PM_SLEEP + driver->driver.pm = &ssb_pcihost_pm_ops; +#endif + + return pci_register_driver(driver); +} +EXPORT_SYMBOL(ssb_pcihost_register); -- cgit v1.3.1