1# Copyright (c) 2012 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 6import time 7 8from autotest_lib.client.common_lib import error 9from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 10 11 12class firmware_ECBootTime(FirmwareTest): 13 """ 14 Servo based EC boot time test. 15 """ 16 version = 1 17 18 def initialize(self, host, cmdline_args): 19 super(firmware_ECBootTime, self).initialize(host, cmdline_args) 20 # Don't bother if there is no Chrome EC. 21 if not self.check_ec_capability(): 22 raise error.TestNAError("Nothing needs to be tested on this device") 23 # Only run in normal mode 24 self.switcher.setup_mode('normal') 25 self.host = host 26 27 def check_boot_time(self): 28 """Check EC and AP boot times""" 29 # Initialize a list of two strings, one printed by the EC when the AP 30 # is taken out of reset, and another one printed when the EC observes 31 # the AP running. These strings are used as for console output anchors 32 # when calculating the AP boot time. 33 # 34 # This is very approximate, a better long term solution would be to 35 # have the EC print the same fixed strings for these two events on all 36 # platforms. http://crosbug.com/p/21628 has been opened to track this 37 # issue. 38 if self._x86: 39 boot_anchors = ["\[([0-9\.]+) PB", "\[([0-9\.]+) .*(HC 0x|Port 80|ACPI query)"] 40 elif self._arm_legacy: 41 boot_anchors = ["\[([0-9\.]+) AP running ...", 42 "\[([0-9\.]+) XPSHOLD seen"] 43 else: 44 boot_anchors = ["\[([0-9\.]+) power state 1 = S5", 45 "\[([0-9\.]+) power state 3 = S0"] 46 47 # regular expression to say that EC is ready. For systems that 48 # run out of ram there is a second boot where the PMIC is 49 # asked to power cycle the EC to be 100% sure (I wish) that 50 # the code is clean. Looking for the "Inits done" generates a 51 # match after the first boot, and introduces a race between 52 # the EC booting the second time and the test sending the 53 # power_cmd. 54 if self._doubleboot: 55 ec_ready = ["(?ms)UART.*UART.*?\[([0-9.]+) "] 56 else: 57 ec_ready = ["([0-9.]+) Inits done"] 58 59 power_cmd = "powerbtn" if self.faft_config.ec_has_powerbtn_cmd else \ 60 "power on" 61 # Try the EC reboot command several times in case the console 62 # output is not clean enough for the full string to be found. 63 retry = 10 64 while retry > 0: 65 retry = retry - 1 66 try: 67 reboot = self.ec.send_command_get_output( 68 "reboot ap-off", ec_ready) 69 break 70 except error.TestFail: 71 logging.info("Unable to parse EC console output, " 72 "%d more attempts", retry) 73 if retry == 0: 74 raise error.TestFail("Unable to reboot EC cleanly, " + 75 "Please try removing AC power") 76 logging.debug("reboot: %r", reboot) 77 78 # The EC console must be available 1 second after startup 79 time.sleep(1) 80 81 version = self.ec.get_version() 82 83 if not version: 84 raise error.TestFail("Unable to get EC console.") 85 86 # Switch on the AP 87 power_press = self.ec.send_command_get_output( 88 power_cmd, boot_anchors) 89 90 # TODO(crbug.com/847289): reboot_time only measures the time spent in 91 # EC's main function, which is not a good measure of "EC cold boot time" 92 reboot_time = float(reboot[0][1]) 93 power_press_time = float(power_press[0][1]) 94 firmware_resp_time = float(power_press[1][1]) 95 boot_time = firmware_resp_time - power_press_time 96 logging.info("EC cold boot time: %f s", reboot_time) 97 if reboot_time > 1.0: 98 raise error.TestFail("EC cold boot time longer than 1 second.") 99 logging.info("EC boot time: %f s", boot_time) 100 if boot_time > 1.0: 101 raise error.TestFail("Boot time longer than 1 second.") 102 103 def is_arm_legacy_board(self): 104 """Detect whether the board is a legacy ARM board. 105 106 This group of boards prints specific strings on the EC console when the 107 EC and AP come out of reset. 108 """ 109 110 arm_legacy = ('Snow', 'Spring', 'Pit', 'Pi', 'Big', 'Blaze', 'Kitty') 111 output = self.faft_client.system.get_platform_name() 112 return output in arm_legacy 113 114 def run_once(self): 115 """Execute the main body of the test. 116 """ 117 118 self._x86 = ('x86' in self.faft_config.ec_capability) 119 self._doubleboot = ('doubleboot' in self.faft_config.ec_capability) 120 self._arm_legacy = self.is_arm_legacy_board() 121 dev_mode = self.checkers.crossystem_checker({'devsw_boot': '1'}) 122 logging.info("Reboot and check EC cold boot time and host boot time.") 123 self.switcher.mode_aware_reboot('custom', self.check_boot_time) 124 125 def cleanup(self): 126 try: 127 # Restore the ec_uart_regexp to None 128 self.ec.set_uart_regexp('None') 129 130 # Reboot the EC and wait for the host to come up so it is ready for 131 # the next test. 132 self.ec.reboot() 133 self.host.wait_up(timeout=30) 134 except Exception as e: 135 logging.error("Caught exception: %s", str(e)) 136 super(firmware_ECBootTime, self).cleanup() 137