154 lines
6.1 KiB
Python
154 lines
6.1 KiB
Python
# Copyright (c) 2012 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
|
|
import time
|
|
|
|
from autotest_lib.client.common_lib import error
|
|
from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
|
|
|
|
|
|
class firmware_ECBootTime(FirmwareTest):
|
|
"""
|
|
Servo based EC boot time test.
|
|
"""
|
|
version = 1
|
|
|
|
def initialize(self, host, cmdline_args):
|
|
super(firmware_ECBootTime, self).initialize(host, cmdline_args)
|
|
# Don't bother if there is no Chrome EC.
|
|
if not self.check_ec_capability():
|
|
raise error.TestNAError("Nothing needs to be tested on this device")
|
|
# Only run in normal mode
|
|
self.switcher.setup_mode('normal')
|
|
self.host = host
|
|
|
|
def check_boot_time(self):
|
|
"""Check EC and AP boot times"""
|
|
# Initialize a list of two strings, one printed by the EC when the AP
|
|
# is taken out of reset, and another one printed when the EC observes
|
|
# the AP running. These strings are used as for console output anchors
|
|
# when calculating the AP boot time.
|
|
#
|
|
# This is very approximate, a better long term solution would be to
|
|
# have the EC print the same fixed strings for these two events on all
|
|
# platforms. http://crosbug.com/p/21628 has been opened to track this
|
|
# issue.
|
|
if self._x86:
|
|
boot_anchors = ["\[([0-9\.]+) PB",
|
|
"\[([0-9\.]+) [^\r\n]*(HC 0x|Port 80|ACPI query)"]
|
|
elif self._arm_legacy:
|
|
boot_anchors = ["\[([0-9\.]+) AP running ...",
|
|
"\[([0-9\.]+) XPSHOLD seen"]
|
|
else:
|
|
boot_anchors = ["\[([0-9\.]+) power state 1 = S5",
|
|
"\[([0-9\.]+) power state 3 = S0"]
|
|
|
|
# regular expression to say that EC is ready. For systems that
|
|
# run out of ram there is a second boot where the PMIC is
|
|
# asked to power cycle the EC to be 100% sure (I wish) that
|
|
# the code is clean. Looking for the "Inits done" generates a
|
|
# match after the first boot, and introduces a race between
|
|
# the EC booting the second time and the test sending the
|
|
# power_cmd.
|
|
if self._doubleboot:
|
|
ec_ready = ["(?ms)UART.*UART.*?\[([0-9.]+) "]
|
|
else:
|
|
ec_ready = ["([0-9.]+) Inits done"]
|
|
|
|
if self.faft_config.ec_has_powerbtn_cmd:
|
|
# powerbtn takes ms while hold_pwr_button_powero is seconds.
|
|
hold_ms = int(1000 * self.faft_config.hold_pwr_button_poweron)
|
|
power_cmd = 'powerbtn %s' % hold_ms
|
|
else:
|
|
power_cmd = 'power on'
|
|
|
|
# Try the EC reboot command several times in case the console
|
|
# output is not clean enough for the full string to be found.
|
|
retry = 10
|
|
while retry > 0:
|
|
retry = retry - 1
|
|
try:
|
|
reboot = self.ec.send_command_get_output(
|
|
"reboot ap-off", ec_ready)
|
|
break
|
|
except error.TestFail:
|
|
logging.info("Unable to parse EC console output, "
|
|
"%d more attempts", retry)
|
|
if retry == 0:
|
|
raise error.TestFail("Unable to reboot EC cleanly, " +
|
|
"Please try removing AC power")
|
|
logging.debug("reboot: %r", reboot)
|
|
|
|
# The EC console must be available 1 second after startup
|
|
time.sleep(1)
|
|
|
|
version = self.ec.get_version()
|
|
|
|
if not version:
|
|
raise error.TestFail("Unable to get EC console.")
|
|
|
|
# Wait until the ap enter the G3
|
|
time.sleep(self.faft_config.ec_reboot_to_g3_delay)
|
|
|
|
# Enable printing host commands. Some boards have it disabled by default
|
|
# After reboot it will be restored to default
|
|
self.ec.send_command("hcdebug normal")
|
|
|
|
# Enable port80 output for x86 devices so there is an early signal from
|
|
# the host that it is booting, instead of relying on an EC transaction.
|
|
if self._x86:
|
|
self.ec.send_command("port80 intprint")
|
|
|
|
# Switch on the AP
|
|
power_press = self.ec.send_command_get_output(
|
|
power_cmd, boot_anchors)
|
|
|
|
# TODO(crbug.com/847289): reboot_time only measures the time spent in
|
|
# EC's main function, which is not a good measure of "EC cold boot time"
|
|
reboot_time = float(reboot[0][1])
|
|
power_press_time = float(power_press[0][1])
|
|
firmware_resp_time = float(power_press[1][1])
|
|
boot_time = firmware_resp_time - power_press_time
|
|
logging.info("EC cold boot time: %f s", reboot_time)
|
|
if reboot_time > 1.0:
|
|
raise error.TestFail("EC cold boot time longer than 1 second.")
|
|
logging.info("EC boot time: %f s", boot_time)
|
|
if boot_time > 1.0:
|
|
raise error.TestFail("Boot time longer than 1 second.")
|
|
|
|
def is_arm_legacy_board(self):
|
|
"""Detect whether the board is a legacy ARM board.
|
|
|
|
This group of boards prints specific strings on the EC console when the
|
|
EC and AP come out of reset.
|
|
"""
|
|
|
|
arm_legacy = ('snow', 'spring', 'pit', 'pi', 'big', 'blaze', 'kitty')
|
|
output = self.faft_client.system.get_platform_name()
|
|
return output.lower() in arm_legacy
|
|
|
|
def run_once(self):
|
|
"""Execute the main body of the test.
|
|
"""
|
|
|
|
self._x86 = ('x86' in self.faft_config.ec_capability)
|
|
self._doubleboot = ('doubleboot' in self.faft_config.ec_capability)
|
|
self._arm_legacy = self.is_arm_legacy_board()
|
|
logging.info("Reboot and check EC cold boot time and host boot time.")
|
|
self.switcher.mode_aware_reboot('custom', self.check_boot_time)
|
|
|
|
def cleanup(self):
|
|
try:
|
|
# Restore the ec_uart_regexp to None
|
|
self.ec.set_uart_regexp('None')
|
|
|
|
# Reboot the EC and wait for the host to come up so it is ready for
|
|
# the next test.
|
|
self.ec.reboot()
|
|
self.host.wait_up(timeout=30)
|
|
except Exception as e:
|
|
logging.error("Caught exception: %s", str(e))
|
|
super(firmware_ECBootTime, self).cleanup()
|