1/* 2 * Copyright �� 2016 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 * 23 */ 24 25#include "../i915_selftest.h" 26 27#include "gt/intel_gt.h" 28 29static int intel_fw_table_check(const struct intel_forcewake_range *ranges, 30 unsigned int num_ranges, 31 bool is_watertight) 32{ 33 unsigned int i; 34 s32 prev; 35 36 for (i = 0, prev = -1; i < num_ranges; i++, ranges++) { 37 /* Check that the table is watertight */ 38 if (is_watertight && (prev + 1) != (s32)ranges->start) { 39 pr_err("%s: entry[%d]:(%x, %x) is not watertight to previous (%x)\n", 40 __func__, i, ranges->start, ranges->end, prev); 41 return -EINVAL; 42 } 43 44 /* Check that the table never goes backwards */ 45 if (prev >= (s32)ranges->start) { 46 pr_err("%s: entry[%d]:(%x, %x) is less than the previous (%x)\n", 47 __func__, i, ranges->start, ranges->end, prev); 48 return -EINVAL; 49 } 50 51 /* Check that the entry is valid */ 52 if (ranges->start >= ranges->end) { 53 pr_err("%s: entry[%d]:(%x, %x) has negative length\n", 54 __func__, i, ranges->start, ranges->end); 55 return -EINVAL; 56 } 57 58 prev = ranges->end; 59 } 60 61 return 0; 62} 63 64static int intel_shadow_table_check(void) 65{ 66 struct { 67 const struct i915_range *regs; 68 unsigned int size; 69 } range_lists[] = { 70 { gen8_shadowed_regs, ARRAY_SIZE(gen8_shadowed_regs) }, 71 { gen11_shadowed_regs, ARRAY_SIZE(gen11_shadowed_regs) }, 72 { gen12_shadowed_regs, ARRAY_SIZE(gen12_shadowed_regs) }, 73 { dg2_shadowed_regs, ARRAY_SIZE(dg2_shadowed_regs) }, 74 { pvc_shadowed_regs, ARRAY_SIZE(pvc_shadowed_regs) }, 75 { mtl_shadowed_regs, ARRAY_SIZE(mtl_shadowed_regs) }, 76 { xelpmp_shadowed_regs, ARRAY_SIZE(xelpmp_shadowed_regs) }, 77 }; 78 const struct i915_range *range; 79 unsigned int i, j; 80 s32 prev; 81 82 for (j = 0; j < ARRAY_SIZE(range_lists); ++j) { 83 range = range_lists[j].regs; 84 for (i = 0, prev = -1; i < range_lists[j].size; i++, range++) { 85 if (range->end < range->start) { 86 pr_err("%s: range[%d]:(%06x-%06x) has end before start\n", 87 __func__, i, range->start, range->end); 88 return -EINVAL; 89 } 90 91 if (prev >= (s32)range->start) { 92 pr_err("%s: range[%d]:(%06x-%06x) is before end of previous (%06x)\n", 93 __func__, i, range->start, range->end, prev); 94 return -EINVAL; 95 } 96 97 if (range->start % 4) { 98 pr_err("%s: range[%d]:(%06x-%06x) has non-dword-aligned start\n", 99 __func__, i, range->start, range->end); 100 return -EINVAL; 101 } 102 103 prev = range->end; 104 } 105 } 106 107 return 0; 108} 109 110int intel_uncore_mock_selftests(void) 111{ 112 struct { 113 const struct intel_forcewake_range *ranges; 114 unsigned int num_ranges; 115 bool is_watertight; 116 } fw[] = { 117 { __vlv_fw_ranges, ARRAY_SIZE(__vlv_fw_ranges), false }, 118 { __chv_fw_ranges, ARRAY_SIZE(__chv_fw_ranges), false }, 119 { __gen9_fw_ranges, ARRAY_SIZE(__gen9_fw_ranges), true }, 120 { __gen11_fw_ranges, ARRAY_SIZE(__gen11_fw_ranges), true }, 121 { __gen12_fw_ranges, ARRAY_SIZE(__gen12_fw_ranges), true }, 122 { __xehp_fw_ranges, ARRAY_SIZE(__xehp_fw_ranges), true }, 123 { __pvc_fw_ranges, ARRAY_SIZE(__pvc_fw_ranges), true }, 124 { __mtl_fw_ranges, ARRAY_SIZE(__mtl_fw_ranges), true }, 125 { __xelpmp_fw_ranges, ARRAY_SIZE(__xelpmp_fw_ranges), true }, 126 }; 127 int err, i; 128 129 for (i = 0; i < ARRAY_SIZE(fw); i++) { 130 err = intel_fw_table_check(fw[i].ranges, 131 fw[i].num_ranges, 132 fw[i].is_watertight); 133 if (err) 134 return err; 135 } 136 137 err = intel_shadow_table_check(); 138 if (err) 139 return err; 140 141 return 0; 142} 143 144static int live_forcewake_ops(void *arg) 145{ 146 static const struct reg { 147 const char *name; 148 u8 min_graphics_ver; 149 u8 max_graphics_ver; 150 unsigned long platforms; 151 unsigned int offset; 152 } registers[] = { 153 { 154 "RING_START", 155 6, 7, 156 0x38, 157 }, 158 { 159 "RING_MI_MODE", 160 8, U8_MAX, 161 0x9c, 162 } 163 }; 164 const struct reg *r; 165 struct intel_gt *gt = arg; 166 struct intel_uncore_forcewake_domain *domain; 167 struct intel_uncore *uncore = gt->uncore; 168 struct intel_engine_cs *engine; 169 enum intel_engine_id id; 170 intel_wakeref_t wakeref; 171 unsigned int tmp; 172 int err = 0; 173 174 GEM_BUG_ON(gt->awake); 175 176 /* vlv/chv with their pcu behave differently wrt reads */ 177 if (IS_VALLEYVIEW(gt->i915) || IS_CHERRYVIEW(gt->i915)) { 178 pr_debug("PCU fakes forcewake badly; skipping\n"); 179 return 0; 180 } 181 182 /* 183 * Not quite as reliable across the gen as one would hope. 184 * 185 * Either our theory of operation is incorrect, or there remain 186 * external parties interfering with the powerwells. 187 * 188 * https://bugs.freedesktop.org/show_bug.cgi?id=110210 189 */ 190 if (!IS_ENABLED(CONFIG_DRM_I915_SELFTEST_BROKEN)) 191 return 0; 192 193 /* We have to pick carefully to get the exact behaviour we need */ 194 for (r = registers; r->name; r++) 195 if (IS_GRAPHICS_VER(gt->i915, r->min_graphics_ver, r->max_graphics_ver)) 196 break; 197 if (!r->name) { 198 pr_debug("Forcewaked register not known for %s; skipping\n", 199 intel_platform_name(INTEL_INFO(gt->i915)->platform)); 200 return 0; 201 } 202 203 wakeref = intel_runtime_pm_get(uncore->rpm); 204 205 for_each_fw_domain(domain, uncore, tmp) { 206 smp_store_mb(domain->active, false); 207 if (!hrtimer_cancel(&domain->timer)) 208 continue; 209 210 intel_uncore_fw_release_timer(&domain->timer); 211 } 212 213 for_each_engine(engine, gt, id) { 214 i915_reg_t mmio = _MMIO(engine->mmio_base + r->offset); 215 u32 __iomem *reg = intel_uncore_regs(uncore) + engine->mmio_base + r->offset; 216 enum forcewake_domains fw_domains; 217 u32 val; 218 219 if (!engine->default_state) 220 continue; 221 222 fw_domains = intel_uncore_forcewake_for_reg(uncore, mmio, 223 FW_REG_READ); 224 if (!fw_domains) 225 continue; 226 227 for_each_fw_domain_masked(domain, fw_domains, uncore, tmp) { 228 if (!domain->wake_count) 229 continue; 230 231 pr_err("fw_domain %s still active, aborting test!\n", 232 intel_uncore_forcewake_domain_to_str(domain->id)); 233 err = -EINVAL; 234 goto out_rpm; 235 } 236 237 intel_uncore_forcewake_get(uncore, fw_domains); 238 val = readl(reg); 239 intel_uncore_forcewake_put(uncore, fw_domains); 240 241 /* Flush the forcewake release (delayed onto a timer) */ 242 for_each_fw_domain_masked(domain, fw_domains, uncore, tmp) { 243 smp_store_mb(domain->active, false); 244 if (hrtimer_cancel(&domain->timer)) 245 intel_uncore_fw_release_timer(&domain->timer); 246 247 preempt_disable(); 248 err = wait_ack_clear(domain, FORCEWAKE_KERNEL); 249 preempt_enable(); 250 if (err) { 251 pr_err("Failed to clear fw_domain %s\n", 252 intel_uncore_forcewake_domain_to_str(domain->id)); 253 goto out_rpm; 254 } 255 } 256 257 if (!val) { 258 pr_err("%s:%s was zero while fw was held!\n", 259 engine->name, r->name); 260 err = -EINVAL; 261 goto out_rpm; 262 } 263 264 /* We then expect the read to return 0 outside of the fw */ 265 if (wait_for(readl(reg) == 0, 100)) { 266 pr_err("%s:%s=%0x, fw_domains 0x%x still up after 100ms!\n", 267 engine->name, r->name, readl(reg), fw_domains); 268 err = -ETIMEDOUT; 269 goto out_rpm; 270 } 271 } 272 273out_rpm: 274 intel_runtime_pm_put(uncore->rpm, wakeref); 275 return err; 276} 277 278static int live_forcewake_domains(void *arg) 279{ 280#define FW_RANGE 0x40000 281 struct intel_gt *gt = arg; 282 struct intel_uncore *uncore = gt->uncore; 283 unsigned long *valid; 284 u32 offset; 285 int err; 286 287 if (!HAS_FPGA_DBG_UNCLAIMED(gt->i915) && 288 !IS_VALLEYVIEW(gt->i915) && 289 !IS_CHERRYVIEW(gt->i915)) 290 return 0; 291 292 /* 293 * This test may lockup the machine or cause GPU hangs afterwards. 294 */ 295 if (!IS_ENABLED(CONFIG_DRM_I915_SELFTEST_BROKEN)) 296 return 0; 297 298 valid = bitmap_zalloc(FW_RANGE, GFP_KERNEL); 299 if (!valid) 300 return -ENOMEM; 301 302 intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL); 303 304 check_for_unclaimed_mmio(uncore); 305 for (offset = 0; offset < FW_RANGE; offset += 4) { 306 i915_reg_t reg = { offset }; 307 308 intel_uncore_posting_read_fw(uncore, reg); 309 if (!check_for_unclaimed_mmio(uncore)) 310 set_bit(offset, valid); 311 } 312 313 intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL); 314 315 err = 0; 316 for_each_set_bit(offset, valid, FW_RANGE) { 317 i915_reg_t reg = { offset }; 318 319 iosf_mbi_punit_acquire(); 320 intel_uncore_forcewake_reset(uncore); 321 iosf_mbi_punit_release(); 322 323 check_for_unclaimed_mmio(uncore); 324 325 intel_uncore_posting_read_fw(uncore, reg); 326 if (check_for_unclaimed_mmio(uncore)) { 327 pr_err("Unclaimed mmio read to register 0x%04x\n", 328 offset); 329 err = -EINVAL; 330 } 331 } 332 333 bitmap_free(valid); 334 return err; 335} 336 337static int live_fw_table(void *arg) 338{ 339 struct intel_gt *gt = arg; 340 341 /* Confirm the table we load is still valid */ 342 return intel_fw_table_check(gt->uncore->fw_domains_table, 343 gt->uncore->fw_domains_table_entries, 344 GRAPHICS_VER(gt->i915) >= 9); 345} 346 347int intel_uncore_live_selftests(struct drm_i915_private *i915) 348{ 349 static const struct i915_subtest tests[] = { 350 SUBTEST(live_fw_table), 351 SUBTEST(live_forcewake_ops), 352 SUBTEST(live_forcewake_domains), 353 }; 354 355 return intel_gt_live_subtests(tests, to_gt(i915)); 356} 357