• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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