xref: /kvm-unit-tests/powerpc/rtas.c (revision a299895b7abb54e7ba6bb4108f202acbb484ac65)
1 /*
2  * Test the RTAS interface
3  */
4 
5 #include <libcflat.h>
6 #include <util.h>
7 #include <asm/rtas.h>
8 
9 #define DAYS(y,m,d) (365UL * (y) + ((y) / 4) - ((y) / 100) + ((y) / 400) + \
10 		     367UL * (m) / 12  + \
11 		     (d))
12 
mktime(int year,int month,int day,int hour,int minute,int second)13 static unsigned long mktime(int year, int month, int day,
14 			    int hour, int minute, int second)
15 {
16 	unsigned long epoch;
17 
18 	/* Put February at end of the year to avoid leap day this year */
19 
20 	month -= 2;
21 	if (month <= 0) {
22 		month += 12;
23 		year -= 1;
24 	}
25 
26 	/* compute epoch: substract DAYS(since_March(1-1-1970)) */
27 
28 	epoch = DAYS(year, month, day) - DAYS(1969, 11, 1);
29 
30 	epoch = epoch * 24 + hour;
31 	epoch = epoch * 60 + minute;
32 	epoch = epoch * 60 + second;
33 
34 	return epoch;
35 }
36 
37 #define DELAY 1
38 #define MAX_LOOP 10000000
39 
check_get_time_of_day(unsigned long start)40 static void check_get_time_of_day(unsigned long start)
41 {
42 	uint32_t token;
43 	int ret;
44 	int now[8];
45 	unsigned long t1, t2, count;
46 
47 	ret = rtas_token("get-time-of-day", &token);
48 	report(ret == 0, "token available");
49 	if (ret)
50 		return;
51 
52 	ret = rtas_call(token, 0, 8, now);
53 	report(ret == 0, "execution");
54 
55 	report(now[5] >= 0 && now[5] <= 59, "second");
56 	report(now[4] >= 0 && now[4] <= 59, "minute");
57 	report(now[3] >= 0 && now[3] <= 23, "hour");
58 	report(now[2] >= 1 && now[2] <= 31, "day");
59 	report(now[1] >= 1 && now[1] <= 12, "month");
60 	report(now[0] >= 1970, "year");
61 	report(mktime(now[0], now[1], now[2], now[3], now[4], now[5]) - start < 3,
62 	       "accuracy (< 3s)");
63 
64 	ret = rtas_call(token, 0, 8, now);
65 	t1 = mktime(now[0], now[1], now[2], now[3], now[4], now[5]);
66 	count = 0;
67 	do {
68 		ret = rtas_call(token, 0, 8, now);
69 		t2 = mktime(now[0], now[1], now[2], now[3], now[4], now[5]);
70 		count++;
71 	} while (t1 + DELAY > t2 && count < MAX_LOOP);
72 	report(t1 + DELAY <= t2, "running");
73 }
74 
check_set_time_of_day(void)75 static void check_set_time_of_day(void)
76 {
77 	uint32_t stod_token, gtod_token;
78 	int ret;
79 	int date[8];
80 	unsigned long t1, t2, count;
81 
82 	ret = rtas_token("set-time-of-day", &stod_token);
83 	report(ret == 0, "token available");
84 	if (ret)
85 		return;
86 
87 	/* 23:59:59 28/2/2000 */
88 
89 	ret = rtas_call(stod_token, 7, 1, NULL, 2000, 2, 28, 23, 59, 59);
90 	report(ret == 0, "execution");
91 
92 	/* check it has worked */
93 	ret = rtas_token("get-time-of-day", &gtod_token);
94 	assert(ret == 0);
95 	ret = rtas_call(gtod_token, 0, 8, date);
96 	report(ret == 0, "re-read");
97 	t1 = mktime(2000, 2, 28, 23, 59, 59);
98 	t2 = mktime(date[0], date[1], date[2],
99 		    date[3], date[4], date[5]);
100 	report(t2 - t1 < 2, "result");
101 
102 	/* check it is running */
103 	count = 0;
104 	do {
105 		ret = rtas_call(gtod_token, 0, 8, date);
106 		t2 = mktime(date[0], date[1], date[2],
107 			    date[3], date[4], date[5]);
108 		count++;
109 	} while (t1 + DELAY > t2 && count < MAX_LOOP);
110 	report(t1 + DELAY <= t2, "running");
111 }
112 
main(int argc,char ** argv)113 int main(int argc, char **argv)
114 {
115 	int len;
116 	long val;
117 
118 	report_prefix_push("rtas");
119 
120 	if (argc < 2)
121 		report_abort("no test specified");
122 
123 	report_prefix_push(argv[1]);
124 
125 	if (strcmp(argv[1], "get-time-of-day") == 0) {
126 
127 		len = parse_keyval(argv[2], &val);
128 		if (len == -1) {
129 			printf("Missing parameter \"date\"\n");
130 			abort();
131 		}
132 		argv[2][len] = '\0';
133 
134 		check_get_time_of_day(val);
135 
136 	} else if (strcmp(argv[1], "set-time-of-day") == 0) {
137 
138 		check_set_time_of_day();
139 
140 	} else {
141 		printf("Unknown subtest\n");
142 		abort();
143 	}
144 
145 	report_prefix_pop();
146 
147 	report_prefix_pop();
148 
149 	return report_summary();
150 }
151