From ff53ebfdd32d23f4f5dd6796cb862f2a0c2ad244 Mon Sep 17 00:00:00 2001 From: Suneel Date: Thu, 6 Nov 2025 20:40:12 +0530 Subject: [PATCH 1/3] os/drivers/cpu: Add CPU driver interface for Secondary CPUs management Add character driver for Secondary CPUs management operations through /dev/cpuX device nodes. Provides ioctl interface for CPU enable/disable and state query operations. This driver enables userspace applications and test utilities to control CPU states and perform cpu on/off operations through standard interface. --- os/drivers/Kconfig | 1 + os/drivers/Makefile | 4 + os/drivers/cpu/Kconfig | 13 +++ os/drivers/cpu/cpu_driver.c | 163 ++++++++++++++++++++++++++++++++ os/include/tinyara/cpu_driver.h | 54 +++++++++++ os/include/tinyara/fs/ioctl.h | 1 + os/kernel/init/os_bringup.c | 7 ++ 7 files changed, 243 insertions(+) create mode 100644 os/drivers/cpu/Kconfig create mode 100644 os/drivers/cpu/cpu_driver.c create mode 100644 os/include/tinyara/cpu_driver.h diff --git a/os/drivers/Kconfig b/os/drivers/Kconfig index 3e94a6deab..bc84551b33 100644 --- a/os/drivers/Kconfig +++ b/os/drivers/Kconfig @@ -287,6 +287,7 @@ source drivers/ai-soc/Kconfig endmenu source drivers/lcd/Kconfig +source drivers/cpu/Kconfig menuconfig BCH bool "Block-to-Character (BCH) Support" diff --git a/os/drivers/Makefile b/os/drivers/Makefile index 6662bf3c99..94de2aba96 100644 --- a/os/drivers/Makefile +++ b/os/drivers/Makefile @@ -148,6 +148,10 @@ ifeq ($(CONFIG_VIRTKEY),y) endif endif +ifeq ($(CONFIG_CPU_DRIVER),y) + CSRCS += cpu/cpu_driver.c +endif + AOBJS = $(ASRCS:.S=$(OBJEXT)) COBJS = $(CSRCS:.c=$(OBJEXT)) diff --git a/os/drivers/cpu/Kconfig b/os/drivers/cpu/Kconfig new file mode 100644 index 0000000000..6dfca9e82c --- /dev/null +++ b/os/drivers/cpu/Kconfig @@ -0,0 +1,13 @@ +# +# For a description of the syntax of this configuration file, +# see kconfig-language at https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt +# + +config CPU_DRIVER + bool "CPU state driver" + default y + depends on SMP + ---help--- + Enable /dev/cpuX driver for secondary CPU state control. + Provides IOCTL interface to manage CPU state (running, stop and query status). + diff --git a/os/drivers/cpu/cpu_driver.c b/os/drivers/cpu/cpu_driver.c new file mode 100644 index 0000000000..4492e0fb2c --- /dev/null +++ b/os/drivers/cpu/cpu_driver.c @@ -0,0 +1,163 @@ +/**************************************************************************** + * + * Copyright 2025 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int cpu_ioctl(FAR struct file *filep, int cmd, unsigned long arg); +static int cpu_open(FAR struct file *filep); +static int cpu_close(FAR struct file *filep); +static ssize_t cpu_read(FAR struct file *filep, FAR char *buffer, size_t buflen); +static ssize_t cpu_write(FAR struct file *filep, FAR char *buffer, size_t buflen); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_cpu_fops = { + .ioctl = cpu_ioctl, + .open = cpu_open, + .close = cpu_close, + .read = cpu_read, + .write = cpu_write +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int cpu_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + int ret; + int cpu; + FAR struct inode *inode; + + DEBUGASSERT(filep != NULL && filep->f_inode != NULL); + + inode = filep->f_inode; + + /* Extract CPU number from device name */ + cpu = inode->i_private; + + switch (cmd) { + case IOC_CPU_ENABLE: + /* Call Scheduler API to enable the CPU */ + ret = sched_cpuon(cpu); + if (ret < 0) { + lldbg("ERROR: Failed to enable CPU%d: %d\n", cpu, ret); + return ret; + } + return OK; + case IOC_CPU_DISABLE: + /* Call Scheduler API to disable the CPU */ + ret = sched_cpuoff(cpu); + if (ret < 0) { + lldbg("ERROR: Failed to disable CPU%d: %d\n", cpu, ret); + return ret; + } + return OK; + case IOC_CPU_GET_STATE: { + int state = up_get_cpu_state(cpu); + if (state < 0) { + lldbg("ERROR: Invalid CPU state %d for CPU%d\n", state, cpu); + return -EINVAL; + } + + *(FAR int*)arg = state; + return OK; + } + default: + return -EINVAL; + } +} + +static int cpu_open(FAR struct file *filep) +{ + DEBUGASSERT(filep != NULL && filep->f_inode != NULL); + return OK; +} + +static int cpu_close(FAR struct file *filep) +{ + DEBUGASSERT(filep != NULL && filep->f_inode != NULL); + return OK; +} + +static ssize_t cpu_read(FAR struct file *filep, FAR char *buffer, size_t buflen) +{ + return OK; +} + +static ssize_t cpu_write(FAR struct file *filep, FAR char *buffer, size_t buflen) +{ + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cpu_driver_init + * + * Description: + * Initialize the CPU driver by registering device nodes for all secondary + * CPUs. This function creates /dev/cpuX device files for each secondary CPU. + * + * Input Parameters: + * None + * + * Returned Value: + * OK (0) on success, negative errno on failure + * + ****************************************************************************/ + +void cpu_driver_init(void) +{ + char devname[16]; + int ret, cpu; + + /* Register device nodes for all secondary CPUs */ + for (cpu = 1; cpu < CONFIG_SMP_NCPUS; cpu++) { + snprintf(devname, sizeof(devname), "/dev/cpu%d", cpu); + + /* Use CPU number as private data */ + ret = register_driver(devname, &g_cpu_fops, 0666, (FAR void *)cpu); + if (ret != OK) { + lldbg("ERROR: Failed to register %s: %d\n", devname); + return; + } + + svdbg("CPU driver registered: %s\n", devname); + } +} diff --git a/os/include/tinyara/cpu_driver.h b/os/include/tinyara/cpu_driver.h new file mode 100644 index 0000000000..9d23a0c977 --- /dev/null +++ b/os/include/tinyara/cpu_driver.h @@ -0,0 +1,54 @@ +/**************************************************************************** + * + * Copyright 2025 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_TINYARA_CPU_DRIVER_H +#define __INCLUDE_TINYARA_CPU_DRIVER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/* IOCTLs for /dev/cpuX */ +#define IOC_CPU_ENABLE _IOC(_CPUSTATEBASE, 1) +#define IOC_CPU_DISABLE _IOC(_CPUSTATEBASE, 2) +#define IOC_CPU_GET_STATE _IOC(_CPUSTATEBASE, 3) + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: cpu_driver_init + * + * Description: + * Initialize the CPU driver by registering device nodes for all secondary + * CPUs. This function creates /dev/cpuX device files for each secondary CPU. + * + * Input Parameters: + * None + * + * Returned Value: + * OK (0) on success, negative errno on failure + * + ****************************************************************************/ + +void cpu_driver_init(void); + +#endif /* __INCLUDE_TINYARA_CPU_DRIVER_H */ diff --git a/os/include/tinyara/fs/ioctl.h b/os/include/tinyara/fs/ioctl.h index e5febc35f6..19e1686c4c 100644 --- a/os/include/tinyara/fs/ioctl.h +++ b/os/include/tinyara/fs/ioctl.h @@ -108,6 +108,7 @@ #define _MIPIDSIBASE (0x3900) /* Mipidsi device ioctl commands */ #define _CSIIOCBASE (0x3a00) /* Wifi CSI ioctl commands */ #define _SILENTRBCBASE (0x3b00) /* Silent reboot ioctl commands */ +#define _CPUSTATEBASE (0x3c00) /* cpu state driver ioctl commands */ /* boardctl() commands share the same number space */ diff --git a/os/kernel/init/os_bringup.c b/os/kernel/init/os_bringup.c index b13ca5d11a..57aa87a81a 100644 --- a/os/kernel/init/os_bringup.c +++ b/os/kernel/init/os_bringup.c @@ -93,6 +93,9 @@ #ifdef CONFIG_TASK_MANAGER #include #endif +#ifdef CONFIG_CPU_DRIVER +#include +#endif #include "init/init.h" #ifdef CONFIG_PAGING #include "paging/paging.h" @@ -307,6 +310,10 @@ static inline void os_do_appstart(void) cpuload_initialize(); #endif +#ifdef CONFIG_CPU_DRIVER + cpu_driver_init(); +#endif + #ifdef CONFIG_TASK_MANAGER task_manager_drv_register(); #endif From ed97f2ddb103f8395ef9f2538a03e072bfa9c572 Mon Sep 17 00:00:00 2001 From: Suneel Date: Thu, 6 Nov 2025 20:42:12 +0530 Subject: [PATCH 2/3] apps/system : Add cputest application for Secondary CPUs management testing Add cputest application with shell commands for testing CPU driver functionality. Provides commands to enable/disable secondary CPUs and check CPU status through device interface. Shell commands added: - cpuctrl on : Power on specified CPU - cpuctrl off : Power off specified CPU - cpuctrl status: Show status of all Secondary CPUs - cpuctrl help : Show the help message Test Results: TASH>> TASH>> TASH>>cpuctrl status TASH>>cpu state for cpu1: 0 (running) TASH>> TASH>> TASH>> TASH>>smp TASH>> Main[0]: Running on CPU0 Main[0]: Initializing barrier Running SMP test with AMP configuration Thread[1]: Started Thread[1]: Running on CPU0 Main[0]: Thread 1 created Thread[2]: Started Thread[2]: Running on CPU1 Main[0]: Thread 2 created Thread[3]: Started Thread[3]: Running on CPU0 Main[0]: Thread 3 created Thread[4]: Started Thread[4]: Running on CPU1 Main[0]: Thread 4 created Thread[5]: Started Thread[5]: Running on CPU0 Main[0]: Thread 5 created Thread[6]: Started Thread[6]: Running on CPU1 Main[0]: Thread 6 created Thread[7]: Started Thread[7]: Running on CPU0 Main[0]: Thread 7 created Thread[8]: Started Thread[8]: Running on CPU1 Main[0]: Thread 8 created Thread[2]: Calling pthread_barrier_wait() Thread[1]: Calling pthread_barrier_wait() Thread[4]: Calling pthread_barrier_wait() Thread[3]: Calling pthread_barrier_wait() Thread[5]: Calling pthread_barrier_wait() Thread[6]: Calling pthread_barrier_wait() Thread[7]: Calling pthread_barrier_wait() Thread[8]: Calling pthread_barrier_wait() Thread[8]: Back with ret=PTHREAD_BARRIER_SERIAL_THREAD (I AM SPECIAL) Thread[1]: Back with ret=0 (I am not special) Thread[3]: Back with ret=0 (I am not special) Thread[5]: Back with ret=0 (I am not special) Thread[7]: Back with ret=0 (I am not special) Thread[2]: Back with ret=0 (I am not special) Thread[4]: Back with ret=0 (I am not special) Thread[6]: Back with ret=0 (I am not special) Thread[8]: Done Thread[2]: Done Thread[4]: Done Thread[6]: Done Thread[1]: Done Thread[3]: Done Thread[5]: Done Main[0]: Thread 1 completed with result=0 Thread[7]: Done Main[0]: Thread 2 completed with result=0 Main[0]: Thread 3 completed with result=0 Main[0]: Thread 4 completed with result=0 Main[0]: Thread 5 completed with result=0 Main[0]: Thread 6 completed with result=0 Main[0]: Thread 7 completed with result=0 Main[0]: Thread 8 completed with result=0 TASH>> TASH>> TASH>> TASH>> TASH>>cpuctrl off 1 TASH>>powering down cpu1! cpu1 successfully disabled state: 1 (offline) TASH>> TASH>> TASH>> TASH>>cpuctrl status TASH>>cpu state for cpu1: 1 (offline) TASH>> TASH>> TASH>> TASH>> TASH>>smp TASH>> Main[0]: Running on CPU0 Main[0]: Initializing barrier Running SMP test with AMP configuration Thread[1]: Started Thread[1]: Running on CPU0 Main[0]: Thread 1 created Thread[2]: Started Thread[2]: Running on CPU0 Main[0]: Thread 2 created Thread[3]: Started Thread[3]: Running on CPU0 Main[0]: Thread 3 created Thread[4]: Started Thread[4]: Running on CPU0 Main[0]: Thread 4 created Thread[5]: Started Thread[5]: Running on CPU0 Main[0]: Thread 5 created Thread[6]: Started Thread[6]: Running on CPU0 Main[0]: Thread 6 created Thread[7]: Started Thread[7]: Running on CPU0 Main[0]: Thread 7 created Thread[8]: Started Thread[8]: Running on CPU0 Main[0]: Thread 8 created Thread[1]: Calling pthread_barrier_wait() Thread[3]: Calling pthread_barrier_wait() Thread[5]: Calling pthread_barrier_wait() Thread[7]: Calling pthread_barrier_wait() Thread[2]: Calling pthread_barrier_wait() Thread[4]: Calling pthread_barrier_wait() Thread[6]: Calling pthread_barrier_wait() Thread[8]: Calling pthread_barrier_wait() Thread[8]: Back with ret=PTHREAD_BARRIER_SERIAL_THREAD (I AM SPECIAL) Thread[1]: Back with ret=0 (I am not special) Thread[3]: Back with ret=0 (I am not special) Thread[5]: Back with ret=0 (I am not special) Thread[7]: Back with ret=0 (I am not special) Thread[2]: Back with ret=0 (I am not special) Thread[4]: Back with ret=0 (I am not special) Thread[6]: Back with ret=0 (I am not special) Thread[1]: Done Thread[3]: Done Thread[7]: Done Thread[5]: Done Main[0]: Thread 1 completed with result=0 Thread[6]: Done Thread[8]: Done Thread[2]: Done Thread[4]: Done Main[0]: Thread 2 completed with result=0 Main[0]: Thread 3 completed with result=0 Main[0]: Thread 4 completed with result=0 Main[0]: Thread 5 completed with result=0 Main[0]: Thread 6 completed with result=0 Main[0]: Thread 7 completed with result=0 Main[0]: Thread 8 completed with result=0 TASH>> TASH>> TASH>> TASH>>cpuctrl on 1 TASH>>powering up cpu1! cpu1 successfully enabled state: 0 (running) TASH>> TASH>> TASH>>cpuctrl status TASH>>cpu state for cpu1: 0 (running) TASH>> TASH>> TASH>> TASH>>smp TASH>> Main[0]: Running on CPU0 Main[0]: Initializing barrier Running SMP test with AMP configuration Thread[1]: Started Thread[1]: Running on CPU0 Main[0]: Thread 1 created Thread[2]: Started Thread[2]: Running on CPU1 Main[0]: Thread 2 created Thread[3]: Started Thread[3]: Running on CPU0 Main[0]: Thread 3 created Thread[4]: Started Thread[4]: Running on CPU1 Main[0]: Thread 4 created Thread[5]: Started Thread[5]: Running on CPU0 Main[0]: Thread 5 created Thread[6]: Started Thread[6]: Running on CPU1 Main[0]: Thread 6 created Thread[7]: Started Thread[7]: Running on CPU0 Main[0]: Thread 7 created Thread[8]: Started Thread[8]: Running on CPU1 Main[0]: Thread 8 created Thread[2]: Calling pthread_barrier_wait() Thread[1]: Calling pthread_barrier_wait() Thread[4]: Calling pthread_barrier_wait() Thread[3]: Calling pthread_barrier_wait() Thread[5]: Calling pthread_barrier_wait() Thread[6]: Calling pthread_barrier_wait() Thread[7]: Calling pthread_barrier_wait() Thread[8]: Calling pthread_barrier_wait() Thread[8]: Back with ret=PTHREAD_BARRIER_SERIAL_THREAD (I AM SPECIAL) Thread[1]: Back with ret=0 (I am not special) Thread[3]: Back with ret=0 (I am not special) Thread[5]: Back with ret=0 (I am not special) Thread[7]: Back with ret=0 (I am not special) Thread[2]: Back with ret=0 (I am not special) Thread[4]: Back with ret=0 (I am not special) Thread[6]: Back with ret=0 (I am not special) Thread[8]: Done Thread[2]: Done Thread[4]: Done Thread[6]: Done Thread[1]: Done Thread[3]: Done Thread[5]: Done Main[0]: Thread 1 completed with result=0 Thread[7]: Done Main[0]: Thread 2 completed with result=0 Main[0]: Thread 3 completed with result=0 Main[0]: Thread 4 completed with result=0 Main[0]: Thread 5 completed with result=0 Main[0]: Thread 6 completed with result=0 Main[0]: Thread 7 completed with result=0 Main[0]: Thread 8 completed with result=0 TASH>> TASH>> TASH>> TASH>> --- apps/system/cpucontrol/Kconfig | 13 ++ apps/system/cpucontrol/Make.defs | 23 +++ apps/system/cpucontrol/Makefile | 102 +++++++++++++ apps/system/cpucontrol/cpucontrol.c | 226 ++++++++++++++++++++++++++++ apps/system/init/init.c | 8 + 5 files changed, 372 insertions(+) create mode 100644 apps/system/cpucontrol/Kconfig create mode 100644 apps/system/cpucontrol/Make.defs create mode 100644 apps/system/cpucontrol/Makefile create mode 100644 apps/system/cpucontrol/cpucontrol.c diff --git a/apps/system/cpucontrol/Kconfig b/apps/system/cpucontrol/Kconfig new file mode 100644 index 0000000000..e4c4814778 --- /dev/null +++ b/apps/system/cpucontrol/Kconfig @@ -0,0 +1,13 @@ +# +# For a description of the syntax of this configuration file, +# see kconfig-language at https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt +# + +config SYSTEM_CPUCONTROL + bool "CPU Control commands" + default n + depends on SMP + ---help--- + Enable support for CPU control commands in TASH. This provides commands + for managing CPU power management and status functionality on multi-core + systems. Commands include cpu1on, cpu1off, cpustatus. diff --git a/apps/system/cpucontrol/Make.defs b/apps/system/cpucontrol/Make.defs new file mode 100644 index 0000000000..00289b7b70 --- /dev/null +++ b/apps/system/cpucontrol/Make.defs @@ -0,0 +1,23 @@ +########################################################################### +# +# Copyright 2025 Samsung Electronics All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. +# See the License for the specific +# language governing permissions and limitations under the License. +# +########################################################################### + + +ifeq ($(CONFIG_SYSTEM_CPUCONTROL),y) +CONFIGURED_APPS += system/cpucontrol +endif diff --git a/apps/system/cpucontrol/Makefile b/apps/system/cpucontrol/Makefile new file mode 100644 index 0000000000..23c3d8b67d --- /dev/null +++ b/apps/system/cpucontrol/Makefile @@ -0,0 +1,102 @@ +############################################################################ +# +# Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. +# See the License for the specific +# language governing permissions and limitations under the License. +# +########################################################################### + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +ifeq ($(WINTOOL),y) +INCDIROPT = -w +endif + +# CPU Control System Utility + +ASRCS = +CSRCS = +MAINSRC = cpucontrol.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) +MAINOBJ = $(MAINSRC:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) $(MAINSRC) +OBJS = $(AOBJS) $(COBJS) + +ifneq ($(CONFIG_BUILD_KERNEL),y) + OBJS += $(MAINOBJ) +endif + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + BIN = ..\..\libapps$(LIBEXT) +else +ifeq ($(WINTOOL),y) + BIN = ..\\..\\libapps$(LIBEXT) +else + BIN = ../../libapps$(LIBEXT) +endif +endif + +ifeq ($(WINTOOL),y) + INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}" +else + INSTALL_DIR = $(BIN_DIR) +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS) $(MAINOBJ): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + $(call ARCHIVE, $(BIN), $(OBJS)) + $(Q) touch .built + +install: + +context: + +# Create dependencies + +.depend: Makefile $(SRCS) + $(Q) $(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep + $(Q) touch $@ + +depend: .depend + +clean: + $(call DELFILE, .built) + $(call CLEAN) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep +.PHONY: preconfig +preconfig: diff --git a/apps/system/cpucontrol/cpucontrol.c b/apps/system/cpucontrol/cpucontrol.c new file mode 100644 index 0000000000..c8dfa91e33 --- /dev/null +++ b/apps/system/cpucontrol/cpucontrol.c @@ -0,0 +1,226 @@ +/**************************************************************************** + * + * Copyright 2025 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. + * See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Preprocessor Definitions + ****************************************************************************/ + +const char *cpu_states[] = { + "running", //0 + "offline", //1 + "wake from sleep", //2 +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + + +static int cpucontrol_cpu_on(int argc, char *argv[]); +static int cpucontrol_cpu_off(int argc, char *argv[]); +static int cpucontrol_cpu_status(int argc, char *argv[]); +static int cpucontrol_help(int argc, char *argv[]); +static int cpucontrol_main(int argc, char *argv[]); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int cpucontrol_cpu_on(int argc, char *argv[]) +{ + int fd, state, cpu_num; + char devname[16]; + + if (argc < 3) { + printf("Usage: cpuctrl on \n"); + printf("Example: cpuctrl on 1\n"); + return -EINVAL; + } + + cpu_num = atoi(argv[2]); + if (cpu_num <= 0 || cpu_num >= CONFIG_SMP_NCPUS) { + printf("Invalid CPU ID %d. Valid range: 1-%d\n", cpu_num, CONFIG_SMP_NCPUS - 1); + return -EINVAL; + } + + if (sched_getcpu() > 0) { + printf("can only powerup cpu%d from cpu0!\n", cpu_num); + return -EPERM; + } + + printf("powering up cpu%d!\n", cpu_num); + + snprintf(devname, sizeof(devname), "/dev/cpu%d", cpu_num); + fd = open(devname, O_RDWR); + if (fd < 0) { + printf("Cannot open %s: errno = %d\n", devname, get_errno()); + return -get_errno(); + } + + if (ioctl(fd, IOC_CPU_ENABLE, 1) < 0) { + printf("IOC_CPU_ENABLE ioctl failed for %s : errno = %d\n", devname, get_errno()); + close(fd); + return -get_errno(); + } + printf("cpu%d successfully enabled\n", cpu_num); + + if (ioctl(fd, IOC_CPU_GET_STATE, &state) < 0) { + printf("IOC_CPU_GET_STATE ioctl failed for %s : errno = %d\n", devname, get_errno()); + close(fd); + return -get_errno(); + } + + printf("state: %d (%s)\n", state, cpu_states[state]); + close(fd); + return 0; +} + +static int cpucontrol_cpu_off(int argc, char *argv[]) +{ + int fd, state, cpu_num; + char devname[16]; + + if (argc < 3) { + printf("Usage: cpuctrl off \n"); + printf("Example: cpuctrl off 1\n"); + return -EINVAL; + } + + cpu_num = atoi(argv[2]); + if (cpu_num <= 0 || cpu_num >= CONFIG_SMP_NCPUS) { + printf("Invalid CPU ID %d. Valid range: 1-%d\n", cpu_num, CONFIG_SMP_NCPUS - 1); + return -EINVAL; + } + + if (sched_getcpu() > 0) { + printf("can only powerdown cpu%d from cpu0!\n", cpu_num); + return -EPERM; + } + + printf("powering down cpu%d!\n", cpu_num); + + snprintf(devname, sizeof(devname), "/dev/cpu%d", cpu_num); + fd = open(devname, O_RDWR); + if (fd < 0) { + printf("Cannot open %s: errno = %d\n", devname, get_errno()); + return -get_errno(); + } + + if (ioctl(fd, IOC_CPU_DISABLE, 1) < 0) { + printf("IOC_CPU_DISABLE ioctl failed for %s : errno = %d\n", devname, get_errno()); + close(fd); + return -get_errno(); + } + printf("cpu%d successfully disabled\n", cpu_num); + + if (ioctl(fd, IOC_CPU_GET_STATE, &state) < 0) { + printf("IOC_CPU_GET_STATE ioctl failed for %s : errno = %d\n", devname, get_errno()); + close(fd); + return -get_errno(); + } + printf("state: %d (%s)\n", state, cpu_states[state]); + close(fd); + return 0; +} + +static int cpucontrol_cpu_status(int argc, char *argv[]) +{ + int fd, state; + char devname[16]; + + for (u8 i = 1; i < CONFIG_SMP_NCPUS; i++) { + snprintf(devname, sizeof(devname), "/dev/cpu%d", i); + + fd = open(devname, O_RDWR); + if (fd < 0) { + printf("Cannot open %s: errno = %d\n", devname, get_errno()); + continue; + } + + if (ioctl(fd, IOC_CPU_GET_STATE, &state) < 0) { + printf("IOC_CPU_GET_STATE ioctl failed for %s : errno = %d\n", devname, get_errno()); + close(fd); + continue; + } + + printf("cpu state for cpu%d: %d (%s)\n", i, state, cpu_states[state]); + close(fd); + } + return 0; +} + +static int cpucontrol_help(int argc, char *argv[]) +{ + printf("CPU Control Commands:\n"); + printf(" cpuctrl on - Power on specified CPU\n"); + printf(" cpuctrl off - Power off specified CPU\n"); + printf(" cpuctrl status - Show status of all secondary CPUs\n"); + printf(" cpuctrl help - Show this help message\n"); + printf("\nExamples:\n"); + printf(" cpuctrl on 1 - Power on CPU1\n"); + printf(" cpuctrl off 1 - Power off CPU1\n"); + printf(" cpuctrl status - Show all CPU states\n"); + printf("\nNote: CPU control operations can only be performed from CPU0\n"); + return 0; +} + +static int cpucontrol_main(int argc, char *argv[]) +{ + if (argc < 2) { + return cpucontrol_help(argc, argv); + } + + if (strcmp(argv[1], "on") == 0) { + return cpucontrol_cpu_on(argc, argv); + } else if (strcmp(argv[1], "off") == 0) { + return cpucontrol_cpu_off(argc, argv); + } else if (strcmp(argv[1], "help") == 0) { + return cpucontrol_help(argc, argv); + } else if (strcmp(argv[1], "status") == 0) { + return cpucontrol_cpu_status(argc, argv); + } else { + printf("Unknown subcommand: %s\n", argv[1]); + return cpucontrol_help(argc, argv); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void cpucontrol_register_cmds(void) +{ + /* Register the CPU control command during system initialization */ + tash_cmd_install("cpuctrl", cpucontrol_main, TASH_EXECMD_ASYNC); +} diff --git a/apps/system/init/init.c b/apps/system/init/init.c index 3415c37048..c969ddd08b 100644 --- a/apps/system/init/init.c +++ b/apps/system/init/init.c @@ -73,6 +73,10 @@ extern void iotjs_register_cmds(void); #endif +#ifdef CONFIG_SYSTEM_CPUCONTROL +extern void cpucontrol_register_cmds(void); +#endif + /**************************************************************************** * Pravite Functions ****************************************************************************/ @@ -107,6 +111,10 @@ static void tash_register_cmds(void) #ifdef CONFIG_DEBUG_SYSTEM_APP sysdbgapp_init(); #endif + +#ifdef CONFIG_SYSTEM_CPUCONTROL + cpucontrol_register_cmds(); +#endif } #endif /* CONFIG_TASH */ From c68e8a8d06fc15ae1066823e20d25eeb9665e091 Mon Sep 17 00:00:00 2001 From: Suneel Date: Thu, 6 Nov 2025 20:44:48 +0530 Subject: [PATCH 3/3] build/configs/rtl8730e: Enable CPU driver and CPU control app configuration for rtl8730e Add CONFIG_CPU_DRIVER=y and CONFIG_SYSTEM_CPUCONTROL=y to rtl8730e board configurations to enable CPU driver support and CPU control app for CPU management operations. --- build/configs/rtl8730e/flat_dev_ddr/defconfig | 2 ++ build/configs/rtl8730e/loadable_ext_ddr/defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/build/configs/rtl8730e/flat_dev_ddr/defconfig b/build/configs/rtl8730e/flat_dev_ddr/defconfig index d15434b689..6a5123c8a4 100644 --- a/build/configs/rtl8730e/flat_dev_ddr/defconfig +++ b/build/configs/rtl8730e/flat_dev_ddr/defconfig @@ -577,6 +577,8 @@ CONFIG_NDP120_ALIVE_CHECK=y # LCD Driver Support # # CONFIG_LCD is not set +CONFIG_CPU_DRIVER=y +CONFIG_SYSTEM_CPUCONTROL=y CONFIG_BCH=y CONFIG_RTC=y # CONFIG_RTC_DATETIME is not set diff --git a/build/configs/rtl8730e/loadable_ext_ddr/defconfig b/build/configs/rtl8730e/loadable_ext_ddr/defconfig index ae4b9f66e5..81d6f8d8ff 100644 --- a/build/configs/rtl8730e/loadable_ext_ddr/defconfig +++ b/build/configs/rtl8730e/loadable_ext_ddr/defconfig @@ -551,6 +551,8 @@ CONFIG_DEV_ZERO=y # CONFIG_ARCH_HAVE_PWM_MULTICHAN is not set # CONFIG_PWM is not set # CONFIG_ARCH_HAVE_I2CRESET is not set +CONFIG_CPU_DRIVER=y +CONFIG_SYSTEM_CPUCONTROL=y CONFIG_I2C=y # CONFIG_I2C_SLAVE is not set CONFIG_I2C_USERIO=y