diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 29a8e444db83..e5421751eb2d 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -21,6 +21,10 @@ #include #include +#ifdef CONFIG_HOTPLUG_CPU +#include +#endif + static int __init cpu_psci_cpu_init(unsigned int cpu) { return 0; @@ -67,14 +71,18 @@ static int cpu_psci_cpu_disable(unsigned int cpu) static void cpu_psci_cpu_die(unsigned int cpu) { - /* - * There are no known implementations of PSCI actually using the - * power state field, pass a sensible default for now. - */ - u32 state = PSCI_POWER_STATE_TYPE_POWER_DOWN << - PSCI_0_2_POWER_STATE_TYPE_SHIFT; + if (is_ist_enabled(cpu)) { + cpu_enter_ist(cpu); + } else { + /* + * There are no known implementations of PSCI actually using the + * power state field, pass a sensible default for now. + */ + u32 state = PSCI_POWER_STATE_TYPE_POWER_DOWN << + PSCI_0_2_POWER_STATE_TYPE_SHIFT; - psci_ops.cpu_off(state); + psci_ops.cpu_off(state); + } } static int cpu_psci_cpu_kill(unsigned int cpu) diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index ea6ea5bbbc9c..3fc04c2c8e35 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -58,6 +58,7 @@ obj-y += cardreader/ obj-$(CONFIG_PVPANIC) += pvpanic/ obj-$(CONFIG_UACCE) += uacce/ obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o +obj-$(CONFIG_ARM_PSCI_FW) += nv_ist.o obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o obj-$(CONFIG_HI6421V600_IRQ) += hi6421v600-irq.o obj-$(CONFIG_OPEN_DICE) += open-dice.o diff --git a/drivers/misc/nv_ist.c b/drivers/misc/nv_ist.c new file mode 100644 index 000000000000..501bdc4b7f4b --- /dev/null +++ b/drivers/misc/nv_ist.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* RIST START SMC */ +/* https://confluence.nvidia.com/display/TFA/Central+Registry+for+SMCs */ +#define NV_IST_FN_RIST_START 0xC200FF0A + +struct ist_smc_vars { + bool enable; + u32 tid; + u32 smc_id; +}; + +static struct ist_smc_vars *cpu_settings; +static struct dentry *dbgfs_root; + +bool is_ist_enabled(unsigned int cpu) +{ + return cpu_settings != NULL && cpu_settings[cpu].enable; +} + +void cpu_enter_ist(unsigned int cpu) +{ + struct arm_smccc_res res; + + if ((cpu_settings != NULL && cpu_settings[cpu].enable)) { + pr_debug("CPU %x is entering SMC %x\n", cpu, cpu_settings[cpu].smc_id); + arm_smccc_smc(cpu_settings[cpu].smc_id, + cpu_settings[cpu].tid, + 0, 0, 0, 0, 0, 0, &res); + } +} + +static int create_ist_debugfs_entries(void) +{ + char subdir_name[6]; /* cpu + XX + \n */ + struct dentry *subdir; + int cpu; + + dbgfs_root = debugfs_create_dir("nv_ist", NULL); + if (!dbgfs_root) { + return -ENOENT; + } + + for (cpu = cpumask_first(cpu_possible_mask); + cpu < nr_cpu_ids; + cpu = cpumask_next(cpu, cpu_possible_mask)) { + snprintf(subdir_name, 6, "cpu%d", cpu); + subdir = debugfs_create_dir(subdir_name, dbgfs_root); + + if (subdir == NULL) + goto err; + + debugfs_create_bool("enable", 0644, + subdir, &(cpu_settings[cpu].enable)); + + debugfs_create_u32("test_id", 0644, + subdir, &(cpu_settings[cpu].tid)); + } + + return 0; +err: + debugfs_remove_recursive(dbgfs_root); + return -ENOENT; +} + +static int tegra_ist_probe(struct platform_device *pdev) +{ + size_t i; + int err = 0; + + /* Zero-initialized */ + cpu_settings = devm_kcalloc(&pdev->dev, nr_cpu_ids, + sizeof(struct ist_smc_vars), GFP_KERNEL); + + /* Setting the PSCI-ID to RIST_START SMC */ + for (i = 0; i < nr_cpu_ids; i++) { + cpu_settings[i].enable = false; + cpu_settings[i].tid = 0U; + cpu_settings[i].smc_id = NV_IST_FN_RIST_START; + } + /* Create debugfs */ + err = create_ist_debugfs_entries(); + + if (err) + devm_kfree(&pdev->dev, cpu_settings); + + return err; +} + +static int tegra_ist_remove(struct platform_device *pdev) +{ + debugfs_remove_recursive(dbgfs_root); + return 0; +} + +static const struct of_device_id tegra_ist_of_match[] = { + { .compatible = "nvidia,tegra26x-ist" }, + { }, /* Terminal */ +}; + +static struct platform_driver nv_ist_driver = { + .probe = tegra_ist_probe, + .remove = tegra_ist_remove, + .driver = { + .name = "nv_ist", + .of_match_table = tegra_ist_of_match, + }, +}; +module_platform_driver(nv_ist_driver); + +MODULE_AUTHOR("Ishan Shah "); +MODULE_DESCRIPTION("NV IST Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/misc/nv_ist.h b/include/misc/nv_ist.h new file mode 100644 index 000000000000..623b04338f0d --- /dev/null +++ b/include/misc/nv_ist.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef _MISC_NV_IST_H +#define _MISC_NV_IST_H + +#if IS_ENABLED(CONFIG_ARM_PSCI_FW) + +bool is_ist_enabled(unsigned int cpu); +void cpu_enter_ist(unsigned int cpu); + +#else /* ! CONFIG_ARM_PSCI_FW */ + +static inline bool is_ist_enabled(unsigned int cpu) { return false; } +static inline void cpu_enter_ist(unsigned int cpu) { } + +#endif /* CONFIG_ARM_PSCI_FW */ + +#endif /* _MISC_NV_IST_H */