1 /*
2  * Copyright © 2013, 2015 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *    Paulo Zanoni <paulo.r.zanoni@intel.com>
25  *    David Weinehall <david.weinehall@intel.com>
26  *
27  */
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <limits.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <dirent.h>
37 
38 #include "drmtest.h"
39 #include "igt_pm.h"
40 #include "igt_aux.h"
41 
42 /**
43  * SECTION:igt_pm
44  * @short_description: Power Management related helpers
45  * @title: Power Management
46  * @include: igt.h
47  *
48  * This library provides various helpers to enable power management for,
49  * and in some cases subsequently allow restoring the old behaviour of,
50  * various external components that by default are set up in a way
51  * that interferes with the testing of our power management functionality.
52  */
53 
54 enum {
55 	POLICY_UNKNOWN = -1,
56 	POLICY_MAX_PERFORMANCE = 0,
57 	POLICY_MEDIUM_POWER = 1,
58 	POLICY_MIN_POWER = 2
59 };
60 
61 #define MAX_PERFORMANCE_STR	"max_performance\n"
62 #define MEDIUM_POWER_STR	"medium_power\n"
63 #define MIN_POWER_STR		"min_power\n"
64 /* Remember to fix this if adding longer strings */
65 #define MAX_POLICY_STRLEN	strlen(MAX_PERFORMANCE_STR)
66 
67 static char __igt_pm_audio_runtime_power_save[64];
68 static char * __igt_pm_audio_runtime_control_path;
69 static char __igt_pm_audio_runtime_control[64];
70 
__igt_pm_audio_restore_runtime_pm(void)71 static int __igt_pm_audio_restore_runtime_pm(void)
72 {
73 	int fd;
74 
75 	if (!__igt_pm_audio_runtime_power_save[0])
76 		return 0;
77 
78 	fd = open("/sys/module/snd_hda_intel/parameters/power_save", O_WRONLY);
79 	if (fd < 0)
80 		return errno;
81 
82 	if (write(fd, __igt_pm_audio_runtime_power_save,
83 		  strlen(__igt_pm_audio_runtime_power_save)) !=
84 	    strlen(__igt_pm_audio_runtime_power_save)) {
85 		close(fd);
86 		return errno;
87 	}
88 
89 	close(fd);
90 
91 	fd = open(__igt_pm_audio_runtime_control_path, O_WRONLY);
92 	if (fd < 0)
93 		return errno;
94 
95 	if (write(fd, __igt_pm_audio_runtime_control,
96 		  strlen(__igt_pm_audio_runtime_control)) !=
97 	    strlen(__igt_pm_audio_runtime_control)) {
98 		close(fd);
99 		return errno;
100 	}
101 
102 	close(fd);
103 
104 	memset(__igt_pm_audio_runtime_power_save, 0,
105 	       sizeof(__igt_pm_audio_runtime_power_save));
106 
107 	memset(__igt_pm_audio_runtime_control, 0,
108 	       sizeof(__igt_pm_audio_runtime_control));
109 
110 	free(__igt_pm_audio_runtime_control_path);
111 	__igt_pm_audio_runtime_control_path = NULL;
112 
113 	return 0;
114 }
115 
igt_pm_audio_restore_runtime_pm(void)116 static void igt_pm_audio_restore_runtime_pm(void)
117 {
118 	int ret;
119 
120 	if (!__igt_pm_audio_runtime_power_save[0])
121 		return;
122 
123 	igt_debug("Restoring audio power management to '%s' and '%s'\n",
124 		  __igt_pm_audio_runtime_power_save,
125 		  __igt_pm_audio_runtime_control);
126 
127 	ret = __igt_pm_audio_restore_runtime_pm();
128 	if (ret)
129 		igt_warn("Failed to restore runtime audio PM! (errno=%d)\n",
130 			 ret);
131 }
132 
__igt_pm_audio_runtime_exit_handler(int sig)133 static void __igt_pm_audio_runtime_exit_handler(int sig)
134 {
135 	__igt_pm_audio_restore_runtime_pm();
136 }
137 
strchomp(char * str)138 static void strchomp(char *str)
139 {
140 	int len = strlen(str);
141 
142 	if (len && str[len - 1] == '\n')
143 		str[len - 1] = 0;
144 }
145 
__igt_pm_enable_audio_runtime_pm(void)146 static int __igt_pm_enable_audio_runtime_pm(void)
147 {
148 	char *path = NULL;
149 	struct dirent *de;
150 	DIR *dir;
151 	int err;
152 	int fd;
153 
154 	dir = opendir("/sys/class/sound");
155 	if (!dir)
156 		return 0;
157 
158 	/* Find PCI device claimed by snd_hda_intel and tied to i915. */
159 	while ((de = readdir(dir))) {
160 		const char *match = "hwC";
161 		char buf[32] = { }; /* for Valgrind */
162 		int loops = 500;
163 		int base;
164 		int ret;
165 
166 		if (de->d_type != DT_LNK ||
167 		    strncmp(de->d_name, match, strlen(match)))
168 			continue;
169 
170 		base = openat(dirfd(dir), de->d_name, O_RDONLY);
171 		igt_assert_fd(base);
172 
173 		do {
174 			fd = openat(base, "vendor_name", O_RDONLY);
175 			if (fd < 0) /* module is still loading? */
176 				usleep(1000);
177 			else
178 				break;
179 		} while (--loops);
180 		close(base);
181 		if (fd < 0)
182 			continue;
183 
184 		ret = read(fd, buf, sizeof(buf) - 1);
185 		close(fd);
186 		igt_assert(ret > 0);
187 		buf[ret] = '\0';
188 		strchomp(buf);
189 
190 		/* Realtek and similar devices are not what we are after. */
191 		if (strcmp(buf, "Intel"))
192 			continue;
193 
194 		igt_assert(asprintf(&path,
195 				    "/sys/class/sound/%s/device/device/power/control",
196 				    de->d_name));
197 
198 		igt_debug("Audio device path is %s\n", path);
199 		break;
200 	}
201 	closedir(dir);
202 
203 	fd = open("/sys/module/snd_hda_intel/parameters/power_save", O_RDWR);
204 	if (fd < 0)
205 		return 0;
206 
207 	/* snd_hda_intel loaded but no path found is an error. */
208 	if (!path) {
209 		close(fd);
210 		err = -ESRCH;
211 		goto err;
212 	}
213 
214 	igt_assert(read(fd, __igt_pm_audio_runtime_power_save,
215 			sizeof(__igt_pm_audio_runtime_power_save) - 1) > 0);
216 	strchomp(__igt_pm_audio_runtime_power_save);
217 	igt_install_exit_handler(__igt_pm_audio_runtime_exit_handler);
218 	igt_assert_eq(write(fd, "1\n", 2), 2);
219 	close(fd);
220 
221 	fd = open(path, O_RDWR);
222 	if (fd < 0) {
223 		err = -errno;
224 		goto err;
225 	}
226 
227 	igt_assert(read(fd, __igt_pm_audio_runtime_control,
228 			sizeof(__igt_pm_audio_runtime_control) - 1) > 0);
229 	strchomp(__igt_pm_audio_runtime_control);
230 	igt_assert_eq(write(fd, "auto\n", 5), 5);
231 	close(fd);
232 
233 	__igt_pm_audio_runtime_control_path = path;
234 
235 	igt_debug("Saved audio power management as '%s' and '%s'\n",
236 		  __igt_pm_audio_runtime_power_save,
237 		  __igt_pm_audio_runtime_control);
238 
239 	/* Give some time for it to react. */
240 	sleep(1);
241 	return 0;
242 
243 err:
244 	free(path);
245 	return err;
246 }
247 
248 /**
249  * igt_pm_enable_audio_runtime_pm:
250  *
251  * We know that if we don't enable audio runtime PM, snd_hda_intel will never
252  * release its power well refcount, and we'll never reach the LPSP state.
253  * There's no guarantee that it will release the power well if we enable
254  * runtime PM, but at least we can try.
255  *
256  * We don't have any assertions on open since the user may not even have
257  * snd_hda_intel loaded, which is not a problem.
258  */
igt_pm_enable_audio_runtime_pm(void)259 void igt_pm_enable_audio_runtime_pm(void)
260 {
261 	int err;
262 
263 	/* Check if already enabled. */
264 	if (__igt_pm_audio_runtime_power_save[0])
265 		return;
266 
267 	for (int count = 0; count < 110; count++) {
268 		if (!__igt_pm_enable_audio_runtime_pm())
269 			return;
270 
271 		/* modprobe(sna-hda-intel) acts async so poll for sysfs */
272 		if (count < 100)
273 			usleep(10 * 1000); /* poll at 10ms for the first 1s */
274 		else
275 			sleep(1);
276 	}
277 
278 	err = __igt_pm_enable_audio_runtime_pm();
279 	if (err)
280 		igt_debug("Failed to enable audio runtime PM! (%d)\n", -err);
281 }
282 
283 /**
284  * igt_pm_enable_sata_link_power_management:
285  *
286  * Enable the min_power policy for SATA link power management.
287  * Without this we cannot reach deep runtime power states.
288  *
289  * We don't have any assertions on open since the system might not have
290  * a SATA host.
291  *
292  * Returns:
293  * An opaque pointer to the data needed to restore the default values
294  * after the test has terminated, or NULL if SATA link power management
295  * is not supported. This pointer should be freed when no longer used
296  * (typically after having called restore_sata_link_power_management()).
297  */
igt_pm_enable_sata_link_power_management(void)298 int8_t *igt_pm_enable_sata_link_power_management(void)
299 {
300 	int fd, i;
301 	ssize_t len;
302 	char *buf;
303 	char *file_name;
304 	int8_t *link_pm_policies = NULL;
305 
306 	file_name = malloc(PATH_MAX);
307 	buf = malloc(MAX_POLICY_STRLEN + 1);
308 
309 	for (i = 0; ; i++) {
310 		int8_t policy;
311 
312 		snprintf(file_name, PATH_MAX,
313 			 "/sys/class/scsi_host/host%d/link_power_management_policy",
314 			 i);
315 
316 		fd = open(file_name, O_RDWR);
317 		if (fd < 0)
318 			break;
319 
320 		len = read(fd, buf, MAX_POLICY_STRLEN);
321 		buf[len] = '\0';
322 
323 		if (!strncmp(MAX_PERFORMANCE_STR, buf,
324 			     strlen(MAX_PERFORMANCE_STR)))
325 			policy = POLICY_MAX_PERFORMANCE;
326 		else if (!strncmp(MEDIUM_POWER_STR, buf,
327 				  strlen(MEDIUM_POWER_STR)))
328 			policy = POLICY_MEDIUM_POWER;
329 		else if (!strncmp(MIN_POWER_STR, buf,
330 				  strlen(MIN_POWER_STR)))
331 			policy = POLICY_MIN_POWER;
332 		else
333 			policy = POLICY_UNKNOWN;
334 
335 		if (!(i % 256))
336 			link_pm_policies = realloc(link_pm_policies,
337 						   (i / 256 + 1) * 256 + 1);
338 
339 		link_pm_policies[i] = policy;
340 		link_pm_policies[i + 1] = 0;
341 
342 		/* If the policy is something we don't know about,
343 		 * don't touch it, since we might potentially break things.
344 		 * And we obviously don't need to touch anything if the
345 		 * setting is already correct...
346 		 */
347 		if (policy != POLICY_UNKNOWN &&
348 		    policy != POLICY_MIN_POWER) {
349 			lseek(fd, 0, SEEK_SET);
350 			igt_assert_eq(write(fd, MIN_POWER_STR,
351 					    strlen(MIN_POWER_STR)),
352 				      strlen(MIN_POWER_STR));
353 		}
354 		close(fd);
355 	}
356 	free(buf);
357 	free(file_name);
358 
359 	return link_pm_policies;
360 }
361 
362 /**
363  * igt_pm_restore_sata_link_power_management:
364  * @pm_data: An opaque pointer with saved link PM policies;
365  *           If NULL is passed we force enable the "max_performance" policy.
366  *
367  * Restore the link power management policies to the values
368  * prior to enabling min_power.
369  *
370  * Caveat: If the system supports hotplugging and hotplugging takes
371  *         place during our testing so that the hosts change numbers
372  *         we might restore the settings to the wrong hosts.
373  */
igt_pm_restore_sata_link_power_management(int8_t * pm_data)374 void igt_pm_restore_sata_link_power_management(int8_t *pm_data)
375 
376 {
377 	int fd, i;
378 	char *file_name;
379 
380 	/* Disk runtime PM policies. */
381 	file_name = malloc(PATH_MAX);
382 	for (i = 0; ; i++) {
383 		int8_t policy;
384 
385 		if (!pm_data)
386 			policy = POLICY_MAX_PERFORMANCE;
387 		else if (pm_data[i] == POLICY_UNKNOWN)
388 			continue;
389 		else
390 			policy = pm_data[i];
391 
392 		snprintf(file_name, PATH_MAX,
393 			 "/sys/class/scsi_host/host%d/link_power_management_policy",
394 			 i);
395 
396 		fd = open(file_name, O_WRONLY);
397 		if (fd < 0)
398 			break;
399 
400 		switch (policy) {
401 		default:
402 		case POLICY_MAX_PERFORMANCE:
403 			igt_assert_eq(write(fd, MAX_PERFORMANCE_STR,
404 					    strlen(MAX_PERFORMANCE_STR)),
405 				      strlen(MAX_PERFORMANCE_STR));
406 			break;
407 
408 		case POLICY_MEDIUM_POWER:
409 			igt_assert_eq(write(fd, MEDIUM_POWER_STR,
410 					    strlen(MEDIUM_POWER_STR)),
411 				      strlen(MEDIUM_POWER_STR));
412 			break;
413 
414 		case POLICY_MIN_POWER:
415 			igt_assert_eq(write(fd, MIN_POWER_STR,
416 					    strlen(MIN_POWER_STR)),
417 				      strlen(MIN_POWER_STR));
418 			break;
419 		}
420 
421 		close(fd);
422 	}
423 	free(file_name);
424 }
425 #define POWER_DIR "/sys/devices/pci0000:00/0000:00:02.0/power"
426 /* We just leak this on exit ... */
427 int pm_status_fd = -1;
428 
429 static char __igt_pm_runtime_autosuspend[64];
430 static char __igt_pm_runtime_control[64];
431 
__igt_restore_runtime_pm(void)432 static int __igt_restore_runtime_pm(void)
433 {
434 	int fd;
435 
436 	if (pm_status_fd < 0)
437 		return 0;
438 
439 	fd = open(POWER_DIR "/autosuspend_delay_ms", O_WRONLY);
440 	if (fd < 0)
441 		return errno;
442 
443 	if (write(fd, __igt_pm_runtime_autosuspend,
444 		  strlen(__igt_pm_runtime_autosuspend)) !=
445 	    strlen(__igt_pm_runtime_autosuspend)) {
446 		close(fd);
447 		return errno;
448 	}
449 
450 	close(fd);
451 
452 	fd = open(POWER_DIR "/control", O_WRONLY);
453 	if (fd < 0)
454 		return errno;
455 
456 	if (write(fd, __igt_pm_runtime_control,
457 		  strlen(__igt_pm_runtime_control)) !=
458 	    strlen(__igt_pm_runtime_control)) {
459 		close(fd);
460 		return errno;
461 	}
462 
463 	close(fd);
464 
465 	close(pm_status_fd);
466 	pm_status_fd = -1;
467 
468 	return 0;
469 }
470 
471 /**
472  * igt_restore_runtime_pm:
473  *
474  * Restores the runtime PM configuration as it was before the call to
475  * igt_setup_runtime_pm.
476  */
igt_restore_runtime_pm(void)477 void igt_restore_runtime_pm(void)
478 {
479 	int ret;
480 
481 	if (pm_status_fd < 0)
482 		return;
483 
484 	igt_debug("Restoring runtime PM management to '%s' and '%s'\n",
485 		  __igt_pm_runtime_autosuspend,
486 		  __igt_pm_runtime_control);
487 
488 	ret = __igt_restore_runtime_pm();
489 	if (ret)
490 		igt_warn("Failed to restore runtime PM! (errno=%d)\n", ret);
491 
492 	igt_pm_audio_restore_runtime_pm();
493 }
494 
__igt_pm_runtime_exit_handler(int sig)495 static void __igt_pm_runtime_exit_handler(int sig)
496 {
497 	__igt_restore_runtime_pm();
498 }
499 
500 /**
501  * igt_setup_runtime_pm:
502  *
503  * Sets up the runtime PM helper functions and enables runtime PM. To speed up
504  * tests the autosuspend delay is set to 0.
505  *
506  * Returns:
507  * True if runtime pm is available, false otherwise.
508  */
igt_setup_runtime_pm(void)509 bool igt_setup_runtime_pm(void)
510 {
511 	int fd;
512 	ssize_t size;
513 	char buf[6];
514 
515 	if (pm_status_fd >= 0)
516 		return true;
517 
518 	igt_pm_enable_audio_runtime_pm();
519 
520 	/*
521 	 * Our implementation uses autosuspend. Try to set it to 0ms so the
522 	 * test suite goes faster and we have a higher probability of
523 	 * triggering race conditions.
524 	 */
525 	fd = open(POWER_DIR "/autosuspend_delay_ms", O_RDWR);
526 	if (fd < 0) {
527 		igt_pm_audio_restore_runtime_pm();
528 		return false;
529 	}
530 
531 	/*
532 	 * Save previous values to be able to  install exit handler to restore
533 	 * them on test exit.
534 	 */
535 	size = read(fd, __igt_pm_runtime_autosuspend,
536 		    sizeof(__igt_pm_runtime_autosuspend) - 1);
537 
538 	/*
539 	 * If we fail to read from the file, it means this system doesn't
540 	 * support runtime PM.
541 	 */
542 	if (size <= 0) {
543 		close(fd);
544 		igt_pm_audio_restore_runtime_pm();
545 		return false;
546 	}
547 
548 	__igt_pm_runtime_autosuspend[size] = '\0';
549 
550 	strchomp(__igt_pm_runtime_autosuspend);
551 	igt_install_exit_handler(__igt_pm_runtime_exit_handler);
552 
553 	size = write(fd, "0\n", 2);
554 
555 	close(fd);
556 
557 	if (size != 2)
558 		return false;
559 
560 	/* We know we support runtime PM, let's try to enable it now. */
561 	fd = open(POWER_DIR "/control", O_RDWR);
562 	igt_assert_f(fd >= 0, "Can't open " POWER_DIR "/control\n");
563 
564 	igt_assert(read(fd, __igt_pm_runtime_control,
565 			sizeof(__igt_pm_runtime_control) - 1) > 0);
566 	strchomp(__igt_pm_runtime_control);
567 
568 	igt_debug("Saved runtime power management as '%s' and '%s'\n",
569 		  __igt_pm_runtime_autosuspend, __igt_pm_runtime_control);
570 
571 	size = write(fd, "auto\n", 5);
572 	igt_assert(size == 5);
573 
574 	lseek(fd, 0, SEEK_SET);
575 	size = read(fd, buf, ARRAY_SIZE(buf));
576 	igt_assert(size == 5);
577 	igt_assert(strncmp(buf, "auto\n", 5) == 0);
578 
579 	close(fd);
580 
581 	pm_status_fd = open(POWER_DIR "/runtime_status", O_RDONLY);
582 	igt_assert_f(pm_status_fd >= 0,
583 		     "Can't open " POWER_DIR "/runtime_status\n");
584 
585 	return true;
586 }
587 
588 /**
589  * igt_get_runtime_pm_status:
590  *
591  * Returns: The current runtime PM status.
592  */
igt_get_runtime_pm_status(void)593 enum igt_runtime_pm_status igt_get_runtime_pm_status(void)
594 {
595 	ssize_t n_read;
596 	char buf[32];
597 
598 	lseek(pm_status_fd, 0, SEEK_SET);
599 	n_read = read(pm_status_fd, buf, ARRAY_SIZE(buf) - 1);
600 	igt_assert(n_read >= 0);
601 	buf[n_read] = '\0';
602 
603 	if (strncmp(buf, "suspended\n", n_read) == 0)
604 		return IGT_RUNTIME_PM_STATUS_SUSPENDED;
605 	else if (strncmp(buf, "active\n", n_read) == 0)
606 		return IGT_RUNTIME_PM_STATUS_ACTIVE;
607 	else if (strncmp(buf, "suspending\n", n_read) == 0)
608 		return IGT_RUNTIME_PM_STATUS_SUSPENDING;
609 	else if (strncmp(buf, "resuming\n", n_read) == 0)
610 		return IGT_RUNTIME_PM_STATUS_RESUMING;
611 
612 	igt_assert_f(false, "Unknown status %s\n", buf);
613 	return IGT_RUNTIME_PM_STATUS_UNKNOWN;
614 }
615 
616 /**
617  * igt_wait_for_pm_status:
618  * @status: desired runtime PM status
619  *
620  * Waits until for the driver to switch to into the desired runtime PM status,
621  * with a 10 second timeout.
622  *
623  * Returns:
624  * True if the desired runtime PM status was attained, false if the operation
625  * timed out.
626  */
igt_wait_for_pm_status(enum igt_runtime_pm_status status)627 bool igt_wait_for_pm_status(enum igt_runtime_pm_status status)
628 {
629 	return igt_wait(igt_get_runtime_pm_status() == status, 10000, 100);
630 }
631