1# Copyright 2014 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, os, re, struct, time 6 7from autotest_lib.client.bin import test 8from autotest_lib.client.bin import utils 9from autotest_lib.client.common_lib import error 10from autotest_lib.client.common_lib.cros import chrome 11from autotest_lib.client.cros import cros_logging 12 13# Kernel 3.8 to 3.14 has cur_delay_info, 3.18+ has frequency_info. 14CLOCK_PATHS = ['/sys/kernel/debug/dri/0/i915_frequency_info', 15 '/sys/kernel/debug/dri/0/i915_cur_delayinfo'] 16# Kernel 3.8 has i915_fbc, kernel > 3.8 i915_fbc_status. 17FBC_PATHS = ['/sys/kernel/debug/dri/0/i915_fbc', 18 '/sys/kernel/debug/dri/0/i915_fbc_status'] 19GEM_PATHS = ['/sys/kernel/debug/dri/0/i915_gem_active'] 20PSR_PATHS = ['/sys/kernel/debug/dri/0/i915_edp_psr_status'] 21RC6_PATHS = ['/sys/kernel/debug/dri/0/i915_drpc_info'] 22 23 24class graphics_Idle(test.test): 25 """Class for graphics_Idle. See 'control' for details.""" 26 version = 1 27 _gpu_type = None 28 _cpu_type = None 29 _board = None 30 31 def run_once(self): 32 # Try to protect against runaway previous tests. 33 if not utils.wait_for_idle_cpu(20.0, 0.1): 34 logging.warning('Could not get idle CPU before running tests.') 35 # We use kiosk mode to make sure Chrome is idle. 36 with chrome.Chrome(logged_in=False, extra_browser_args=['--kiosk']): 37 self._gpu_type = utils.get_gpu_family() 38 self._cpu_type = utils.get_cpu_soc_family() 39 self._board = utils.get_board() 40 errors = '' 41 errors += self.verify_graphics_dvfs() 42 errors += self.verify_graphics_fbc() 43 errors += self.verify_graphics_psr() 44 errors += self.verify_graphics_gem_idle() 45 errors += self.verify_graphics_i915_min_clock() 46 errors += self.verify_graphics_rc6() 47 errors += self.verify_lvds_downclock() 48 errors += self.verify_short_blanking() 49 if errors: 50 raise error.TestFail(errors) 51 52 def get_valid_path(self, paths): 53 for path in paths: 54 if os.path.exists(path): 55 return path 56 logging.error('Error: %s not found.', ' '.join(paths)) 57 return None 58 59 def verify_lvds_downclock(self): 60 """On systems which support LVDS downclock, checks the kernel log for 61 a message that an LVDS downclock mode has been added.""" 62 logging.info('Running verify_lvds_downclock') 63 board = utils.get_board() 64 if not (board == 'alex' or board == 'lumpy' or board == 'stout'): 65 return '' 66 67 # Get the downclock message from the logs. 68 reader = cros_logging.LogReader() 69 reader.set_start_by_reboot(-1) 70 if not reader.can_find('Adding LVDS downclock mode'): 71 logging.error('Error: LVDS downclock quirk not applied.') 72 return 'LVDS downclock quirk not applied. ' 73 74 return '' 75 76 def verify_short_blanking(self): 77 """On baytrail systems with a known panel, checks the kernel log for a 78 message that a short blanking mode has been added.""" 79 logging.info('Running verify_short_blanking') 80 if self._gpu_type != 'baytrail' or utils.has_no_monitor(): 81 return '' 82 83 # Open the EDID to find the panel model. 84 param_path = '/sys/class/drm/card0-eDP-1/edid' 85 if not os.path.exists(param_path): 86 logging.error('Error: %s not found.', param_path) 87 return 'Short blanking not added (no EDID found). ' 88 89 with open(param_path, 'r') as edp_edid_file: 90 edp_edid_file.seek(8) 91 data = edp_edid_file.read(2) 92 manufacturer = int(struct.unpack('<H', data)[0]) 93 data = edp_edid_file.read(2) 94 product_code = int(struct.unpack('<H', data)[0]) 95 96 # This is not the panel we are looking for (AUO B116XTN02.2) 97 if manufacturer != 0xaf06 or product_code != 0x225c: 98 return '' 99 100 # Get the downclock message from the logs. 101 reader = cros_logging.LogReader() 102 reader.set_start_by_reboot(-1) 103 if not reader.can_find('Modified preferred into a short blanking mode'): 104 logging.error('Error: short blanking not added.') 105 return 'Short blanking not added. ' 106 107 return '' 108 109 def verify_graphics_rc6(self): 110 """ On systems which support RC6 (non atom), check that we are able to 111 get into rc6; idle before doing so, and retry every second for 20 112 seconds.""" 113 logging.info('Running verify_graphics_rc6') 114 # TODO(ihf): Implement on baytrail/braswell using residency counters. 115 # But note the format changed since SNB, so this will be complex. 116 if (utils.get_cpu_soc_family() == 'x86_64' and 117 self._gpu_type != 'pinetrail' and 118 self._gpu_type != 'baytrail' and self._gpu_type != 'braswell'): 119 tries = 0 120 found = False 121 param_path = self.get_valid_path(RC6_PATHS) 122 if not param_path: 123 return 'RC6_PATHS not found.' 124 while found == False and tries < 20: 125 time.sleep(1) 126 with open(param_path, 'r') as drpc_info_file: 127 for line in drpc_info_file: 128 match = re.search(r'Current RC state: (.*)', line) 129 if match and match.group(1) == 'RC6': 130 found = True 131 break 132 133 tries += 1 134 135 if not found: 136 utils.log_process_activity() 137 logging.error('Error: did not see the GPU in RC6.') 138 return 'Did not see the GPU in RC6. ' 139 140 return '' 141 142 def verify_graphics_i915_min_clock(self): 143 """ On i915 systems, check that we get into the lowest clock frequency; 144 idle before doing so, and retry every second for 20 seconds.""" 145 logging.info('Running verify_graphics_i915_min_clock') 146 if (utils.get_cpu_soc_family() == 'x86_64' and 147 self._gpu_type != 'pinetrail'): 148 tries = 0 149 found = False 150 param_path = self.get_valid_path(CLOCK_PATHS) 151 if not param_path: 152 return 'CLOCK_PATHS not found.' 153 while not found and tries < 80: 154 time.sleep(0.25) 155 156 with open(param_path, 'r') as delayinfo_file: 157 for line in delayinfo_file: 158 # This file has a different format depending on the 159 # board, so we parse both. Also, it would be tedious 160 # to add the minimum clock for each board, so instead 161 # we use 650MHz which is the max of the minimum clocks. 162 match = re.search(r'CAGF: (.*)MHz', line) 163 if match and int(match.group(1)) <= 650: 164 found = True 165 break 166 167 match = re.search(r'current GPU freq: (.*) MHz', line) 168 if match and int(match.group(1)) <= 650: 169 found = True 170 break 171 172 tries += 1 173 174 if not found: 175 utils.log_process_activity() 176 logging.error('Error: did not see the min i915 clock') 177 return 'Did not see the min i915 clock. ' 178 179 return '' 180 181 def verify_graphics_dvfs(self): 182 """ On systems which support DVFS, check that we get into the lowest 183 clock frequency; idle before doing so, and retry every second for 20 184 seconds.""" 185 logging.info('Running verify_graphics_dvfs') 186 if self._gpu_type == 'mali': 187 if self._cpu_type == 'exynos5': 188 node = '/sys/devices/11800000.mali/' 189 enable_node = 'dvfs' 190 enable_value = 'on' 191 elif self._cpu_type == 'rockchip': 192 node = '/sys/devices/ffa30000.gpu/' 193 enable_node = 'dvfs_enable' 194 enable_value = '1' 195 else: 196 logging.error('Error: Unknown CPU type (%s) for mali GPU.', 197 self._cpu_type) 198 return 'Unknown CPU type for mali GPU. ' 199 200 clock_path = utils.locate_file('clock', node) 201 enable_path = utils.locate_file(enable_node, node) 202 freqs_path = utils.locate_file('available_frequencies', node) 203 204 enable = utils.read_one_line(enable_path) 205 logging.info('DVFS enable = %s', enable) 206 if not enable == enable_value: 207 logging.error('Error: DVFS is not enabled') 208 return 'DVFS is not enabled. ' 209 210 # available_frequencies are always sorted in ascending order 211 lowest_freq = int(utils.read_one_line(freqs_path)) 212 213 # daisy_* (exynos5250) boards set idle frequency to 266000000 214 # See: crbug.com/467401 and crosbug.com/p/19710 215 if self._board.startswith('daisy'): 216 lowest_freq = 266000000 217 218 logging.info('Expecting idle DVFS clock = %u', lowest_freq) 219 220 tries = 0 221 found = False 222 while not found and tries < 80: 223 time.sleep(0.25) 224 clock = int(utils.read_one_line(clock_path)) 225 if clock <= lowest_freq: 226 logging.info('Found idle DVFS clock = %u', clock) 227 found = True 228 break 229 230 tries += 1 231 232 if not found: 233 utils.log_process_activity() 234 logging.error('Error: DVFS clock (%u) > min (%u)', clock, 235 lowest_freq) 236 return 'Did not see the min DVFS clock. ' 237 238 return '' 239 240 def verify_graphics_fbc(self): 241 """ On systems which support FBC, check that we can get into FBC; 242 idle before doing so, and retry every second for 20 seconds.""" 243 logging.info('Running verify_graphics_fbc') 244 245 # Link's FBC is disabled (crbug.com/338588). 246 # TODO(marcheu): remove this when/if we fix this bug. 247 board = utils.get_board() 248 if board == 'link': 249 return '' 250 251 # Machines which don't have a monitor can't get FBC. 252 if utils.has_no_monitor(): 253 return '' 254 255 if (self._gpu_type == 'haswell' or self._gpu_type == 'ivybridge' or 256 self._gpu_type == 'sandybridge'): 257 tries = 0 258 found = False 259 param_path = self.get_valid_path(FBC_PATHS) 260 if not param_path: 261 return 'FBC_PATHS not found.' 262 while not found and tries < 20: 263 time.sleep(1) 264 with open(param_path, 'r') as fbc_info_file: 265 for line in fbc_info_file: 266 if re.search('FBC enabled', line): 267 found = True 268 break 269 270 tries += 1 271 272 if not found: 273 logging.error('Error: did not see FBC enabled.') 274 return 'Did not see FBC enabled. ' 275 276 return '' 277 278 def verify_graphics_psr(self): 279 """ On systems which support PSR, check that we can get into PSR; 280 idle before doing so, and retry every second for 20 seconds.""" 281 logging.info('Running verify_graphics_psr') 282 283 board = utils.get_board() 284 if board != 'samus': 285 return '' 286 tries = 0 287 found = False 288 param_path = self.get_valid_path(PSR_PATHS) 289 if not param_path: 290 return 'PSR_PATHS not found.' 291 while not found and tries < 20: 292 time.sleep(1) 293 with open(param_path, 'r') as fbc_info_file: 294 for line in fbc_info_file: 295 match = re.search(r'Performance_Counter: (.*)', line) 296 if match and int(match.group(1)) > 0: 297 found = True 298 break 299 300 tries += 1 301 302 if not found: 303 logging.error('Error: did not see PSR enabled.') 304 return 'Did not see PSR enabled. ' 305 306 return '' 307 308 def verify_graphics_gem_idle(self): 309 """ On systems which have i915, check that we can get all gem objects 310 to become idle (i.e. the i915_gem_active list need to go to 0); 311 idle before doing so, and retry every second for 20 seconds.""" 312 logging.info('Running verify_graphics_gem_idle') 313 if (utils.get_cpu_soc_family() == 'x86_64' and 314 self._gpu_type != 'pinetrail'): 315 tries = 0 316 found = False 317 gem_path = self.get_valid_path(GEM_PATHS) 318 if not gem_path: 319 return 'GEM_PATHS not found.' 320 while not found and tries < 240: 321 time.sleep(0.25) 322 with open(gem_path, 'r') as gem_file: 323 for line in gem_file: 324 if re.search('Total 0 objects', line): 325 found = True 326 break 327 328 tries += 1 329 330 if not found: 331 utils.log_process_activity() 332 logging.error('Error: did not reach 0 gem actives.') 333 return 'Did not reach 0 gem actives. ' 334 335 return '' 336