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/input/misc/pf1550-onkey.c | 197 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 drivers/input/misc/pf1550-onkey.c (limited to 'drivers/input/misc/pf1550-onkey.c') diff --git a/drivers/input/misc/pf1550-onkey.c b/drivers/input/misc/pf1550-onkey.c new file mode 100644 index 000000000..0d1b570bb --- /dev/null +++ b/drivers/input/misc/pf1550-onkey.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the PF1550 ONKEY + * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Portions Copyright (c) 2025 Savoir-faire Linux Inc. + * Samuel Kayode + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PF1550_ONKEY_IRQ_NR 6 + +struct onkey_drv_data { + struct device *dev; + const struct pf1550_ddata *pf1550; + bool wakeup; + struct input_dev *input; +}; + +static irqreturn_t pf1550_onkey_irq_handler(int irq, void *data) +{ + struct onkey_drv_data *onkey = data; + struct platform_device *pdev = to_platform_device(onkey->dev); + int i, state, irq_type = -1; + + for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) + if (irq == platform_get_irq(pdev, i)) + irq_type = i; + + switch (irq_type) { + case PF1550_ONKEY_IRQ_PUSHI: + state = 0; + break; + case PF1550_ONKEY_IRQ_1SI: + case PF1550_ONKEY_IRQ_2SI: + case PF1550_ONKEY_IRQ_3SI: + case PF1550_ONKEY_IRQ_4SI: + case PF1550_ONKEY_IRQ_8SI: + state = 1; + break; + default: + dev_err(onkey->dev, "onkey interrupt: irq %d occurred\n", + irq_type); + return IRQ_HANDLED; + } + + input_event(onkey->input, EV_KEY, KEY_POWER, state); + input_sync(onkey->input); + + return IRQ_HANDLED; +} + +static int pf1550_onkey_probe(struct platform_device *pdev) +{ + struct onkey_drv_data *onkey; + struct input_dev *input; + bool key_power = false; + int i, irq, error; + + onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL); + if (!onkey) + return -ENOMEM; + + onkey->dev = &pdev->dev; + + onkey->pf1550 = dev_get_drvdata(pdev->dev.parent); + if (!onkey->pf1550->regmap) + return dev_err_probe(&pdev->dev, -ENODEV, + "failed to get regmap\n"); + + onkey->wakeup = device_property_read_bool(pdev->dev.parent, + "wakeup-source"); + + if (device_property_read_bool(pdev->dev.parent, + "nxp,disable-key-power")) { + error = regmap_clear_bits(onkey->pf1550->regmap, + PF1550_PMIC_REG_PWRCTRL1, + PF1550_ONKEY_RST_EN); + if (error) + return dev_err_probe(&pdev->dev, error, + "failed: disable turn system off"); + } else { + key_power = true; + } + + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return dev_err_probe(&pdev->dev, -ENOMEM, + "failed to allocate the input device\n"); + + input->name = pdev->name; + input->phys = "pf1550-onkey/input0"; + input->id.bustype = BUS_HOST; + + if (key_power) + input_set_capability(input, EV_KEY, KEY_POWER); + + onkey->input = input; + platform_set_drvdata(pdev, onkey); + + for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { + irq = platform_get_irq(pdev, i); + if (irq < 0) + return irq; + + error = devm_request_threaded_irq(&pdev->dev, irq, NULL, + pf1550_onkey_irq_handler, + IRQF_NO_SUSPEND, + "pf1550-onkey", onkey); + if (error) + return dev_err_probe(&pdev->dev, error, + "failed: irq request (IRQ: %d)\n", + i); + } + + error = input_register_device(input); + if (error) + return dev_err_probe(&pdev->dev, error, + "failed to register input device\n"); + + device_init_wakeup(&pdev->dev, onkey->wakeup); + + return 0; +} + +static int pf1550_onkey_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct onkey_drv_data *onkey = platform_get_drvdata(pdev); + int i, irq; + + if (!device_may_wakeup(&pdev->dev)) + regmap_write(onkey->pf1550->regmap, + PF1550_PMIC_REG_ONKEY_INT_MASK0, + ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | ONKEY_IRQ_2SI | + ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | ONKEY_IRQ_8SI); + else + for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { + irq = platform_get_irq(pdev, i); + if (irq > 0) + enable_irq_wake(irq); + } + + return 0; +} + +static int pf1550_onkey_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct onkey_drv_data *onkey = platform_get_drvdata(pdev); + int i, irq; + + if (!device_may_wakeup(&pdev->dev)) + regmap_write(onkey->pf1550->regmap, + PF1550_PMIC_REG_ONKEY_INT_MASK0, + ~((u8)(ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | + ONKEY_IRQ_2SI | ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | + ONKEY_IRQ_8SI))); + else + for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { + irq = platform_get_irq(pdev, i); + if (irq > 0) + disable_irq_wake(irq); + } + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend, + pf1550_onkey_resume); + +static const struct platform_device_id pf1550_onkey_id[] = { + { "pf1550-onkey", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, pf1550_onkey_id); + +static struct platform_driver pf1550_onkey_driver = { + .driver = { + .name = "pf1550-onkey", + .pm = pm_sleep_ptr(&pf1550_onkey_pm_ops), + }, + .probe = pf1550_onkey_probe, + .id_table = pf1550_onkey_id, +}; +module_platform_driver(pf1550_onkey_driver); + +MODULE_AUTHOR("Freescale Semiconductor"); +MODULE_DESCRIPTION("PF1550 onkey Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3.1