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, fw_path=None): 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 self.fw_path = fw_path 37 self.b_ver = '' 38 servo_type = self.servo.get_servo_version() 39 if 'ccd' not in servo_type: 40 raise error.TestNAError('unsupported servo type: %s' % servo_type) 41 42 if eval(full_args.get('backup_fw', 'False')): 43 self.backup_firmware() 44 45 def cleanup(self): 46 try: 47 if not self.should_restore_fw: 48 return 49 50 self.cr50.reboot() 51 self.switcher.mode_aware_reboot(reboot_type='cold') 52 53 # Verify the EC is responsive before raising an error and going to 54 # cleanup. Repair and cleanup don't recover corrupted EC firmware 55 # very well. 56 try: 57 self.verify_ec_response() 58 except Exception as e: 59 logging.error('Caught exception: %s', str(e)) 60 61 if self.is_firmware_saved(): 62 logging.info('Restoring firmware') 63 self.restore_firmware() 64 else: 65 logging.info('chromeos-firmwareupdate --mode=recovery') 66 result = self._client.run('chromeos-firmwareupdate' 67 ' --mode=recovery', 68 ignore_status=True) 69 if result.exit_status != 0: 70 logging.error('chromeos-firmwareupdate failed: %s', 71 result.stdout.strip()) 72 self._client.reboot() 73 except Exception as e: 74 logging.error('Caught exception: %s', str(e)) 75 finally: 76 super(firmware_Cr50CCDFirmwareUpdate, self).cleanup() 77 78 def verify_ec_response(self): 79 """ Verify the EC is responsive.""" 80 # Try to reflash EC a couple of times to see if it's possible to recover 81 # the device now. 82 count = MAX_TRIES 83 while True: 84 try: 85 if self.servo.get_ec_board(): 86 return 87 except servo.ConsoleError as e: 88 logging.error('EC console is unresponsive: %s', str(e)) 89 90 if count == 0: 91 break 92 93 count -= 1 94 # In the last iteration, try with main servo device. 95 if count == 0: 96 self.servo.enable_main_servo_device() 97 98 try: 99 self.cros_host.firmware_install(build=self.b_ver, 100 local_tarball=self.fw_path, 101 install_bios=False) 102 except Exception as e: 103 logging.error('firmware_install failed: %s', str(e)) 104 105 logging.error('DUT likely needs a manual recovery.') 106 107 def run_once(self, host, rw_only=False): 108 """The method called by the control file to start the test. 109 110 Args: 111 host: a CrosHost object of the machine to update. 112 rw_only: True to only update the RW firmware. 113 114 Raises: 115 TestFail: if the firmware version remains unchanged. 116 TestError: if the latest firmware release cannot be located. 117 TestNAError: if the test environment is not properly set. 118 e.g. the servo type doesn't support this test. 119 """ 120 self.cros_host = host 121 # Get the parent (a.k.a. reference board or baseboard), and hand it 122 # to get_latest_release_version so that it 123 # can use it in search as secondary candidate. For example, bob doesn't 124 # have its own release directory, but its parent, gru does. 125 parent = getattr(self.faft_config, 'parent', None) 126 127 if not self.fw_path: 128 self.b_ver = host.get_latest_release_version( 129 self.faft_config.platform, parent) 130 if not self.b_ver: 131 raise error.TestError( 132 'Cannot locate the latest release for %s' % 133 self.faft_config.platform) 134 135 # Fast open cr50 and check if testlab is enabled. 136 self.fast_ccd_open(enable_testlab=True) 137 if not self.servo.enable_ccd_servo_device(): 138 raise error.TestNAError('Cannot make ccd active') 139 # TODO(b/196824029): remove when servod supports using the power state 140 # controller with the ccd device. 141 try: 142 self.host.servo.get_power_state_controller().reset() 143 except Exception as e: 144 logging.info(e) 145 raise error.TestNAError('Unable to do power state reset with ' 146 'active ccd device') 147 148 # If it is ITE EC, then ccd reset factory. 149 if self.servo.get('ec_chip') == 'it83xx': 150 self.cr50.set_cap('I2C', 'Always') 151 152 self.should_restore_fw = True 153 try: 154 self.cros_host.firmware_install(build=self.b_ver, 155 rw_only=rw_only, 156 local_tarball=self.fw_path, 157 dest=self.resultsdir, 158 verify_version=True) 159 except Exception as e: 160 # The test failed to flash the firmware. 161 raise error.TestFail('firmware_install failed with CCD: %s' % 162 str(e)) 163