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 
237fd786dfSSrinivas Pandruvada static int per_package_levels_info[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
247fd786dfSSrinivas Pandruvada static time_t per_package_levels_tm[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
257fd786dfSSrinivas Pandruvada 
267fd786dfSSrinivas Pandruvada static void init_levels(void)
277fd786dfSSrinivas Pandruvada {
287fd786dfSSrinivas Pandruvada 	int i, j;
297fd786dfSSrinivas Pandruvada 
307fd786dfSSrinivas Pandruvada 	for (i = 0; i < MAX_PACKAGE_COUNT; ++i)
317fd786dfSSrinivas Pandruvada 		for (j = 0; j < MAX_DIE_PER_PACKAGE; ++j)
327fd786dfSSrinivas Pandruvada 			per_package_levels_info[i][j] = -1;
337fd786dfSSrinivas Pandruvada }
347fd786dfSSrinivas Pandruvada 
35*850337ecSZhang Rui void process_level_change(struct isst_id *id)
367fd786dfSSrinivas Pandruvada {
377fd786dfSSrinivas Pandruvada 	struct isst_pkg_ctdp_level_info ctdp_level;
38*850337ecSZhang Rui 	int pkg_id = get_physical_package_id(id->cpu);
39*850337ecSZhang Rui 	int die_id = get_physical_die_id(id->cpu);
407fd786dfSSrinivas Pandruvada 	struct isst_pkg_ctdp pkg_dev;
417fd786dfSSrinivas Pandruvada 	time_t tm;
427fd786dfSSrinivas Pandruvada 	int ret;
437fd786dfSSrinivas Pandruvada 
44d9f74d98SDan Carpenter 	if (pkg_id >= MAX_PACKAGE_COUNT || die_id >= MAX_DIE_PER_PACKAGE) {
45*850337ecSZhang Rui 		debug_printf("Invalid package/die info for cpu:%d\n", id->cpu);
467fd786dfSSrinivas Pandruvada 		return;
477fd786dfSSrinivas Pandruvada 	}
487fd786dfSSrinivas Pandruvada 
497fd786dfSSrinivas Pandruvada 	tm = time(NULL);
507fd786dfSSrinivas Pandruvada 	if (tm - per_package_levels_tm[pkg_id][die_id] < 2 )
517fd786dfSSrinivas Pandruvada 		return;
527fd786dfSSrinivas Pandruvada 
537fd786dfSSrinivas Pandruvada 	per_package_levels_tm[pkg_id][die_id] = tm;
547fd786dfSSrinivas Pandruvada 
55*850337ecSZhang Rui 	ret = isst_get_ctdp_levels(id, &pkg_dev);
567fd786dfSSrinivas Pandruvada 	if (ret) {
57*850337ecSZhang Rui 		debug_printf("Can't get tdp levels for cpu:%d\n", id->cpu);
587fd786dfSSrinivas Pandruvada 		return;
597fd786dfSSrinivas Pandruvada 	}
607fd786dfSSrinivas Pandruvada 
61*850337ecSZhang Rui 	debug_printf("Get Config level %d pkg:%d die:%d current_level:%d\n", id->cpu,
627fd786dfSSrinivas Pandruvada 		      pkg_id, die_id, pkg_dev.current_level);
637fd786dfSSrinivas Pandruvada 
647fd786dfSSrinivas Pandruvada 	if (pkg_dev.locked) {
657fd786dfSSrinivas Pandruvada 		debug_printf("config TDP s locked \n");
667fd786dfSSrinivas Pandruvada 		return;
677fd786dfSSrinivas Pandruvada 	}
687fd786dfSSrinivas Pandruvada 
697fd786dfSSrinivas Pandruvada 	if (per_package_levels_info[pkg_id][die_id] == pkg_dev.current_level)
707fd786dfSSrinivas Pandruvada 		return;
717fd786dfSSrinivas Pandruvada 
727fd786dfSSrinivas Pandruvada 	debug_printf("**Config level change for cpu:%d pkg:%d die:%d from %d to %d\n",
73*850337ecSZhang Rui 		      id->cpu, pkg_id, die_id, per_package_levels_info[pkg_id][die_id],
747fd786dfSSrinivas Pandruvada 		      pkg_dev.current_level);
757fd786dfSSrinivas Pandruvada 
767fd786dfSSrinivas Pandruvada 	per_package_levels_info[pkg_id][die_id] = pkg_dev.current_level;
777fd786dfSSrinivas Pandruvada 
787fd786dfSSrinivas Pandruvada 	ctdp_level.core_cpumask_size =
797fd786dfSSrinivas Pandruvada 		alloc_cpu_set(&ctdp_level.core_cpumask);
80*850337ecSZhang Rui 	ret = isst_get_coremask_info(id, pkg_dev.current_level, &ctdp_level);
817fd786dfSSrinivas Pandruvada 	if (ret) {
827fd786dfSSrinivas Pandruvada 		free_cpu_set(ctdp_level.core_cpumask);
83*850337ecSZhang Rui 		debug_printf("Can't get core_mask:%d\n", id->cpu);
847fd786dfSSrinivas Pandruvada 		return;
857fd786dfSSrinivas Pandruvada 	}
867fd786dfSSrinivas Pandruvada 
877fd786dfSSrinivas Pandruvada 	if (ctdp_level.cpu_count) {
887fd786dfSSrinivas Pandruvada 		int i, max_cpus = get_topo_max_cpus();
897fd786dfSSrinivas Pandruvada 		for (i = 0; i < max_cpus; ++i) {
907fd786dfSSrinivas Pandruvada 			if (pkg_id != get_physical_package_id(i) || die_id != get_physical_die_id(i))
917fd786dfSSrinivas Pandruvada 				continue;
927fd786dfSSrinivas Pandruvada 			if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
937fd786dfSSrinivas Pandruvada 				fprintf(stderr, "online cpu %d\n", i);
947fd786dfSSrinivas Pandruvada 				set_cpu_online_offline(i, 1);
957fd786dfSSrinivas Pandruvada 			} else {
967fd786dfSSrinivas Pandruvada 				fprintf(stderr, "offline cpu %d\n", i);
977fd786dfSSrinivas Pandruvada 				set_cpu_online_offline(i, 0);
987fd786dfSSrinivas Pandruvada 			}
997fd786dfSSrinivas Pandruvada 		}
1007fd786dfSSrinivas Pandruvada 	}
1017fd786dfSSrinivas Pandruvada 
1027fd786dfSSrinivas Pandruvada 	free_cpu_set(ctdp_level.core_cpumask);
1037fd786dfSSrinivas Pandruvada }
1047fd786dfSSrinivas Pandruvada 
105*850337ecSZhang Rui static void _poll_for_config_change(struct isst_id *id, void *arg1, void *arg2,
1067fd786dfSSrinivas Pandruvada 				    void *arg3, void *arg4)
1077fd786dfSSrinivas Pandruvada {
108*850337ecSZhang Rui 	process_level_change(id);
1097fd786dfSSrinivas Pandruvada }
1107fd786dfSSrinivas Pandruvada 
1117fd786dfSSrinivas Pandruvada static void poll_for_config_change(void)
1127fd786dfSSrinivas Pandruvada {
1137fd786dfSSrinivas Pandruvada 	for_each_online_package_in_set(_poll_for_config_change, NULL, NULL,
1147fd786dfSSrinivas Pandruvada 				       NULL, NULL);
1157fd786dfSSrinivas Pandruvada }
1167fd786dfSSrinivas Pandruvada 
1177fd786dfSSrinivas Pandruvada static int done = 0;
1187fd786dfSSrinivas Pandruvada static int pid_file_handle;
1197fd786dfSSrinivas Pandruvada 
1207fd786dfSSrinivas Pandruvada static void signal_handler(int sig)
1217fd786dfSSrinivas Pandruvada {
1227fd786dfSSrinivas Pandruvada 	switch (sig) {
1237fd786dfSSrinivas Pandruvada 	case SIGINT:
1247fd786dfSSrinivas Pandruvada 	case SIGTERM:
1257fd786dfSSrinivas Pandruvada 		done = 1;
1267d440da0SSrinivas Pandruvada 		hfi_exit();
1277fd786dfSSrinivas Pandruvada 		exit(0);
1287fd786dfSSrinivas Pandruvada 		break;
1297fd786dfSSrinivas Pandruvada 	default:
1307fd786dfSSrinivas Pandruvada 		break;
1317fd786dfSSrinivas Pandruvada 	}
1327fd786dfSSrinivas Pandruvada }
1337fd786dfSSrinivas Pandruvada 
1347fd786dfSSrinivas Pandruvada static void daemonize(char *rundir, char *pidfile)
1357fd786dfSSrinivas Pandruvada {
1367fd786dfSSrinivas Pandruvada 	int pid, sid, i;
1377fd786dfSSrinivas Pandruvada 	char str[10];
1387fd786dfSSrinivas Pandruvada 	struct sigaction sig_actions;
1397fd786dfSSrinivas Pandruvada 	sigset_t sig_set;
1407fd786dfSSrinivas Pandruvada 	int ret;
1417fd786dfSSrinivas Pandruvada 
1427fd786dfSSrinivas Pandruvada 	if (getppid() == 1)
1437fd786dfSSrinivas Pandruvada 		return;
1447fd786dfSSrinivas Pandruvada 
1457fd786dfSSrinivas Pandruvada 	sigemptyset(&sig_set);
1467fd786dfSSrinivas Pandruvada 	sigaddset(&sig_set, SIGCHLD);
1477fd786dfSSrinivas Pandruvada 	sigaddset(&sig_set, SIGTSTP);
1487fd786dfSSrinivas Pandruvada 	sigaddset(&sig_set, SIGTTOU);
1497fd786dfSSrinivas Pandruvada 	sigaddset(&sig_set, SIGTTIN);
1507fd786dfSSrinivas Pandruvada 	sigprocmask(SIG_BLOCK, &sig_set, NULL);
1517fd786dfSSrinivas Pandruvada 
1527fd786dfSSrinivas Pandruvada 	sig_actions.sa_handler = signal_handler;
1537fd786dfSSrinivas Pandruvada 	sigemptyset(&sig_actions.sa_mask);
1547fd786dfSSrinivas Pandruvada 	sig_actions.sa_flags = 0;
1557fd786dfSSrinivas Pandruvada 
1567fd786dfSSrinivas Pandruvada 	sigaction(SIGHUP, &sig_actions, NULL);
1577fd786dfSSrinivas Pandruvada 	sigaction(SIGTERM, &sig_actions, NULL);
1587fd786dfSSrinivas Pandruvada 	sigaction(SIGINT, &sig_actions, NULL);
1597fd786dfSSrinivas Pandruvada 
1607fd786dfSSrinivas Pandruvada 	pid = fork();
1617fd786dfSSrinivas Pandruvada 	if (pid < 0) {
1627fd786dfSSrinivas Pandruvada 		/* Could not fork */
1637fd786dfSSrinivas Pandruvada 		exit(EXIT_FAILURE);
1647fd786dfSSrinivas Pandruvada 	}
1657fd786dfSSrinivas Pandruvada 	if (pid > 0)
1667fd786dfSSrinivas Pandruvada 		exit(EXIT_SUCCESS);
1677fd786dfSSrinivas Pandruvada 
1687fd786dfSSrinivas Pandruvada 	umask(027);
1697fd786dfSSrinivas Pandruvada 
1707fd786dfSSrinivas Pandruvada 	sid = setsid();
1717fd786dfSSrinivas Pandruvada 	if (sid < 0)
1727fd786dfSSrinivas Pandruvada 		exit(EXIT_FAILURE);
1737fd786dfSSrinivas Pandruvada 
1747fd786dfSSrinivas Pandruvada 	/* close all descriptors */
1757fd786dfSSrinivas Pandruvada 	for (i = getdtablesize(); i >= 0; --i)
1767fd786dfSSrinivas Pandruvada 		close(i);
1777fd786dfSSrinivas Pandruvada 
1787fd786dfSSrinivas Pandruvada 	i = open("/dev/null", O_RDWR);
1797fd786dfSSrinivas Pandruvada 	ret = dup(i);
1807fd786dfSSrinivas Pandruvada 	if (ret == -1)
1817fd786dfSSrinivas Pandruvada 		exit(EXIT_FAILURE);
1827fd786dfSSrinivas Pandruvada 
1837fd786dfSSrinivas Pandruvada 	ret = dup(i);
1847fd786dfSSrinivas Pandruvada 	if (ret == -1)
1857fd786dfSSrinivas Pandruvada 		exit(EXIT_FAILURE);
1867fd786dfSSrinivas Pandruvada 
1877fd786dfSSrinivas Pandruvada 	ret = chdir(rundir);
1887fd786dfSSrinivas Pandruvada 	if (ret == -1)
1897fd786dfSSrinivas Pandruvada 		exit(EXIT_FAILURE);
1907fd786dfSSrinivas Pandruvada 
1917fd786dfSSrinivas Pandruvada 	pid_file_handle = open(pidfile, O_RDWR | O_CREAT, 0600);
1927fd786dfSSrinivas Pandruvada 	if (pid_file_handle == -1) {
1937fd786dfSSrinivas Pandruvada 		/* Couldn't open lock file */
1947fd786dfSSrinivas Pandruvada 		exit(1);
1957fd786dfSSrinivas Pandruvada 	}
1967fd786dfSSrinivas Pandruvada 	/* Try to lock file */
1977fd786dfSSrinivas Pandruvada #ifdef LOCKF_SUPPORT
1987fd786dfSSrinivas Pandruvada 	if (lockf(pid_file_handle, F_TLOCK, 0) == -1) {
1997fd786dfSSrinivas Pandruvada #else
2007fd786dfSSrinivas Pandruvada 	if (flock(pid_file_handle, LOCK_EX|LOCK_NB) < 0) {
2017fd786dfSSrinivas Pandruvada #endif
2027fd786dfSSrinivas Pandruvada 		/* Couldn't get lock on lock file */
2037fd786dfSSrinivas Pandruvada 		fprintf(stderr, "Couldn't get lock file %d\n", getpid());
2047fd786dfSSrinivas Pandruvada 		exit(1);
2057fd786dfSSrinivas Pandruvada 	}
2067fd786dfSSrinivas Pandruvada 	snprintf(str, sizeof(str), "%d\n", getpid());
2077fd786dfSSrinivas Pandruvada 	ret = write(pid_file_handle, str, strlen(str));
2087fd786dfSSrinivas Pandruvada 	if (ret == -1)
2097fd786dfSSrinivas Pandruvada 		exit(EXIT_FAILURE);
2107fd786dfSSrinivas Pandruvada 
2117fd786dfSSrinivas Pandruvada 	close(i);
2127fd786dfSSrinivas Pandruvada }
2137fd786dfSSrinivas Pandruvada 
2147fd786dfSSrinivas Pandruvada int isst_daemon(int debug_mode, int poll_interval, int no_daemon)
2157fd786dfSSrinivas Pandruvada {
2167fd786dfSSrinivas Pandruvada 	int ret;
2177fd786dfSSrinivas Pandruvada 
2187fd786dfSSrinivas Pandruvada 	if (!no_daemon && poll_interval < 0 && !debug_mode) {
2197fd786dfSSrinivas Pandruvada 		fprintf(stderr, "OOB mode is enabled and will run as daemon\n");
2207fd786dfSSrinivas Pandruvada 		daemonize((char *) "/tmp/",
2217fd786dfSSrinivas Pandruvada 				(char *)"/tmp/hfi-events.pid");
2227fd786dfSSrinivas Pandruvada 	} else {
2237fd786dfSSrinivas Pandruvada 		signal(SIGINT, signal_handler);
2247fd786dfSSrinivas Pandruvada 	}
2257fd786dfSSrinivas Pandruvada 
2267fd786dfSSrinivas Pandruvada 	init_levels();
2277fd786dfSSrinivas Pandruvada 
2287fd786dfSSrinivas Pandruvada 	if (poll_interval < 0) {
2297d440da0SSrinivas Pandruvada 		ret = hfi_main();
2307d440da0SSrinivas Pandruvada 		if (ret) {
2317d440da0SSrinivas Pandruvada 			fprintf(stderr, "HFI initialization failed\n");
2327d440da0SSrinivas Pandruvada 		}
2337fd786dfSSrinivas Pandruvada 		fprintf(stderr, "Must specify poll-interval\n");
2347fd786dfSSrinivas Pandruvada 		return ret;
2357fd786dfSSrinivas Pandruvada 	}
2367fd786dfSSrinivas Pandruvada 
2377fd786dfSSrinivas Pandruvada 	debug_printf("Starting loop\n");
2387fd786dfSSrinivas Pandruvada 	while (!done) {
2397fd786dfSSrinivas Pandruvada 		sleep(poll_interval);
2407fd786dfSSrinivas Pandruvada 		poll_for_config_change();
2417fd786dfSSrinivas Pandruvada 	}
2427fd786dfSSrinivas Pandruvada 
2437fd786dfSSrinivas Pandruvada 	return 0;
2447fd786dfSSrinivas Pandruvada }
245