diff --git a/drivers/misc/mods/Makefile b/drivers/misc/mods/Makefile index 0195ea4a..9e61b417 100644 --- a/drivers/misc/mods/Makefile +++ b/drivers/misc/mods/Makefile @@ -18,6 +18,7 @@ mods-$(CONFIG_TEGRA_NVADSP) += mods_adsp.o mods-$(CONFIG_COMMON_CLK) += mods_clock.o mods-$(CONFIG_DEBUG_FS) += mods_debugfs.o mods-$(CONFIG_DMA_ENGINE) += mods_dma.o +mods-$(CONFIG_ARCH_TEGRA) += mods_ipi.o mods-$(CONFIG_NET) += mods_netdevice.o mods-$(CONFIG_ARCH_TEGRA) += mods_oist.o mods-$(CONFIG_OPTEE) += mods_optee.o diff --git a/drivers/misc/mods/mods_internal.h b/drivers/misc/mods/mods_internal.h index e2c012ea..f9252dba 100644 --- a/drivers/misc/mods/mods_internal.h +++ b/drivers/misc/mods/mods_internal.h @@ -739,4 +739,8 @@ int smmu_driver_init(void); void smmu_driver_exit(void); #endif +#if defined(MODS_HAS_TEGRA) +int esc_mods_send_ipi(struct mods_client *client, struct MODS_SEND_IPI *p); +#endif + #endif /* _MODS_INTERNAL_H_ */ diff --git a/drivers/misc/mods/mods_ipi.c b/drivers/misc/mods/mods_ipi.c new file mode 100644 index 00000000..b4c89f54 --- /dev/null +++ b/drivers/misc/mods/mods_ipi.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This file is part of NVIDIA MODS kernel driver. + * + * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA MODS kernel driver is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * NVIDIA MODS kernel driver is distributed in the hope that 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. + * + * You should have received a copy of the GNU General Public License + * along with NVIDIA MODS kernel driver. + * If not, see . + */ + +#include "mods_internal.h" + +#include +#include +#include +#include +#include + +#define MAX_IPI_WFI_LOOPS 5 +#define MAX_IPI_WFE_LOOPS 10 + +static void ipi_wfi_cpu(void *p) +{ + struct MODS_SEND_IPI *p_ipi = (struct MODS_SEND_IPI *)p; + u32 i; + + for (i = 0; i < p_ipi->num_loops; i++) + wfi(); +} + +static void ipi_wfe_cpu(void *p) +{ + struct MODS_SEND_IPI *p_ipi = (struct MODS_SEND_IPI *)p; + u32 i; + + for (i = 0; i < p_ipi->num_loops; i++) + wfe(); +} + +int esc_mods_send_ipi(struct mods_client *client, struct MODS_SEND_IPI *p) +{ + LOG_ENT(); + + switch (p->ipi_type) { + case MODS_IPI_KICK: { + kick_all_cpus_sync(); + break; + } + case MODS_IPI_WFI: { + if (p->num_loops > MAX_IPI_WFI_LOOPS) { + cl_error("num_loops %u exceed maximum limit %d for MODS_IPI_WFI\n", + p->num_loops, + MAX_IPI_WFI_LOOPS); + LOG_EXT(); + return -EINVAL; + } + preempt_disable(); + smp_call_function_many(cpu_online_mask, ipi_wfi_cpu, (void *)p, 1); + preempt_enable(); + break; + } + case MODS_IPI_WFE: { + if (p->num_loops > MAX_IPI_WFE_LOOPS) { + cl_error("num_loops %u exceed maximum limit %d for MODS_IPI_WFE\n", + p->num_loops, + MAX_IPI_WFE_LOOPS); + LOG_EXT(); + return -EINVAL; + } + preempt_disable(); + smp_call_function_many(cpu_online_mask, ipi_wfe_cpu, (void *)p, 1); + preempt_enable(); + break; + } + default: { + cl_error("unsupported MODS_IPI_TYPE\n"); + LOG_EXT(); + return -EINVAL; + } + } + + LOG_EXT(); + return 0; +} diff --git a/drivers/misc/mods/mods_krnl.c b/drivers/misc/mods/mods_krnl.c index 33e477ec..8b3485d4 100644 --- a/drivers/misc/mods/mods_krnl.c +++ b/drivers/misc/mods/mods_krnl.c @@ -2604,6 +2604,11 @@ static long mods_krnl_ioctl(struct file *fp, MODS_IOCTL(MODS_ESC_OIST_STATUS, esc_mods_oist_status, MODS_TEGRA_OIST_STATUS); break; + + case MODS_ESC_MODS_SEND_IPI: + MODS_IOCTL(MODS_ESC_MODS_SEND_IPI, + esc_mods_send_ipi, MODS_SEND_IPI); + break; #endif case MODS_ESC_ACQUIRE_ACCESS_TOKEN: diff --git a/include/uapi/misc/mods.h b/include/uapi/misc/mods.h index ec4c01e5..bcd5e26f 100644 --- a/include/uapi/misc/mods.h +++ b/include/uapi/misc/mods.h @@ -1858,6 +1858,23 @@ struct MODS_TEGRA_OIST_STATUS { __u64 smc_status; }; +enum MODS_IPI_TYPE { + MODS_IPI_KICK, + MODS_IPI_WFI, + MODS_IPI_WFE +}; + +/* Used by MODS_ESC_MODS_SEND_IPI ioctl. + * + * Available only on Tegra. + */ +struct MODS_SEND_IPI { + /* IN */ + __u32 ipi_type; + /* IN */ + __u32 num_loops; +}; + #define MODS_IOMMU_MAP_CONTIGUOUS 1 #define MODS_MAX_PROP_NAME_LEN 64 @@ -2097,5 +2114,6 @@ struct MODS_PROXIMITY_TO_NUMA_NODE { #define MODS_ESC_INVOKE_OPTEE_TA MODSIO(WR, 141, MODS_OPTEE_PARAMS) #define MODS_ESC_READ_DEV_PROPERTY MODSIO(WR, 142, MODS_READ_DEV_PROPERTY) #define MODS_ESC_PROXIMITY_TO_NUMA_NODE MODSIO(WR, 143, MODS_PROXIMITY_TO_NUMA_NODE) +#define MODS_ESC_MODS_SEND_IPI MODSIO(W, 144, MODS_SEND_IPI) #endif /* _UAPI_MODS_H_ */