| # Copyright 2016 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import logging, re, time |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.server import test |
| from autotest_lib.server.cros.dark_resume_utils import DarkResumeUtils |
| from autotest_lib.server.cros.faft.config.config import Config as FAFTConfig |
| |
| SUSPEND_DURATION = 15 |
| NUM_DARK_RESUMES = 10 |
| ERROR_FILE = '/sys/kernel/debug/dri/0/i915_crtc_errors' |
| |
| |
| class power_DarkResumeDisplay(test.test): |
| """ Ensure we don't have display errors after dark resume """ |
| version = 1 |
| dark_resume_utils = None |
| |
| |
| def initialize(self, host): |
| self.dark_resume_utils = DarkResumeUtils(host, |
| duration=SUSPEND_DURATION) |
| |
| |
| def verify_host_supports_test(self, host): |
| """Check if the test works on the given host |
| |
| @param host: reference to the host object |
| """ |
| platform = host.run_output('mosys platform name') |
| logging.info('Checking platform %s for compatibility with display test', |
| platform) |
| |
| # TODO(seanpaul) Look at backporting i915_crtc_errors accounting to |
| # other kernels. |
| kernel_ver = host.run('uname -r').stdout.rstrip() |
| logging.info('kernel version is %s', kernel_ver) |
| if not kernel_ver.startswith('3.14') and \ |
| not kernel_ver.startswith('3.18'): |
| raise error.TestNAError('Test support on 3.14 | 3.18 kernels only') |
| |
| client_attr = FAFTConfig(platform) |
| if client_attr.dark_resume_capable == False: |
| raise error.TestNAError('platform is not capable of dark resume') |
| |
| cmd = host.run('test -r %s' % ERROR_FILE, ignore_status=True) |
| logging.info("node_exists=%s", str(cmd.exit_status)) |
| if cmd.exit_status != 0: |
| raise error.TestError('%s file not found.' % ERROR_FILE) |
| |
| |
| def get_crtc_error_count(self, host): |
| """Get the current crtc error count for the dut |
| |
| @returns: A dict whose key is the crtc id, and whose value is a |
| dict of {pipe, errors} |
| """ |
| output = host.run_output('cat %s' % ERROR_FILE) |
| pattern = 'Crtc ([0-9]+) Pipe ([A-Za-z]+) errors:\t\t([0-9a-fA-F]{8})' |
| regex = re.compile(pattern) |
| counts = {} |
| for line in output.splitlines(): |
| match = regex.match(line) |
| if match == None: |
| raise error.TestError('Unexpected error file string: %s' % line) |
| |
| counts[int(match.group(1))] = { |
| 'pipe': match.group(2), |
| 'errors': int(match.group(3), 16), |
| } |
| return counts |
| |
| |
| def run_once(self, host=None): |
| """Run the test. |
| |
| Setup preferences so that a dark resume will happen shortly after |
| suspending the machine. |
| |
| store the current crtc error count |
| suspend the machine |
| wait for dark resume |
| wake the machine |
| retrieve the current crtc error count after suspend |
| ensure the error counts did not increase while suspended |
| |
| @param host: The machine to run the tests on |
| """ |
| self.verify_host_supports_test(host) |
| |
| pre_err_count = self.get_crtc_error_count(host) |
| |
| # The DUT will perform a dark resume every SUSPEND_DURATION seconds |
| # while it is suspended. Suspend the device and wait for the amount |
| # of time to have performed NUM_DARK_RESUMES, plus half the |
| # SUSPEND_DURATION to ensure the last dark resume has a chance to |
| # complete. |
| wait_time = SUSPEND_DURATION * NUM_DARK_RESUMES + SUSPEND_DURATION / 2 |
| logging.info('suspending host, and waiting %ds', wait_time) |
| with self.dark_resume_utils.suspend() as _: |
| time.sleep(wait_time) |
| |
| dark_resume_count = self.dark_resume_utils.count_dark_resumes() |
| logging.info('dark resume count = %d', dark_resume_count) |
| if dark_resume_count == 0: |
| raise error.TestError('Device did not enter dark resume!') |
| |
| logging.info('retrieving post-suspend error counts') |
| post_err_count = self.get_crtc_error_count(host) |
| for k in pre_err_count: |
| pre = pre_err_count[k]['errors'] |
| post = post_err_count[k]['errors'] |
| if pre != post: |
| raise error.TestError('Crtc %d Pipe %s err count changed %d/%d' |
| % (k, pre_err_count[k]['pipe'], pre, |
| post)) |
| logging.info('error counts for Crtc %d Pipe %s constant at %d', k, |
| pre_err_count[k]['pipe'], pre) |
| |
| |
| def cleanup(self, _): |
| self.dark_resume_utils.teardown() |
| |