1# Copyright 2020 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 5 6"""The autotest performing FW update, both EC and AP in CCD mode.""" 7import logging 8 9from autotest_lib.client.common_lib import error 10from autotest_lib.server.cros.faft.cr50_test import Cr50Test 11from autotest_lib.server.cros.servo import servo 12 13MAX_TRIES=2 14 15 16class firmware_Cr50CCDFirmwareUpdate(Cr50Test): 17 """A test that can provision a machine to the correct firmware version.""" 18 19 version = 1 20 should_restore_fw = False 21 22 def initialize(self, host, cmdline_args, full_args): 23 """Initialize the test and check if cr50 exists. 24 25 Raises: 26 TestNAError: If the dut is not proper for this test for its RDD 27 recognition problem. 28 """ 29 super(firmware_Cr50CCDFirmwareUpdate, 30 self).initialize(host, cmdline_args, full_args) 31 32 # Don't bother if there is no Chrome EC. 33 if not self.check_ec_capability(): 34 raise error.TestNAError('Nothing needs to be tested on this device') 35 36 servo_type = self.servo.get_servo_version() 37 if 'ccd_cr50' not in servo_type: 38 raise error.TestNAError('unsupported servo type: %s' % servo_type) 39 40 if eval(full_args.get('backup_fw', 'False')): 41 self.backup_firmware() 42 43 def cleanup(self): 44 try: 45 if not self.should_restore_fw: 46 return 47 48 self.cr50.reboot() 49 self.switcher.mode_aware_reboot(reboot_type='cold') 50 51 # Verify the EC is responsive before raising an error and going to 52 # cleanup. Repair and cleanup don't recover corrupted EC firmware 53 # very well. 54 try: 55 self.verify_ec_response() 56 except Exception as e: 57 logging.error('Caught exception: %s', str(e)) 58 59 if self.is_firmware_saved(): 60 logging.info('Restoring firmware') 61 self.restore_firmware() 62 else: 63 logging.info('chromeos-firmwareupdate --mode=recovery') 64 result = self._client.run('chromeos-firmwareupdate' 65 ' --mode=recovery', 66 ignore_status=True) 67 if result.exit_status != 0: 68 logging.error('chromeos-firmwareupdate failed: %s', 69 result.stdout.strip()) 70 self._client.reboot() 71 except Exception as e: 72 logging.error('Caught exception: %s', str(e)) 73 finally: 74 super(firmware_Cr50CCDFirmwareUpdate, self).cleanup() 75 76 def verify_ec_response(self): 77 """ Verify the EC is responsive.""" 78 # Try to reflash EC a couple of times to see if it's possible to recover 79 # the device now. 80 count = MAX_TRIES 81 while True: 82 try: 83 if self.servo.get_ec_board(): 84 return 85 except servo.ConsoleError as e: 86 logging.error('EC console is unresponsive: %s', str(e)) 87 88 if count == 0: 89 break 90 91 count -= 1 92 # In the last iteration, try with main servo device. 93 if count == 0: 94 self.servo.enable_main_servo_device() 95 96 try: 97 self.cros_host.firmware_install(build=self.b_ver, 98 install_bios=False) 99 except Exception as e: 100 logging.error('firmware_install failed: %s', str(e)) 101 102 logging.error('DUT likely needs a manual recovery.') 103 104 def run_once(self, host, rw_only=False): 105 """The method called by the control file to start the test. 106 107 Args: 108 host: a CrosHost object of the machine to update. 109 rw_only: True to only update the RW firmware. 110 111 Raises: 112 TestFail: if the firmware version remains unchanged. 113 TestError: if the latest firmware release cannot be located. 114 TestNAError: if the test environment is not properly set. 115 e.g. the servo type doesn't support this test. 116 """ 117 self.cros_host = host 118 # Get the parent (a.k.a. reference board or baseboard), and hand it 119 # to get_latest_release_version so that it 120 # can use it in search as secondary candidate. For example, bob doesn't 121 # have its own release directory, but its parent, gru does. 122 parent = getattr(self.faft_config, 'parent', None) 123 124 self.b_ver = host.get_latest_release_version(self.faft_config.platform, 125 parent) 126 if not self.b_ver: 127 raise error.TestError('Cannot locate the latest release for %s' % 128 self.faft_config.platform) 129 130 # Fast open cr50 and check if testlab is enabled. 131 self.fast_ccd_open(enable_testlab=True) 132 if self.servo.has_control('active_v4_device'): 133 try: 134 self.servo.set('active_v4_device', 'ccd_cr50') 135 except error.TestFail as e: 136 raise error.TestNAError('cannot change active_v4_device: %s' % 137 str(e)) 138 139 # If it is ITE EC, then ccd reset factory. 140 if self.servo.get('ec_chip') == 'it83xx': 141 self.cr50.set_cap('I2C', 'Always') 142 143 self.should_restore_fw = True 144 try: 145 self.cros_host.firmware_install(build=self.b_ver, rw_only=rw_only, 146 dest=self.resultsdir, 147 verify_version=True) 148 except Exception as e: 149 # The test failed to flash the firmware. 150 raise error.TestFail('firmware_install failed with CCD: %s' % 151 str(e)) 152