# Copyright 2020 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. """The autotest performing FW update, both EC and AP in CCD mode.""" import logging from autotest_lib.client.common_lib import error from autotest_lib.server.cros.faft.cr50_test import Cr50Test from autotest_lib.server.cros.servo import servo MAX_TRIES=2 class firmware_Cr50CCDFirmwareUpdate(Cr50Test): """A test that can provision a machine to the correct firmware version.""" version = 1 should_restore_fw = False def initialize(self, host, cmdline_args, full_args): """Initialize the test and check if cr50 exists. Raises: TestNAError: If the dut is not proper for this test for its RDD recognition problem. """ super(firmware_Cr50CCDFirmwareUpdate, self).initialize(host, cmdline_args, full_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') servo_type = self.servo.get_servo_version() if 'ccd_cr50' not in servo_type: raise error.TestNAError('unsupported servo type: %s' % servo_type) if eval(full_args.get('backup_fw', 'False')): self.backup_firmware() def cleanup(self): try: if not self.should_restore_fw: return self.cr50.reboot() self.switcher.mode_aware_reboot(reboot_type='cold') # Verify the EC is responsive before raising an error and going to # cleanup. Repair and cleanup don't recover corrupted EC firmware # very well. try: self.verify_ec_response() except Exception as e: logging.error('Caught exception: %s', str(e)) if self.is_firmware_saved(): logging.info('Restoring firmware') self.restore_firmware() else: logging.info('chromeos-firmwareupdate --mode=recovery') result = self._client.run('chromeos-firmwareupdate' ' --mode=recovery', ignore_status=True) if result.exit_status != 0: logging.error('chromeos-firmwareupdate failed: %s', result.stdout.strip()) self._client.reboot() except Exception as e: logging.error('Caught exception: %s', str(e)) finally: super(firmware_Cr50CCDFirmwareUpdate, self).cleanup() def verify_ec_response(self): """ Verify the EC is responsive.""" # Try to reflash EC a couple of times to see if it's possible to recover # the device now. count = MAX_TRIES while True: try: if self.servo.get_ec_board(): return except servo.ConsoleError as e: logging.error('EC console is unresponsive: %s', str(e)) if count == 0: break count -= 1 # In the last iteration, try with main servo device. if count == 0: self.servo.enable_main_servo_device() try: self.cros_host.firmware_install(build=self.b_ver, install_bios=False) except Exception as e: logging.error('firmware_install failed: %s', str(e)) logging.error('DUT likely needs a manual recovery.') def run_once(self, host, rw_only=False): """The method called by the control file to start the test. Args: host: a CrosHost object of the machine to update. rw_only: True to only update the RW firmware. Raises: TestFail: if the firmware version remains unchanged. TestError: if the latest firmware release cannot be located. TestNAError: if the test environment is not properly set. e.g. the servo type doesn't support this test. """ self.cros_host = host # Get the parent (a.k.a. reference board or baseboard), and hand it # to get_latest_release_version so that it # can use it in search as secondary candidate. For example, bob doesn't # have its own release directory, but its parent, gru does. parent = getattr(self.faft_config, 'parent', None) self.b_ver = host.get_latest_release_version(self.faft_config.platform, parent) if not self.b_ver: raise error.TestError('Cannot locate the latest release for %s' % self.faft_config.platform) # Fast open cr50 and check if testlab is enabled. self.fast_ccd_open(enable_testlab=True) if self.servo.has_control('active_v4_device'): try: self.servo.set('active_v4_device', 'ccd_cr50') except error.TestFail as e: raise error.TestNAError('cannot change active_v4_device: %s' % str(e)) # If it is ITE EC, then ccd reset factory. if self.servo.get('ec_chip') == 'it83xx': self.cr50.set_cap('I2C', 'Always') self.should_restore_fw = True try: self.cros_host.firmware_install(build=self.b_ver, rw_only=rw_only, dest=self.resultsdir, verify_version=True) except Exception as e: # The test failed to flash the firmware. raise error.TestFail('firmware_install failed with CCD: %s' % str(e))