xref: /openbmc/linux/tools/testing/selftests/timers/clocksource-switch.c (revision 060f35a317ef09101b128f399dce7ed13d019461)
17290ce14SJohn Stultz /* Clocksource change test
27290ce14SJohn Stultz  *		by: john stultz (johnstul@us.ibm.com)
37290ce14SJohn Stultz  *		(C) Copyright IBM 2012
47290ce14SJohn Stultz  *		Licensed under the GPLv2
57290ce14SJohn Stultz  *
64bf07f65SIngo Molnar  *  NOTE: This is a meta-test which quickly changes the clocksource and
77290ce14SJohn Stultz  *  then uses other tests to detect problems. Thus this test requires
87290ce14SJohn Stultz  *  that the inconsistency-check and nanosleep tests be present in the
97290ce14SJohn Stultz  *  same directory it is run from.
107290ce14SJohn Stultz  *
117290ce14SJohn Stultz  *  To build:
127290ce14SJohn Stultz  *	$ gcc clocksource-switch.c -o clocksource-switch -lrt
137290ce14SJohn Stultz  *
147290ce14SJohn Stultz  *   This program is free software: you can redistribute it and/or modify
157290ce14SJohn Stultz  *   it under the terms of the GNU General Public License as published by
167290ce14SJohn Stultz  *   the Free Software Foundation, either version 2 of the License, or
177290ce14SJohn Stultz  *   (at your option) any later version.
187290ce14SJohn Stultz  *
197290ce14SJohn Stultz  *   This program is distributed in the hope that it will be useful,
207290ce14SJohn Stultz  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
217290ce14SJohn Stultz  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
227290ce14SJohn Stultz  *   GNU General Public License for more details.
237290ce14SJohn Stultz  */
247290ce14SJohn Stultz 
257290ce14SJohn Stultz 
265be1fd96SWolfram Sang #include <fcntl.h>
277290ce14SJohn Stultz #include <stdio.h>
287290ce14SJohn Stultz #include <stdlib.h>
295be1fd96SWolfram Sang #include <string.h>
305be1fd96SWolfram Sang #include <sys/stat.h>
317290ce14SJohn Stultz #include <sys/time.h>
327290ce14SJohn Stultz #include <sys/timex.h>
337290ce14SJohn Stultz #include <sys/types.h>
347290ce14SJohn Stultz #include <sys/wait.h>
355be1fd96SWolfram Sang #include <time.h>
365be1fd96SWolfram Sang #include <unistd.h>
377290ce14SJohn Stultz #include "../kselftest.h"
387290ce14SJohn Stultz 
397290ce14SJohn Stultz 
get_clocksources(char list[][30])407290ce14SJohn Stultz int get_clocksources(char list[][30])
417290ce14SJohn Stultz {
427290ce14SJohn Stultz 	int fd, i;
437290ce14SJohn Stultz 	size_t size;
447290ce14SJohn Stultz 	char buf[512];
457290ce14SJohn Stultz 	char *head, *tmp;
467290ce14SJohn Stultz 
477290ce14SJohn Stultz 	fd = open("/sys/devices/system/clocksource/clocksource0/available_clocksource", O_RDONLY);
487290ce14SJohn Stultz 
497290ce14SJohn Stultz 	size = read(fd, buf, 512);
507290ce14SJohn Stultz 
517290ce14SJohn Stultz 	close(fd);
527290ce14SJohn Stultz 
538f14e26bSBenjamin Gaignard 	for (i = 0; i < 10; i++)
547290ce14SJohn Stultz 		list[i][0] = '\0';
557290ce14SJohn Stultz 
567290ce14SJohn Stultz 	head = buf;
577290ce14SJohn Stultz 	i = 0;
587290ce14SJohn Stultz 	while (head - buf < size) {
597290ce14SJohn Stultz 		/* Find the next space */
607290ce14SJohn Stultz 		for (tmp = head; *tmp != ' '; tmp++) {
617290ce14SJohn Stultz 			if (*tmp == '\n')
627290ce14SJohn Stultz 				break;
637290ce14SJohn Stultz 			if (*tmp == '\0')
647290ce14SJohn Stultz 				break;
657290ce14SJohn Stultz 		}
667290ce14SJohn Stultz 		*tmp = '\0';
677290ce14SJohn Stultz 		strcpy(list[i], head);
687290ce14SJohn Stultz 		head = tmp + 1;
697290ce14SJohn Stultz 		i++;
707290ce14SJohn Stultz 	}
717290ce14SJohn Stultz 
727290ce14SJohn Stultz 	return i-1;
737290ce14SJohn Stultz }
747290ce14SJohn Stultz 
get_cur_clocksource(char * buf,size_t size)757290ce14SJohn Stultz int get_cur_clocksource(char *buf, size_t size)
767290ce14SJohn Stultz {
777290ce14SJohn Stultz 	int fd;
787290ce14SJohn Stultz 
797290ce14SJohn Stultz 	fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_RDONLY);
807290ce14SJohn Stultz 
817290ce14SJohn Stultz 	size = read(fd, buf, size);
827290ce14SJohn Stultz 
837290ce14SJohn Stultz 	return 0;
847290ce14SJohn Stultz }
857290ce14SJohn Stultz 
change_clocksource(char * clocksource)867290ce14SJohn Stultz int change_clocksource(char *clocksource)
877290ce14SJohn Stultz {
887290ce14SJohn Stultz 	int fd;
893b44edaaSAndrzej Hajda 	ssize_t size;
907290ce14SJohn Stultz 
917290ce14SJohn Stultz 	fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_WRONLY);
927290ce14SJohn Stultz 
937290ce14SJohn Stultz 	if (fd < 0)
947290ce14SJohn Stultz 		return -1;
957290ce14SJohn Stultz 
967290ce14SJohn Stultz 	size = write(fd, clocksource, strlen(clocksource));
977290ce14SJohn Stultz 
987290ce14SJohn Stultz 	if (size < 0)
997290ce14SJohn Stultz 		return -1;
1007290ce14SJohn Stultz 
1017290ce14SJohn Stultz 	close(fd);
1027290ce14SJohn Stultz 	return 0;
1037290ce14SJohn Stultz }
1047290ce14SJohn Stultz 
1057290ce14SJohn Stultz 
run_tests(int secs)1067290ce14SJohn Stultz int run_tests(int secs)
1077290ce14SJohn Stultz {
1087290ce14SJohn Stultz 	int ret;
1097290ce14SJohn Stultz 	char buf[255];
1107290ce14SJohn Stultz 
1117290ce14SJohn Stultz 	sprintf(buf, "./inconsistency-check -t %i", secs);
1127290ce14SJohn Stultz 	ret = system(buf);
1134d8f52acSWolfram Sang 	if (WIFEXITED(ret) && WEXITSTATUS(ret))
1144d8f52acSWolfram Sang 		return WEXITSTATUS(ret);
1157290ce14SJohn Stultz 	ret = system("./nanosleep");
1164d8f52acSWolfram Sang 	return WIFEXITED(ret) ? WEXITSTATUS(ret) : 0;
1177290ce14SJohn Stultz }
1187290ce14SJohn Stultz 
1197290ce14SJohn Stultz 
1207290ce14SJohn Stultz char clocksource_list[10][30];
1217290ce14SJohn Stultz 
main(int argc,char ** argv)12219b6823aSWolfram Sang int main(int argc, char **argv)
1237290ce14SJohn Stultz {
1247290ce14SJohn Stultz 	char orig_clk[512];
12519b6823aSWolfram Sang 	int count, i, status, opt;
12619b6823aSWolfram Sang 	int do_sanity_check = 1;
127248ae6f4SWolfram Sang 	int runtime = 60;
1287290ce14SJohn Stultz 	pid_t pid;
1297290ce14SJohn Stultz 
13019b6823aSWolfram Sang 	/* Process arguments */
131248ae6f4SWolfram Sang 	while ((opt = getopt(argc, argv, "st:")) != -1) {
13219b6823aSWolfram Sang 		switch (opt) {
13319b6823aSWolfram Sang 		case 's':
13419b6823aSWolfram Sang 			do_sanity_check = 0;
13519b6823aSWolfram Sang 			break;
136248ae6f4SWolfram Sang 		case 't':
137248ae6f4SWolfram Sang 			runtime = atoi(optarg);
138248ae6f4SWolfram Sang 			break;
13919b6823aSWolfram Sang 		default:
140248ae6f4SWolfram Sang 			printf("Usage: %s [-s] [-t <secs>]\n", argv[0]);
14119b6823aSWolfram Sang 			printf("	-s: skip sanity checks\n");
142248ae6f4SWolfram Sang 			printf("	-t: Number of seconds to run\n");
14319b6823aSWolfram Sang 			exit(-1);
14419b6823aSWolfram Sang 		}
14519b6823aSWolfram Sang 	}
14619b6823aSWolfram Sang 
1477290ce14SJohn Stultz 	get_cur_clocksource(orig_clk, 512);
1487290ce14SJohn Stultz 
1497290ce14SJohn Stultz 	count = get_clocksources(clocksource_list);
1507290ce14SJohn Stultz 
1517290ce14SJohn Stultz 	if (change_clocksource(clocksource_list[0])) {
1527290ce14SJohn Stultz 		printf("Error: You probably need to run this as root\n");
1537290ce14SJohn Stultz 		return -1;
1547290ce14SJohn Stultz 	}
1557290ce14SJohn Stultz 
1564bf07f65SIngo Molnar 	/* Check everything is sane before we start switching asynchronously */
15719b6823aSWolfram Sang 	if (do_sanity_check) {
1587290ce14SJohn Stultz 		for (i = 0; i < count; i++) {
159*e75ae3dbSGeert Uytterhoeven 			ksft_print_msg("Validating clocksource %s\n",
16019b6823aSWolfram Sang 					clocksource_list[i]);
1617290ce14SJohn Stultz 			if (change_clocksource(clocksource_list[i])) {
1627290ce14SJohn Stultz 				status = -1;
1637290ce14SJohn Stultz 				goto out;
1647290ce14SJohn Stultz 			}
1657290ce14SJohn Stultz 			if (run_tests(5)) {
1667290ce14SJohn Stultz 				status = -1;
1677290ce14SJohn Stultz 				goto out;
1687290ce14SJohn Stultz 			}
1697290ce14SJohn Stultz 		}
17019b6823aSWolfram Sang 	}
1717290ce14SJohn Stultz 
172*e75ae3dbSGeert Uytterhoeven 	ksft_print_msg("Running Asynchronous Switching Tests...\n");
1737290ce14SJohn Stultz 	pid = fork();
1747290ce14SJohn Stultz 	if (!pid)
175248ae6f4SWolfram Sang 		return run_tests(runtime);
1767290ce14SJohn Stultz 
1777290ce14SJohn Stultz 	while (pid != waitpid(pid, &status, WNOHANG))
1787290ce14SJohn Stultz 		for (i = 0; i < count; i++)
1797290ce14SJohn Stultz 			if (change_clocksource(clocksource_list[i])) {
1807290ce14SJohn Stultz 				status = -1;
1817290ce14SJohn Stultz 				goto out;
1827290ce14SJohn Stultz 			}
1837290ce14SJohn Stultz out:
1847290ce14SJohn Stultz 	change_clocksource(orig_clk);
1857290ce14SJohn Stultz 
186ce7d1017SWolfram Sang 	/* Print at the end to not mix output with child process */
187ce7d1017SWolfram Sang 	ksft_print_header();
188ce7d1017SWolfram Sang 	ksft_set_plan(1);
189ce7d1017SWolfram Sang 	ksft_test_result(!status, "clocksource-switch\n");
190ce7d1017SWolfram Sang 	ksft_exit(!status);
1917290ce14SJohn Stultz }
192