17fd786dfSSrinivas Pandruvada // SPDX-License-Identifier: GPL-2.0
27fd786dfSSrinivas Pandruvada /*
37fd786dfSSrinivas Pandruvada * Intel Speed Select -- Allow speed select to daemonize
47fd786dfSSrinivas Pandruvada * Copyright (c) 2022 Intel Corporation.
57fd786dfSSrinivas Pandruvada */
67fd786dfSSrinivas Pandruvada
77fd786dfSSrinivas Pandruvada #include <stdio.h>
87fd786dfSSrinivas Pandruvada #include <stdlib.h>
97fd786dfSSrinivas Pandruvada #include <stdarg.h>
107fd786dfSSrinivas Pandruvada #include <string.h>
117fd786dfSSrinivas Pandruvada #include <unistd.h>
127fd786dfSSrinivas Pandruvada #include <fcntl.h>
137fd786dfSSrinivas Pandruvada #include <sys/file.h>
147fd786dfSSrinivas Pandruvada #include <sys/types.h>
157fd786dfSSrinivas Pandruvada #include <sys/stat.h>
167fd786dfSSrinivas Pandruvada #include <errno.h>
177fd786dfSSrinivas Pandruvada #include <getopt.h>
187fd786dfSSrinivas Pandruvada #include <signal.h>
197fd786dfSSrinivas Pandruvada #include <time.h>
207fd786dfSSrinivas Pandruvada
217fd786dfSSrinivas Pandruvada #include "isst.h"
227fd786dfSSrinivas Pandruvada
23b4edf385SZhang Rui static int per_package_levels_info[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE][MAX_PUNIT_PER_DIE];
24b4edf385SZhang Rui static time_t per_package_levels_tm[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE][MAX_PUNIT_PER_DIE];
257fd786dfSSrinivas Pandruvada
init_levels(void)267fd786dfSSrinivas Pandruvada static void init_levels(void)
277fd786dfSSrinivas Pandruvada {
28b4edf385SZhang Rui int i, j, k;
297fd786dfSSrinivas Pandruvada
307fd786dfSSrinivas Pandruvada for (i = 0; i < MAX_PACKAGE_COUNT; ++i)
317fd786dfSSrinivas Pandruvada for (j = 0; j < MAX_DIE_PER_PACKAGE; ++j)
32b4edf385SZhang Rui for (k = 0; k < MAX_PUNIT_PER_DIE; ++k)
33b4edf385SZhang Rui per_package_levels_info[i][j][k] = -1;
347fd786dfSSrinivas Pandruvada }
357fd786dfSSrinivas Pandruvada
process_level_change(struct isst_id * id)36850337ecSZhang Rui void process_level_change(struct isst_id *id)
377fd786dfSSrinivas Pandruvada {
387fd786dfSSrinivas Pandruvada struct isst_pkg_ctdp_level_info ctdp_level;
397fd786dfSSrinivas Pandruvada struct isst_pkg_ctdp pkg_dev;
407fd786dfSSrinivas Pandruvada time_t tm;
417fd786dfSSrinivas Pandruvada int ret;
427fd786dfSSrinivas Pandruvada
43b4edf385SZhang Rui if (id->pkg < 0 || id->die < 0 || id->punit < 0) {
44850337ecSZhang Rui debug_printf("Invalid package/die info for cpu:%d\n", id->cpu);
457fd786dfSSrinivas Pandruvada return;
467fd786dfSSrinivas Pandruvada }
477fd786dfSSrinivas Pandruvada
487fd786dfSSrinivas Pandruvada tm = time(NULL);
49b4edf385SZhang Rui if (tm - per_package_levels_tm[id->pkg][id->die][id->punit] < 2)
507fd786dfSSrinivas Pandruvada return;
517fd786dfSSrinivas Pandruvada
52b4edf385SZhang Rui per_package_levels_tm[id->pkg][id->die][id->punit] = tm;
537fd786dfSSrinivas Pandruvada
54850337ecSZhang Rui ret = isst_get_ctdp_levels(id, &pkg_dev);
557fd786dfSSrinivas Pandruvada if (ret) {
56850337ecSZhang Rui debug_printf("Can't get tdp levels for cpu:%d\n", id->cpu);
577fd786dfSSrinivas Pandruvada return;
587fd786dfSSrinivas Pandruvada }
597fd786dfSSrinivas Pandruvada
60850337ecSZhang Rui debug_printf("Get Config level %d pkg:%d die:%d current_level:%d\n", id->cpu,
6156d64692SZhang Rui id->pkg, id->die, pkg_dev.current_level);
627fd786dfSSrinivas Pandruvada
637fd786dfSSrinivas Pandruvada if (pkg_dev.locked) {
647fd786dfSSrinivas Pandruvada debug_printf("config TDP s locked \n");
657fd786dfSSrinivas Pandruvada return;
667fd786dfSSrinivas Pandruvada }
677fd786dfSSrinivas Pandruvada
68b4edf385SZhang Rui if (per_package_levels_info[id->pkg][id->die][id->punit] == pkg_dev.current_level)
697fd786dfSSrinivas Pandruvada return;
707fd786dfSSrinivas Pandruvada
717fd786dfSSrinivas Pandruvada debug_printf("**Config level change for cpu:%d pkg:%d die:%d from %d to %d\n",
72b4edf385SZhang Rui id->cpu, id->pkg, id->die, per_package_levels_info[id->pkg][id->die][id->punit],
737fd786dfSSrinivas Pandruvada pkg_dev.current_level);
747fd786dfSSrinivas Pandruvada
75b4edf385SZhang Rui per_package_levels_info[id->pkg][id->die][id->punit] = pkg_dev.current_level;
767fd786dfSSrinivas Pandruvada
777fd786dfSSrinivas Pandruvada ctdp_level.core_cpumask_size =
787fd786dfSSrinivas Pandruvada alloc_cpu_set(&ctdp_level.core_cpumask);
79850337ecSZhang Rui ret = isst_get_coremask_info(id, pkg_dev.current_level, &ctdp_level);
807fd786dfSSrinivas Pandruvada if (ret) {
817fd786dfSSrinivas Pandruvada free_cpu_set(ctdp_level.core_cpumask);
82850337ecSZhang Rui debug_printf("Can't get core_mask:%d\n", id->cpu);
837fd786dfSSrinivas Pandruvada return;
847fd786dfSSrinivas Pandruvada }
857fd786dfSSrinivas Pandruvada
86997074dfSSrinivas Pandruvada if (use_cgroupv2()) {
87997074dfSSrinivas Pandruvada int ret;
88997074dfSSrinivas Pandruvada
89997074dfSSrinivas Pandruvada ret = enable_cpuset_controller();
90997074dfSSrinivas Pandruvada if (ret)
91997074dfSSrinivas Pandruvada goto use_offline;
92997074dfSSrinivas Pandruvada
93*3bc0f20aSSrinivas Pandruvada isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask,
94*3bc0f20aSSrinivas Pandruvada pkg_dev.current_level, 0);
95997074dfSSrinivas Pandruvada
96997074dfSSrinivas Pandruvada goto free_mask;
97997074dfSSrinivas Pandruvada }
98997074dfSSrinivas Pandruvada
99997074dfSSrinivas Pandruvada use_offline:
1007fd786dfSSrinivas Pandruvada if (ctdp_level.cpu_count) {
1017fd786dfSSrinivas Pandruvada int i, max_cpus = get_topo_max_cpus();
1027fd786dfSSrinivas Pandruvada for (i = 0; i < max_cpus; ++i) {
10300bb07dbSZhang Rui if (!is_cpu_in_power_domain(i, id))
1047fd786dfSSrinivas Pandruvada continue;
1057fd786dfSSrinivas Pandruvada if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
1067fd786dfSSrinivas Pandruvada fprintf(stderr, "online cpu %d\n", i);
1077fd786dfSSrinivas Pandruvada set_cpu_online_offline(i, 1);
1087fd786dfSSrinivas Pandruvada } else {
1097fd786dfSSrinivas Pandruvada fprintf(stderr, "offline cpu %d\n", i);
1107fd786dfSSrinivas Pandruvada set_cpu_online_offline(i, 0);
1117fd786dfSSrinivas Pandruvada }
1127fd786dfSSrinivas Pandruvada }
1137fd786dfSSrinivas Pandruvada }
114997074dfSSrinivas Pandruvada free_mask:
1157fd786dfSSrinivas Pandruvada free_cpu_set(ctdp_level.core_cpumask);
1167fd786dfSSrinivas Pandruvada }
1177fd786dfSSrinivas Pandruvada
_poll_for_config_change(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)118850337ecSZhang Rui static void _poll_for_config_change(struct isst_id *id, void *arg1, void *arg2,
1197fd786dfSSrinivas Pandruvada void *arg3, void *arg4)
1207fd786dfSSrinivas Pandruvada {
121850337ecSZhang Rui process_level_change(id);
1227fd786dfSSrinivas Pandruvada }
1237fd786dfSSrinivas Pandruvada
poll_for_config_change(void)1247fd786dfSSrinivas Pandruvada static void poll_for_config_change(void)
1257fd786dfSSrinivas Pandruvada {
126c77a8d4aSZhang Rui for_each_online_power_domain_in_set(_poll_for_config_change, NULL, NULL,
1277fd786dfSSrinivas Pandruvada NULL, NULL);
1287fd786dfSSrinivas Pandruvada }
1297fd786dfSSrinivas Pandruvada
1307fd786dfSSrinivas Pandruvada static int done = 0;
1317fd786dfSSrinivas Pandruvada static int pid_file_handle;
1327fd786dfSSrinivas Pandruvada
signal_handler(int sig)1337fd786dfSSrinivas Pandruvada static void signal_handler(int sig)
1347fd786dfSSrinivas Pandruvada {
1357fd786dfSSrinivas Pandruvada switch (sig) {
1367fd786dfSSrinivas Pandruvada case SIGINT:
1377fd786dfSSrinivas Pandruvada case SIGTERM:
1387fd786dfSSrinivas Pandruvada done = 1;
1397d440da0SSrinivas Pandruvada hfi_exit();
1407fd786dfSSrinivas Pandruvada exit(0);
1417fd786dfSSrinivas Pandruvada break;
1427fd786dfSSrinivas Pandruvada default:
1437fd786dfSSrinivas Pandruvada break;
1447fd786dfSSrinivas Pandruvada }
1457fd786dfSSrinivas Pandruvada }
1467fd786dfSSrinivas Pandruvada
daemonize(char * rundir,char * pidfile)1477fd786dfSSrinivas Pandruvada static void daemonize(char *rundir, char *pidfile)
1487fd786dfSSrinivas Pandruvada {
1497fd786dfSSrinivas Pandruvada int pid, sid, i;
1507fd786dfSSrinivas Pandruvada char str[10];
1517fd786dfSSrinivas Pandruvada struct sigaction sig_actions;
1527fd786dfSSrinivas Pandruvada sigset_t sig_set;
1537fd786dfSSrinivas Pandruvada int ret;
1547fd786dfSSrinivas Pandruvada
1557fd786dfSSrinivas Pandruvada if (getppid() == 1)
1567fd786dfSSrinivas Pandruvada return;
1577fd786dfSSrinivas Pandruvada
1587fd786dfSSrinivas Pandruvada sigemptyset(&sig_set);
1597fd786dfSSrinivas Pandruvada sigaddset(&sig_set, SIGCHLD);
1607fd786dfSSrinivas Pandruvada sigaddset(&sig_set, SIGTSTP);
1617fd786dfSSrinivas Pandruvada sigaddset(&sig_set, SIGTTOU);
1627fd786dfSSrinivas Pandruvada sigaddset(&sig_set, SIGTTIN);
1637fd786dfSSrinivas Pandruvada sigprocmask(SIG_BLOCK, &sig_set, NULL);
1647fd786dfSSrinivas Pandruvada
1657fd786dfSSrinivas Pandruvada sig_actions.sa_handler = signal_handler;
1667fd786dfSSrinivas Pandruvada sigemptyset(&sig_actions.sa_mask);
1677fd786dfSSrinivas Pandruvada sig_actions.sa_flags = 0;
1687fd786dfSSrinivas Pandruvada
1697fd786dfSSrinivas Pandruvada sigaction(SIGHUP, &sig_actions, NULL);
1707fd786dfSSrinivas Pandruvada sigaction(SIGTERM, &sig_actions, NULL);
1717fd786dfSSrinivas Pandruvada sigaction(SIGINT, &sig_actions, NULL);
1727fd786dfSSrinivas Pandruvada
1737fd786dfSSrinivas Pandruvada pid = fork();
1747fd786dfSSrinivas Pandruvada if (pid < 0) {
1757fd786dfSSrinivas Pandruvada /* Could not fork */
1767fd786dfSSrinivas Pandruvada exit(EXIT_FAILURE);
1777fd786dfSSrinivas Pandruvada }
1787fd786dfSSrinivas Pandruvada if (pid > 0)
1797fd786dfSSrinivas Pandruvada exit(EXIT_SUCCESS);
1807fd786dfSSrinivas Pandruvada
1817fd786dfSSrinivas Pandruvada umask(027);
1827fd786dfSSrinivas Pandruvada
1837fd786dfSSrinivas Pandruvada sid = setsid();
1847fd786dfSSrinivas Pandruvada if (sid < 0)
1857fd786dfSSrinivas Pandruvada exit(EXIT_FAILURE);
1867fd786dfSSrinivas Pandruvada
1877fd786dfSSrinivas Pandruvada /* close all descriptors */
1887fd786dfSSrinivas Pandruvada for (i = getdtablesize(); i >= 0; --i)
1897fd786dfSSrinivas Pandruvada close(i);
1907fd786dfSSrinivas Pandruvada
1917fd786dfSSrinivas Pandruvada i = open("/dev/null", O_RDWR);
192364ba3b7SZhang Rui if (i < 0)
193364ba3b7SZhang Rui exit(EXIT_FAILURE);
1947fd786dfSSrinivas Pandruvada
1957fd786dfSSrinivas Pandruvada ret = dup(i);
1967fd786dfSSrinivas Pandruvada if (ret == -1)
1977fd786dfSSrinivas Pandruvada exit(EXIT_FAILURE);
1987fd786dfSSrinivas Pandruvada
1997fd786dfSSrinivas Pandruvada ret = chdir(rundir);
2007fd786dfSSrinivas Pandruvada if (ret == -1)
2017fd786dfSSrinivas Pandruvada exit(EXIT_FAILURE);
2027fd786dfSSrinivas Pandruvada
2037fd786dfSSrinivas Pandruvada pid_file_handle = open(pidfile, O_RDWR | O_CREAT, 0600);
2047fd786dfSSrinivas Pandruvada if (pid_file_handle == -1) {
2057fd786dfSSrinivas Pandruvada /* Couldn't open lock file */
2067fd786dfSSrinivas Pandruvada exit(1);
2077fd786dfSSrinivas Pandruvada }
2087fd786dfSSrinivas Pandruvada /* Try to lock file */
2097fd786dfSSrinivas Pandruvada #ifdef LOCKF_SUPPORT
2107fd786dfSSrinivas Pandruvada if (lockf(pid_file_handle, F_TLOCK, 0) == -1) {
2117fd786dfSSrinivas Pandruvada #else
2127fd786dfSSrinivas Pandruvada if (flock(pid_file_handle, LOCK_EX|LOCK_NB) < 0) {
2137fd786dfSSrinivas Pandruvada #endif
2147fd786dfSSrinivas Pandruvada /* Couldn't get lock on lock file */
2157fd786dfSSrinivas Pandruvada fprintf(stderr, "Couldn't get lock file %d\n", getpid());
2167fd786dfSSrinivas Pandruvada exit(1);
2177fd786dfSSrinivas Pandruvada }
2187fd786dfSSrinivas Pandruvada snprintf(str, sizeof(str), "%d\n", getpid());
2197fd786dfSSrinivas Pandruvada ret = write(pid_file_handle, str, strlen(str));
2207fd786dfSSrinivas Pandruvada if (ret == -1)
2217fd786dfSSrinivas Pandruvada exit(EXIT_FAILURE);
2227fd786dfSSrinivas Pandruvada
2237fd786dfSSrinivas Pandruvada close(i);
2247fd786dfSSrinivas Pandruvada }
2257fd786dfSSrinivas Pandruvada
2267fd786dfSSrinivas Pandruvada int isst_daemon(int debug_mode, int poll_interval, int no_daemon)
2277fd786dfSSrinivas Pandruvada {
2287fd786dfSSrinivas Pandruvada int ret;
2297fd786dfSSrinivas Pandruvada
2307fd786dfSSrinivas Pandruvada if (!no_daemon && poll_interval < 0 && !debug_mode) {
2317fd786dfSSrinivas Pandruvada fprintf(stderr, "OOB mode is enabled and will run as daemon\n");
2327fd786dfSSrinivas Pandruvada daemonize((char *) "/tmp/",
2337fd786dfSSrinivas Pandruvada (char *)"/tmp/hfi-events.pid");
2347fd786dfSSrinivas Pandruvada } else {
2357fd786dfSSrinivas Pandruvada signal(SIGINT, signal_handler);
2367fd786dfSSrinivas Pandruvada }
2377fd786dfSSrinivas Pandruvada
2387fd786dfSSrinivas Pandruvada init_levels();
2397fd786dfSSrinivas Pandruvada
2407fd786dfSSrinivas Pandruvada if (poll_interval < 0) {
2417d440da0SSrinivas Pandruvada ret = hfi_main();
2427d440da0SSrinivas Pandruvada if (ret) {
2437d440da0SSrinivas Pandruvada fprintf(stderr, "HFI initialization failed\n");
2447d440da0SSrinivas Pandruvada }
2457fd786dfSSrinivas Pandruvada fprintf(stderr, "Must specify poll-interval\n");
2467fd786dfSSrinivas Pandruvada return ret;
2477fd786dfSSrinivas Pandruvada }
2487fd786dfSSrinivas Pandruvada
2497fd786dfSSrinivas Pandruvada debug_printf("Starting loop\n");
2507fd786dfSSrinivas Pandruvada while (!done) {
2517fd786dfSSrinivas Pandruvada sleep(poll_interval);
2527fd786dfSSrinivas Pandruvada poll_for_config_change();
2537fd786dfSSrinivas Pandruvada }
2547fd786dfSSrinivas Pandruvada
2557fd786dfSSrinivas Pandruvada return 0;
2567fd786dfSSrinivas Pandruvada }
257