1# Copyright 2016 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import logging, re, time 6 7from autotest_lib.client.common_lib import error 8from autotest_lib.server import test 9from autotest_lib.server.cros.dark_resume_utils import DarkResumeUtils 10from autotest_lib.server.cros.faft.config.config import Config as FAFTConfig 11 12SUSPEND_DURATION = 15 13NUM_DARK_RESUMES = 10 14ERROR_FILE = '/sys/kernel/debug/dri/0/i915_crtc_errors' 15 16 17class power_DarkResumeDisplay(test.test): 18 """ Ensure we don't have display errors after dark resume """ 19 version = 1 20 dark_resume_utils = None 21 22 23 def initialize(self, host): 24 self.dark_resume_utils = DarkResumeUtils(host, 25 duration=SUSPEND_DURATION) 26 27 28 def verify_host_supports_test(self, host): 29 """Check if the test works on the given host 30 31 @param host: reference to the host object 32 """ 33 platform = host.run_output('mosys platform name') 34 logging.info('Checking platform %s for compatibility with display test', 35 platform) 36 37 client_attr = FAFTConfig(platform) 38 if client_attr.dark_resume_capable == False: 39 raise error.TestError('platform is not capable of dark resume') 40 41 cmd = host.run('test -r %s' % ERROR_FILE, ignore_status=True) 42 logging.info("node_exists=%s", str(cmd.exit_status)) 43 if cmd.exit_status != 0: 44 raise error.TestError('%s file not found.' % ERROR_FILE) 45 46 47 def get_crtc_error_count(self, host): 48 """Get the current crtc error count for the dut 49 50 @returns: A dict whose key is the crtc id, and whose value is a 51 dict of {pipe, errors} 52 """ 53 output = host.run_output('cat %s' % ERROR_FILE) 54 pattern = 'Crtc ([0-9]+) Pipe ([A-Za-z]+) errors:\t\t([0-9a-fA-F]{8})' 55 regex = re.compile(pattern) 56 counts = {} 57 for line in output.splitlines(): 58 match = regex.match(line) 59 if match == None: 60 raise error.TestError('Unexpected error file string: %s' % line) 61 62 counts[int(match.group(1))] = { 63 'pipe': match.group(2), 64 'errors': int(match.group(3), 16), 65 } 66 return counts 67 68 69 def run_once(self, host=None): 70 """Run the test. 71 72 Setup preferences so that a dark resume will happen shortly after 73 suspending the machine. 74 75 store the current crtc error count 76 suspend the machine 77 wait for dark resume 78 wake the machine 79 retrieve the current crtc error count after suspend 80 ensure the error counts did not increase while suspended 81 82 @param host: The machine to run the tests on 83 """ 84 self.verify_host_supports_test(host) 85 86 pre_err_count = self.get_crtc_error_count(host) 87 88 """The DUT will perform a dark resume every SUSPEND_DURATION seconds 89 while it is suspended. Suspend the device and wait for the amount 90 of time to have performed NUM_DARK_RESUMES, plus half the 91 SUSPEND_DURATION to ensure the last dark resume has a chance to 92 complete. 93 """ 94 wait_time = SUSPEND_DURATION * NUM_DARK_RESUMES + SUSPEND_DURATION / 2 95 logging.info('suspending host, and waiting %ds', wait_time) 96 with self.dark_resume_utils.suspend() as suspend_ctx: 97 time.sleep(wait_time) 98 99 dark_resume_count = self.dark_resume_utils.count_dark_resumes() 100 logging.info('dark resume count = %d', dark_resume_count) 101 if dark_resume_count == 0: 102 raise error.TestError('Device did not enter dark resume!') 103 104 logging.info('retrieving post-suspend error counts') 105 post_err_count = self.get_crtc_error_count(host) 106 for k in pre_err_count: 107 pre = pre_err_count[k]['errors'] 108 post = post_err_count[k]['errors'] 109 if pre != post: 110 raise error.TestError('Crtc %d Pipe %s err count changed %d/%d' 111 % (k, pre_err_count[k]['pipe'], pre, 112 post)) 113 logging.info('error counts for Crtc %d Pipe %s constant at %d', k, 114 pre_err_count[k]['pipe'], pre) 115 116 117 def cleanup(self, host): 118 self.dark_resume_utils.teardown() 119 120