Home | History | Annotate | Download | only in power_DarkResumeDisplay
      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 
      5 import logging, re, time
      6 
      7 from autotest_lib.client.common_lib import error
      8 from autotest_lib.server import test
      9 from autotest_lib.server.cros.dark_resume_utils import DarkResumeUtils
     10 from autotest_lib.server.cros.faft.config.config import Config as FAFTConfig
     11 
     12 SUSPEND_DURATION = 15
     13 NUM_DARK_RESUMES = 10
     14 ERROR_FILE = '/sys/kernel/debug/dri/0/i915_crtc_errors'
     15 
     16 
     17 class 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         # TODO(seanpaul) Look at backporting i915_crtc_errors accounting to
     38         # other kernels.
     39         kernel_ver = host.run('uname -r').stdout.rstrip()
     40         logging.info('kernel version is %s', kernel_ver)
     41         if not kernel_ver.startswith('3.14') and \
     42            not kernel_ver.startswith('3.18'):
     43             raise error.TestNAError('Test support on 3.14 | 3.18 kernels only')
     44 
     45         client_attr = FAFTConfig(platform)
     46         if client_attr.dark_resume_capable == False:
     47             raise error.TestNAError('platform is not capable of dark resume')
     48 
     49         cmd = host.run('test -r %s' % ERROR_FILE, ignore_status=True)
     50         logging.info("node_exists=%s", str(cmd.exit_status))
     51         if cmd.exit_status != 0:
     52             raise error.TestError('%s file not found.' % ERROR_FILE)
     53 
     54 
     55     def get_crtc_error_count(self, host):
     56         """Get the current crtc error count for the dut
     57 
     58         @returns: A dict whose key is the crtc id, and whose value is a
     59                   dict of {pipe, errors}
     60         """
     61         output = host.run_output('cat %s' % ERROR_FILE)
     62         pattern = 'Crtc ([0-9]+) Pipe ([A-Za-z]+) errors:\t\t([0-9a-fA-F]{8})'
     63         regex = re.compile(pattern)
     64         counts = {}
     65         for line in output.splitlines():
     66             match = regex.match(line)
     67             if match == None:
     68                 raise error.TestError('Unexpected error file string: %s' % line)
     69 
     70             counts[int(match.group(1))] = {
     71                 'pipe': match.group(2),
     72                 'errors': int(match.group(3), 16),
     73             }
     74         return counts
     75 
     76 
     77     def run_once(self, host=None):
     78         """Run the test.
     79 
     80            Setup preferences so that a dark resume will happen shortly after
     81            suspending the machine.
     82 
     83            store the current crtc error count
     84            suspend the machine
     85            wait for dark resume
     86            wake the machine
     87            retrieve the current crtc error count after suspend
     88            ensure the error counts did not increase while suspended
     89 
     90         @param host: The machine to run the tests on
     91         """
     92         self.verify_host_supports_test(host)
     93 
     94         pre_err_count = self.get_crtc_error_count(host)
     95 
     96         # The DUT will perform a dark resume every SUSPEND_DURATION seconds
     97         # while it is suspended. Suspend the device and wait for the amount
     98         # of time to have performed NUM_DARK_RESUMES, plus half the
     99         # SUSPEND_DURATION to ensure the last dark resume has a chance to
    100         # complete.
    101         wait_time = SUSPEND_DURATION * NUM_DARK_RESUMES + SUSPEND_DURATION / 2
    102         logging.info('suspending host, and waiting %ds', wait_time)
    103         with self.dark_resume_utils.suspend() as _:
    104             time.sleep(wait_time)
    105 
    106         dark_resume_count = self.dark_resume_utils.count_dark_resumes()
    107         logging.info('dark resume count = %d', dark_resume_count)
    108         if dark_resume_count == 0:
    109             raise error.TestError('Device did not enter dark resume!')
    110 
    111         logging.info('retrieving post-suspend error counts')
    112         post_err_count = self.get_crtc_error_count(host)
    113         for k in pre_err_count:
    114             pre = pre_err_count[k]['errors']
    115             post = post_err_count[k]['errors']
    116             if pre != post:
    117                 raise error.TestError('Crtc %d Pipe %s err count changed %d/%d'
    118                                       % (k, pre_err_count[k]['pipe'], pre,
    119                                          post))
    120             logging.info('error counts for Crtc %d Pipe %s constant at %d', k,
    121                          pre_err_count[k]['pipe'], pre)
    122 
    123 
    124     def cleanup(self, _):
    125         self.dark_resume_utils.teardown()
    126 
    127