• 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",
40                            "\[([0-9\.]+) [^\r\n]*(HC 0x|Port 80|ACPI query)"]
41        elif self._arm_legacy:
42            boot_anchors = ["\[([0-9\.]+) AP running ...",
43                            "\[([0-9\.]+) XPSHOLD seen"]
44        else:
45            boot_anchors = ["\[([0-9\.]+) power state 1 = S5",
46                            "\[([0-9\.]+) power state 3 = S0"]
47
48        # regular expression to say that EC is ready. For systems that
49        # run out of ram there is a second boot where the PMIC is
50        # asked to power cycle the EC to be 100% sure (I wish) that
51        # the code is clean. Looking for the "Inits done" generates a
52        # match after the first boot, and introduces a race between
53        # the EC booting the second time and the test sending the
54        # power_cmd.
55        if self._doubleboot:
56            ec_ready = ["(?ms)UART.*UART.*?\[([0-9.]+) "]
57        else:
58            ec_ready = ["([0-9.]+) Inits done"]
59
60        if self.faft_config.ec_has_powerbtn_cmd:
61            # powerbtn takes ms while hold_pwr_button_powero is seconds.
62            hold_ms = int(1000 * self.faft_config.hold_pwr_button_poweron)
63            power_cmd = 'powerbtn %s' % hold_ms
64        else:
65            power_cmd = 'power on'
66
67        # Try the EC reboot command several times in case the console
68        # output is not clean enough for the full string to be found.
69        retry = 10
70        while retry > 0:
71            retry = retry - 1
72            try:
73                reboot = self.ec.send_command_get_output(
74                    "reboot ap-off", ec_ready)
75                break
76            except error.TestFail:
77                logging.info("Unable to parse EC console output, "
78                             "%d more attempts", retry)
79        if retry == 0:
80            raise error.TestFail("Unable to reboot EC cleanly, " +
81                                 "Please try removing AC power")
82        logging.debug("reboot: %r", reboot)
83
84        # The EC console must be available 1 second after startup
85        time.sleep(1)
86
87        version = self.ec.get_version()
88
89        if not version:
90            raise error.TestFail("Unable to get EC console.")
91
92        # Wait until the ap enter the G3
93        time.sleep(self.faft_config.ec_reboot_to_g3_delay)
94
95        # Enable printing host commands. Some boards have it disabled by default
96        # After reboot it will be restored to default
97        self.ec.send_command("hcdebug normal")
98
99        # Enable port80 output for x86 devices so there is an early signal from
100        # the host that it is booting, instead of relying on an EC transaction.
101        if self._x86:
102            self.ec.send_command("port80 intprint")
103
104        # Switch on the AP
105        power_press = self.ec.send_command_get_output(
106            power_cmd, boot_anchors)
107
108        # TODO(crbug.com/847289): reboot_time only measures the time spent in
109        # EC's main function, which is not a good measure of "EC cold boot time"
110        reboot_time = float(reboot[0][1])
111        power_press_time = float(power_press[0][1])
112        firmware_resp_time = float(power_press[1][1])
113        boot_time = firmware_resp_time - power_press_time
114        logging.info("EC cold boot time: %f s", reboot_time)
115        if reboot_time > 1.0:
116            raise error.TestFail("EC cold boot time longer than 1 second.")
117        logging.info("EC boot time: %f s", boot_time)
118        if boot_time > 1.0:
119            raise error.TestFail("Boot time longer than 1 second.")
120
121    def is_arm_legacy_board(self):
122        """Detect whether the board is a legacy ARM board.
123
124        This group of boards prints specific strings on the EC console when the
125        EC and AP come out of reset.
126        """
127
128        arm_legacy = ('snow', 'spring', 'pit', 'pi', 'big', 'blaze', 'kitty')
129        output = self.faft_client.system.get_platform_name()
130        return output.lower() in arm_legacy
131
132    def run_once(self):
133        """Execute the main body of the test.
134        """
135
136        self._x86 = ('x86' in self.faft_config.ec_capability)
137        self._doubleboot = ('doubleboot' in self.faft_config.ec_capability)
138        self._arm_legacy = self.is_arm_legacy_board()
139        logging.info("Reboot and check EC cold boot time and host boot time.")
140        self.switcher.mode_aware_reboot('custom', self.check_boot_time)
141
142    def cleanup(self):
143        try:
144            # Restore the ec_uart_regexp to None
145            self.ec.set_uart_regexp('None')
146
147            # Reboot the EC and wait for the host to come up so it is ready for
148            # the next test.
149            self.ec.reboot()
150            self.host.wait_up(timeout=30)
151        except Exception as e:
152            logging.error("Caught exception: %s", str(e))
153        super(firmware_ECBootTime, self).cleanup()
154