xref: /aosp_15_r20/external/linux-kselftest/tools/testing/selftests/watchdog/watchdog-test.c (revision 053f45be4e351dfd5e965df293cd45b779f579ee)
1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0
2*053f45beSAndroid Build Coastguard Worker /*
3*053f45beSAndroid Build Coastguard Worker  * Watchdog Driver Test Program
4*053f45beSAndroid Build Coastguard Worker  */
5*053f45beSAndroid Build Coastguard Worker 
6*053f45beSAndroid Build Coastguard Worker #include <errno.h>
7*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
8*053f45beSAndroid Build Coastguard Worker #include <stdlib.h>
9*053f45beSAndroid Build Coastguard Worker #include <string.h>
10*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
11*053f45beSAndroid Build Coastguard Worker #include <fcntl.h>
12*053f45beSAndroid Build Coastguard Worker #include <signal.h>
13*053f45beSAndroid Build Coastguard Worker #include <getopt.h>
14*053f45beSAndroid Build Coastguard Worker #include <sys/ioctl.h>
15*053f45beSAndroid Build Coastguard Worker #include <linux/types.h>
16*053f45beSAndroid Build Coastguard Worker #include <linux/watchdog.h>
17*053f45beSAndroid Build Coastguard Worker 
18*053f45beSAndroid Build Coastguard Worker #define DEFAULT_PING_RATE	1
19*053f45beSAndroid Build Coastguard Worker 
20*053f45beSAndroid Build Coastguard Worker int fd;
21*053f45beSAndroid Build Coastguard Worker const char v = 'V';
22*053f45beSAndroid Build Coastguard Worker static const char sopts[] = "bdehp:t:Tn:NLf:i";
23*053f45beSAndroid Build Coastguard Worker static const struct option lopts[] = {
24*053f45beSAndroid Build Coastguard Worker 	{"bootstatus",          no_argument, NULL, 'b'},
25*053f45beSAndroid Build Coastguard Worker 	{"disable",             no_argument, NULL, 'd'},
26*053f45beSAndroid Build Coastguard Worker 	{"enable",              no_argument, NULL, 'e'},
27*053f45beSAndroid Build Coastguard Worker 	{"help",                no_argument, NULL, 'h'},
28*053f45beSAndroid Build Coastguard Worker 	{"pingrate",      required_argument, NULL, 'p'},
29*053f45beSAndroid Build Coastguard Worker 	{"timeout",       required_argument, NULL, 't'},
30*053f45beSAndroid Build Coastguard Worker 	{"gettimeout",          no_argument, NULL, 'T'},
31*053f45beSAndroid Build Coastguard Worker 	{"pretimeout",    required_argument, NULL, 'n'},
32*053f45beSAndroid Build Coastguard Worker 	{"getpretimeout",       no_argument, NULL, 'N'},
33*053f45beSAndroid Build Coastguard Worker 	{"gettimeleft",		no_argument, NULL, 'L'},
34*053f45beSAndroid Build Coastguard Worker 	{"file",          required_argument, NULL, 'f'},
35*053f45beSAndroid Build Coastguard Worker 	{"info",		no_argument, NULL, 'i'},
36*053f45beSAndroid Build Coastguard Worker 	{NULL,                  no_argument, NULL, 0x0}
37*053f45beSAndroid Build Coastguard Worker };
38*053f45beSAndroid Build Coastguard Worker 
39*053f45beSAndroid Build Coastguard Worker /*
40*053f45beSAndroid Build Coastguard Worker  * This function simply sends an IOCTL to the driver, which in turn ticks
41*053f45beSAndroid Build Coastguard Worker  * the PC Watchdog card to reset its internal timer so it doesn't trigger
42*053f45beSAndroid Build Coastguard Worker  * a computer reset.
43*053f45beSAndroid Build Coastguard Worker  */
keep_alive(void)44*053f45beSAndroid Build Coastguard Worker static void keep_alive(void)
45*053f45beSAndroid Build Coastguard Worker {
46*053f45beSAndroid Build Coastguard Worker 	int dummy;
47*053f45beSAndroid Build Coastguard Worker 	int ret;
48*053f45beSAndroid Build Coastguard Worker 
49*053f45beSAndroid Build Coastguard Worker 	ret = ioctl(fd, WDIOC_KEEPALIVE, &dummy);
50*053f45beSAndroid Build Coastguard Worker 	if (!ret)
51*053f45beSAndroid Build Coastguard Worker 		printf(".");
52*053f45beSAndroid Build Coastguard Worker }
53*053f45beSAndroid Build Coastguard Worker 
54*053f45beSAndroid Build Coastguard Worker /*
55*053f45beSAndroid Build Coastguard Worker  * The main program.  Run the program with "-d" to disable the card,
56*053f45beSAndroid Build Coastguard Worker  * or "-e" to enable the card.
57*053f45beSAndroid Build Coastguard Worker  */
58*053f45beSAndroid Build Coastguard Worker 
term(int sig)59*053f45beSAndroid Build Coastguard Worker static void term(int sig)
60*053f45beSAndroid Build Coastguard Worker {
61*053f45beSAndroid Build Coastguard Worker 	int ret = write(fd, &v, 1);
62*053f45beSAndroid Build Coastguard Worker 
63*053f45beSAndroid Build Coastguard Worker 	close(fd);
64*053f45beSAndroid Build Coastguard Worker 	if (ret < 0)
65*053f45beSAndroid Build Coastguard Worker 		printf("\nStopping watchdog ticks failed (%d)...\n", errno);
66*053f45beSAndroid Build Coastguard Worker 	else
67*053f45beSAndroid Build Coastguard Worker 		printf("\nStopping watchdog ticks...\n");
68*053f45beSAndroid Build Coastguard Worker 	exit(0);
69*053f45beSAndroid Build Coastguard Worker }
70*053f45beSAndroid Build Coastguard Worker 
usage(char * progname)71*053f45beSAndroid Build Coastguard Worker static void usage(char *progname)
72*053f45beSAndroid Build Coastguard Worker {
73*053f45beSAndroid Build Coastguard Worker 	printf("Usage: %s [options]\n", progname);
74*053f45beSAndroid Build Coastguard Worker 	printf(" -f, --file\t\tOpen watchdog device file\n");
75*053f45beSAndroid Build Coastguard Worker 	printf("\t\t\tDefault is /dev/watchdog\n");
76*053f45beSAndroid Build Coastguard Worker 	printf(" -i, --info\t\tShow watchdog_info\n");
77*053f45beSAndroid Build Coastguard Worker 	printf(" -b, --bootstatus\tGet last boot status (Watchdog/POR)\n");
78*053f45beSAndroid Build Coastguard Worker 	printf(" -d, --disable\t\tTurn off the watchdog timer\n");
79*053f45beSAndroid Build Coastguard Worker 	printf(" -e, --enable\t\tTurn on the watchdog timer\n");
80*053f45beSAndroid Build Coastguard Worker 	printf(" -h, --help\t\tPrint the help message\n");
81*053f45beSAndroid Build Coastguard Worker 	printf(" -p, --pingrate=P\tSet ping rate to P seconds (default %d)\n",
82*053f45beSAndroid Build Coastguard Worker 	       DEFAULT_PING_RATE);
83*053f45beSAndroid Build Coastguard Worker 	printf(" -t, --timeout=T\tSet timeout to T seconds\n");
84*053f45beSAndroid Build Coastguard Worker 	printf(" -T, --gettimeout\tGet the timeout\n");
85*053f45beSAndroid Build Coastguard Worker 	printf(" -n, --pretimeout=T\tSet the pretimeout to T seconds\n");
86*053f45beSAndroid Build Coastguard Worker 	printf(" -N, --getpretimeout\tGet the pretimeout\n");
87*053f45beSAndroid Build Coastguard Worker 	printf(" -L, --gettimeleft\tGet the time left until timer expires\n");
88*053f45beSAndroid Build Coastguard Worker 	printf("\n");
89*053f45beSAndroid Build Coastguard Worker 	printf("Parameters are parsed left-to-right in real-time.\n");
90*053f45beSAndroid Build Coastguard Worker 	printf("Example: %s -d -t 10 -p 5 -e\n", progname);
91*053f45beSAndroid Build Coastguard Worker 	printf("Example: %s -t 12 -T -n 7 -N\n", progname);
92*053f45beSAndroid Build Coastguard Worker }
93*053f45beSAndroid Build Coastguard Worker 
main(int argc,char * argv[])94*053f45beSAndroid Build Coastguard Worker int main(int argc, char *argv[])
95*053f45beSAndroid Build Coastguard Worker {
96*053f45beSAndroid Build Coastguard Worker 	int flags;
97*053f45beSAndroid Build Coastguard Worker 	unsigned int ping_rate = DEFAULT_PING_RATE;
98*053f45beSAndroid Build Coastguard Worker 	int ret;
99*053f45beSAndroid Build Coastguard Worker 	int c;
100*053f45beSAndroid Build Coastguard Worker 	int oneshot = 0;
101*053f45beSAndroid Build Coastguard Worker 	char *file = "/dev/watchdog";
102*053f45beSAndroid Build Coastguard Worker 	struct watchdog_info info;
103*053f45beSAndroid Build Coastguard Worker 
104*053f45beSAndroid Build Coastguard Worker 	setbuf(stdout, NULL);
105*053f45beSAndroid Build Coastguard Worker 
106*053f45beSAndroid Build Coastguard Worker 	while ((c = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
107*053f45beSAndroid Build Coastguard Worker 		if (c == 'f')
108*053f45beSAndroid Build Coastguard Worker 			file = optarg;
109*053f45beSAndroid Build Coastguard Worker 	}
110*053f45beSAndroid Build Coastguard Worker 
111*053f45beSAndroid Build Coastguard Worker 	fd = open(file, O_WRONLY);
112*053f45beSAndroid Build Coastguard Worker 
113*053f45beSAndroid Build Coastguard Worker 	if (fd == -1) {
114*053f45beSAndroid Build Coastguard Worker 		if (errno == ENOENT)
115*053f45beSAndroid Build Coastguard Worker 			printf("Watchdog device (%s) not found.\n", file);
116*053f45beSAndroid Build Coastguard Worker 		else if (errno == EACCES)
117*053f45beSAndroid Build Coastguard Worker 			printf("Run watchdog as root.\n");
118*053f45beSAndroid Build Coastguard Worker 		else
119*053f45beSAndroid Build Coastguard Worker 			printf("Watchdog device open failed %s\n",
120*053f45beSAndroid Build Coastguard Worker 				strerror(errno));
121*053f45beSAndroid Build Coastguard Worker 		exit(-1);
122*053f45beSAndroid Build Coastguard Worker 	}
123*053f45beSAndroid Build Coastguard Worker 
124*053f45beSAndroid Build Coastguard Worker 	/*
125*053f45beSAndroid Build Coastguard Worker 	 * Validate that `file` is a watchdog device
126*053f45beSAndroid Build Coastguard Worker 	 */
127*053f45beSAndroid Build Coastguard Worker 	ret = ioctl(fd, WDIOC_GETSUPPORT, &info);
128*053f45beSAndroid Build Coastguard Worker 	if (ret) {
129*053f45beSAndroid Build Coastguard Worker 		printf("WDIOC_GETSUPPORT error '%s'\n", strerror(errno));
130*053f45beSAndroid Build Coastguard Worker 		close(fd);
131*053f45beSAndroid Build Coastguard Worker 		exit(ret);
132*053f45beSAndroid Build Coastguard Worker 	}
133*053f45beSAndroid Build Coastguard Worker 
134*053f45beSAndroid Build Coastguard Worker 	optind = 0;
135*053f45beSAndroid Build Coastguard Worker 
136*053f45beSAndroid Build Coastguard Worker 	while ((c = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
137*053f45beSAndroid Build Coastguard Worker 		switch (c) {
138*053f45beSAndroid Build Coastguard Worker 		case 'b':
139*053f45beSAndroid Build Coastguard Worker 			flags = 0;
140*053f45beSAndroid Build Coastguard Worker 			oneshot = 1;
141*053f45beSAndroid Build Coastguard Worker 			ret = ioctl(fd, WDIOC_GETBOOTSTATUS, &flags);
142*053f45beSAndroid Build Coastguard Worker 			if (!ret)
143*053f45beSAndroid Build Coastguard Worker 				printf("Last boot is caused by: %s.\n", (flags != 0) ?
144*053f45beSAndroid Build Coastguard Worker 					"Watchdog" : "Power-On-Reset");
145*053f45beSAndroid Build Coastguard Worker 			else
146*053f45beSAndroid Build Coastguard Worker 				printf("WDIOC_GETBOOTSTATUS error '%s'\n", strerror(errno));
147*053f45beSAndroid Build Coastguard Worker 			break;
148*053f45beSAndroid Build Coastguard Worker 		case 'd':
149*053f45beSAndroid Build Coastguard Worker 			flags = WDIOS_DISABLECARD;
150*053f45beSAndroid Build Coastguard Worker 			ret = ioctl(fd, WDIOC_SETOPTIONS, &flags);
151*053f45beSAndroid Build Coastguard Worker 			if (!ret)
152*053f45beSAndroid Build Coastguard Worker 				printf("Watchdog card disabled.\n");
153*053f45beSAndroid Build Coastguard Worker 			else {
154*053f45beSAndroid Build Coastguard Worker 				printf("WDIOS_DISABLECARD error '%s'\n", strerror(errno));
155*053f45beSAndroid Build Coastguard Worker 				oneshot = 1;
156*053f45beSAndroid Build Coastguard Worker 			}
157*053f45beSAndroid Build Coastguard Worker 			break;
158*053f45beSAndroid Build Coastguard Worker 		case 'e':
159*053f45beSAndroid Build Coastguard Worker 			flags = WDIOS_ENABLECARD;
160*053f45beSAndroid Build Coastguard Worker 			ret = ioctl(fd, WDIOC_SETOPTIONS, &flags);
161*053f45beSAndroid Build Coastguard Worker 			if (!ret)
162*053f45beSAndroid Build Coastguard Worker 				printf("Watchdog card enabled.\n");
163*053f45beSAndroid Build Coastguard Worker 			else {
164*053f45beSAndroid Build Coastguard Worker 				printf("WDIOS_ENABLECARD error '%s'\n", strerror(errno));
165*053f45beSAndroid Build Coastguard Worker 				oneshot = 1;
166*053f45beSAndroid Build Coastguard Worker 			}
167*053f45beSAndroid Build Coastguard Worker 			break;
168*053f45beSAndroid Build Coastguard Worker 		case 'p':
169*053f45beSAndroid Build Coastguard Worker 			ping_rate = strtoul(optarg, NULL, 0);
170*053f45beSAndroid Build Coastguard Worker 			if (!ping_rate)
171*053f45beSAndroid Build Coastguard Worker 				ping_rate = DEFAULT_PING_RATE;
172*053f45beSAndroid Build Coastguard Worker 			printf("Watchdog ping rate set to %u seconds.\n", ping_rate);
173*053f45beSAndroid Build Coastguard Worker 			break;
174*053f45beSAndroid Build Coastguard Worker 		case 't':
175*053f45beSAndroid Build Coastguard Worker 			flags = strtoul(optarg, NULL, 0);
176*053f45beSAndroid Build Coastguard Worker 			ret = ioctl(fd, WDIOC_SETTIMEOUT, &flags);
177*053f45beSAndroid Build Coastguard Worker 			if (!ret)
178*053f45beSAndroid Build Coastguard Worker 				printf("Watchdog timeout set to %u seconds.\n", flags);
179*053f45beSAndroid Build Coastguard Worker 			else {
180*053f45beSAndroid Build Coastguard Worker 				printf("WDIOC_SETTIMEOUT error '%s'\n", strerror(errno));
181*053f45beSAndroid Build Coastguard Worker 				oneshot = 1;
182*053f45beSAndroid Build Coastguard Worker 			}
183*053f45beSAndroid Build Coastguard Worker 			break;
184*053f45beSAndroid Build Coastguard Worker 		case 'T':
185*053f45beSAndroid Build Coastguard Worker 			oneshot = 1;
186*053f45beSAndroid Build Coastguard Worker 			ret = ioctl(fd, WDIOC_GETTIMEOUT, &flags);
187*053f45beSAndroid Build Coastguard Worker 			if (!ret)
188*053f45beSAndroid Build Coastguard Worker 				printf("WDIOC_GETTIMEOUT returns %u seconds.\n", flags);
189*053f45beSAndroid Build Coastguard Worker 			else
190*053f45beSAndroid Build Coastguard Worker 				printf("WDIOC_GETTIMEOUT error '%s'\n", strerror(errno));
191*053f45beSAndroid Build Coastguard Worker 			break;
192*053f45beSAndroid Build Coastguard Worker 		case 'n':
193*053f45beSAndroid Build Coastguard Worker 			flags = strtoul(optarg, NULL, 0);
194*053f45beSAndroid Build Coastguard Worker 			ret = ioctl(fd, WDIOC_SETPRETIMEOUT, &flags);
195*053f45beSAndroid Build Coastguard Worker 			if (!ret)
196*053f45beSAndroid Build Coastguard Worker 				printf("Watchdog pretimeout set to %u seconds.\n", flags);
197*053f45beSAndroid Build Coastguard Worker 			else {
198*053f45beSAndroid Build Coastguard Worker 				printf("WDIOC_SETPRETIMEOUT error '%s'\n", strerror(errno));
199*053f45beSAndroid Build Coastguard Worker 				oneshot = 1;
200*053f45beSAndroid Build Coastguard Worker 			}
201*053f45beSAndroid Build Coastguard Worker 			break;
202*053f45beSAndroid Build Coastguard Worker 		case 'N':
203*053f45beSAndroid Build Coastguard Worker 			oneshot = 1;
204*053f45beSAndroid Build Coastguard Worker 			ret = ioctl(fd, WDIOC_GETPRETIMEOUT, &flags);
205*053f45beSAndroid Build Coastguard Worker 			if (!ret)
206*053f45beSAndroid Build Coastguard Worker 				printf("WDIOC_GETPRETIMEOUT returns %u seconds.\n", flags);
207*053f45beSAndroid Build Coastguard Worker 			else
208*053f45beSAndroid Build Coastguard Worker 				printf("WDIOC_GETPRETIMEOUT error '%s'\n", strerror(errno));
209*053f45beSAndroid Build Coastguard Worker 			break;
210*053f45beSAndroid Build Coastguard Worker 		case 'L':
211*053f45beSAndroid Build Coastguard Worker 			oneshot = 1;
212*053f45beSAndroid Build Coastguard Worker 			ret = ioctl(fd, WDIOC_GETTIMELEFT, &flags);
213*053f45beSAndroid Build Coastguard Worker 			if (!ret)
214*053f45beSAndroid Build Coastguard Worker 				printf("WDIOC_GETTIMELEFT returns %u seconds.\n", flags);
215*053f45beSAndroid Build Coastguard Worker 			else
216*053f45beSAndroid Build Coastguard Worker 				printf("WDIOC_GETTIMELEFT error '%s'\n", strerror(errno));
217*053f45beSAndroid Build Coastguard Worker 			break;
218*053f45beSAndroid Build Coastguard Worker 		case 'f':
219*053f45beSAndroid Build Coastguard Worker 			/* Handled above */
220*053f45beSAndroid Build Coastguard Worker 			break;
221*053f45beSAndroid Build Coastguard Worker 		case 'i':
222*053f45beSAndroid Build Coastguard Worker 			/*
223*053f45beSAndroid Build Coastguard Worker 			 * watchdog_info was obtained as part of file open
224*053f45beSAndroid Build Coastguard Worker 			 * validation. So we just show it here.
225*053f45beSAndroid Build Coastguard Worker 			 */
226*053f45beSAndroid Build Coastguard Worker 			oneshot = 1;
227*053f45beSAndroid Build Coastguard Worker 			printf("watchdog_info:\n");
228*053f45beSAndroid Build Coastguard Worker 			printf(" identity:\t\t%s\n", info.identity);
229*053f45beSAndroid Build Coastguard Worker 			printf(" firmware_version:\t%u\n",
230*053f45beSAndroid Build Coastguard Worker 			       info.firmware_version);
231*053f45beSAndroid Build Coastguard Worker 			printf(" options:\t\t%08x\n", info.options);
232*053f45beSAndroid Build Coastguard Worker 			break;
233*053f45beSAndroid Build Coastguard Worker 
234*053f45beSAndroid Build Coastguard Worker 		default:
235*053f45beSAndroid Build Coastguard Worker 			usage(argv[0]);
236*053f45beSAndroid Build Coastguard Worker 			goto end;
237*053f45beSAndroid Build Coastguard Worker 		}
238*053f45beSAndroid Build Coastguard Worker 	}
239*053f45beSAndroid Build Coastguard Worker 
240*053f45beSAndroid Build Coastguard Worker 	if (oneshot)
241*053f45beSAndroid Build Coastguard Worker 		goto end;
242*053f45beSAndroid Build Coastguard Worker 
243*053f45beSAndroid Build Coastguard Worker 	printf("Watchdog Ticking Away!\n");
244*053f45beSAndroid Build Coastguard Worker 
245*053f45beSAndroid Build Coastguard Worker 	signal(SIGINT, term);
246*053f45beSAndroid Build Coastguard Worker 
247*053f45beSAndroid Build Coastguard Worker 	while (1) {
248*053f45beSAndroid Build Coastguard Worker 		keep_alive();
249*053f45beSAndroid Build Coastguard Worker 		sleep(ping_rate);
250*053f45beSAndroid Build Coastguard Worker 	}
251*053f45beSAndroid Build Coastguard Worker end:
252*053f45beSAndroid Build Coastguard Worker 	ret = write(fd, &v, 1);
253*053f45beSAndroid Build Coastguard Worker 	if (ret < 0)
254*053f45beSAndroid Build Coastguard Worker 		printf("Stopping watchdog ticks failed (%d)...\n", errno);
255*053f45beSAndroid Build Coastguard Worker 	close(fd);
256*053f45beSAndroid Build Coastguard Worker 	return 0;
257*053f45beSAndroid Build Coastguard Worker }
258