1 1.1 riastrad /* $NetBSD: selftest_mocs.c,v 1.2 2021/12/18 23:45:30 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * SPDX-License-Identifier: MIT 5 1.1 riastrad * 6 1.1 riastrad * Copyright 2019 Intel Corporation 7 1.1 riastrad */ 8 1.1 riastrad 9 1.1 riastrad #include <sys/cdefs.h> 10 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: selftest_mocs.c,v 1.2 2021/12/18 23:45:30 riastradh Exp $"); 11 1.1 riastrad 12 1.1 riastrad #include "gt/intel_engine_pm.h" 13 1.1 riastrad #include "i915_selftest.h" 14 1.1 riastrad 15 1.1 riastrad #include "gem/selftests/mock_context.h" 16 1.1 riastrad #include "selftests/igt_reset.h" 17 1.1 riastrad #include "selftests/igt_spinner.h" 18 1.1 riastrad 19 1.1 riastrad struct live_mocs { 20 1.1 riastrad struct drm_i915_mocs_table table; 21 1.1 riastrad struct i915_vma *scratch; 22 1.1 riastrad void *vaddr; 23 1.1 riastrad }; 24 1.1 riastrad 25 1.1 riastrad static int request_add_sync(struct i915_request *rq, int err) 26 1.1 riastrad { 27 1.1 riastrad i915_request_get(rq); 28 1.1 riastrad i915_request_add(rq); 29 1.1 riastrad if (i915_request_wait(rq, 0, HZ / 5) < 0) 30 1.1 riastrad err = -ETIME; 31 1.1 riastrad i915_request_put(rq); 32 1.1 riastrad 33 1.1 riastrad return err; 34 1.1 riastrad } 35 1.1 riastrad 36 1.1 riastrad static int request_add_spin(struct i915_request *rq, struct igt_spinner *spin) 37 1.1 riastrad { 38 1.1 riastrad int err = 0; 39 1.1 riastrad 40 1.1 riastrad i915_request_get(rq); 41 1.1 riastrad i915_request_add(rq); 42 1.1 riastrad if (spin && !igt_wait_for_spinner(spin, rq)) 43 1.1 riastrad err = -ETIME; 44 1.1 riastrad i915_request_put(rq); 45 1.1 riastrad 46 1.1 riastrad return err; 47 1.1 riastrad } 48 1.1 riastrad 49 1.1 riastrad static struct i915_vma *create_scratch(struct intel_gt *gt) 50 1.1 riastrad { 51 1.1 riastrad struct drm_i915_gem_object *obj; 52 1.1 riastrad struct i915_vma *vma; 53 1.1 riastrad int err; 54 1.1 riastrad 55 1.1 riastrad obj = i915_gem_object_create_internal(gt->i915, PAGE_SIZE); 56 1.1 riastrad if (IS_ERR(obj)) 57 1.1 riastrad return ERR_CAST(obj); 58 1.1 riastrad 59 1.1 riastrad i915_gem_object_set_cache_coherency(obj, I915_CACHING_CACHED); 60 1.1 riastrad 61 1.1 riastrad vma = i915_vma_instance(obj, >->ggtt->vm, NULL); 62 1.1 riastrad if (IS_ERR(vma)) { 63 1.1 riastrad i915_gem_object_put(obj); 64 1.1 riastrad return vma; 65 1.1 riastrad } 66 1.1 riastrad 67 1.1 riastrad err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL); 68 1.1 riastrad if (err) { 69 1.1 riastrad i915_gem_object_put(obj); 70 1.1 riastrad return ERR_PTR(err); 71 1.1 riastrad } 72 1.1 riastrad 73 1.1 riastrad return vma; 74 1.1 riastrad } 75 1.1 riastrad 76 1.1 riastrad static int live_mocs_init(struct live_mocs *arg, struct intel_gt *gt) 77 1.1 riastrad { 78 1.1 riastrad int err; 79 1.1 riastrad 80 1.1 riastrad if (!get_mocs_settings(gt->i915, &arg->table)) 81 1.1 riastrad return -EINVAL; 82 1.1 riastrad 83 1.1 riastrad arg->scratch = create_scratch(gt); 84 1.1 riastrad if (IS_ERR(arg->scratch)) 85 1.1 riastrad return PTR_ERR(arg->scratch); 86 1.1 riastrad 87 1.1 riastrad arg->vaddr = i915_gem_object_pin_map(arg->scratch->obj, I915_MAP_WB); 88 1.1 riastrad if (IS_ERR(arg->vaddr)) { 89 1.1 riastrad err = PTR_ERR(arg->vaddr); 90 1.1 riastrad goto err_scratch; 91 1.1 riastrad } 92 1.1 riastrad 93 1.1 riastrad return 0; 94 1.1 riastrad 95 1.1 riastrad err_scratch: 96 1.1 riastrad i915_vma_unpin_and_release(&arg->scratch, 0); 97 1.1 riastrad return err; 98 1.1 riastrad } 99 1.1 riastrad 100 1.1 riastrad static void live_mocs_fini(struct live_mocs *arg) 101 1.1 riastrad { 102 1.1 riastrad i915_vma_unpin_and_release(&arg->scratch, I915_VMA_RELEASE_MAP); 103 1.1 riastrad } 104 1.1 riastrad 105 1.1 riastrad static int read_regs(struct i915_request *rq, 106 1.1 riastrad u32 addr, unsigned int count, 107 1.1 riastrad uint32_t *offset) 108 1.1 riastrad { 109 1.1 riastrad unsigned int i; 110 1.1 riastrad u32 *cs; 111 1.1 riastrad 112 1.1 riastrad GEM_BUG_ON(!IS_ALIGNED(*offset, sizeof(u32))); 113 1.1 riastrad 114 1.1 riastrad cs = intel_ring_begin(rq, 4 * count); 115 1.1 riastrad if (IS_ERR(cs)) 116 1.1 riastrad return PTR_ERR(cs); 117 1.1 riastrad 118 1.1 riastrad for (i = 0; i < count; i++) { 119 1.1 riastrad *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT; 120 1.1 riastrad *cs++ = addr; 121 1.1 riastrad *cs++ = *offset; 122 1.1 riastrad *cs++ = 0; 123 1.1 riastrad 124 1.1 riastrad addr += sizeof(u32); 125 1.1 riastrad *offset += sizeof(u32); 126 1.1 riastrad } 127 1.1 riastrad 128 1.1 riastrad intel_ring_advance(rq, cs); 129 1.1 riastrad 130 1.1 riastrad return 0; 131 1.1 riastrad } 132 1.1 riastrad 133 1.1 riastrad static int read_mocs_table(struct i915_request *rq, 134 1.1 riastrad const struct drm_i915_mocs_table *table, 135 1.1 riastrad uint32_t *offset) 136 1.1 riastrad { 137 1.1 riastrad u32 addr; 138 1.1 riastrad 139 1.1 riastrad if (HAS_GLOBAL_MOCS_REGISTERS(rq->i915)) 140 1.1 riastrad addr = global_mocs_offset(); 141 1.1 riastrad else 142 1.1 riastrad addr = mocs_offset(rq->engine); 143 1.1 riastrad 144 1.1 riastrad return read_regs(rq, addr, table->n_entries, offset); 145 1.1 riastrad } 146 1.1 riastrad 147 1.1 riastrad static int read_l3cc_table(struct i915_request *rq, 148 1.1 riastrad const struct drm_i915_mocs_table *table, 149 1.1 riastrad uint32_t *offset) 150 1.1 riastrad { 151 1.1 riastrad u32 addr = i915_mmio_reg_offset(GEN9_LNCFCMOCS(0)); 152 1.1 riastrad 153 1.1 riastrad return read_regs(rq, addr, (table->n_entries + 1) / 2, offset); 154 1.1 riastrad } 155 1.1 riastrad 156 1.1 riastrad static int check_mocs_table(struct intel_engine_cs *engine, 157 1.1 riastrad const struct drm_i915_mocs_table *table, 158 1.1 riastrad uint32_t **vaddr) 159 1.1 riastrad { 160 1.1 riastrad unsigned int i; 161 1.1 riastrad u32 expect; 162 1.1 riastrad 163 1.1 riastrad for_each_mocs(expect, table, i) { 164 1.1 riastrad if (**vaddr != expect) { 165 1.1 riastrad pr_err("%s: Invalid MOCS[%d] entry, found %08x, expected %08x\n", 166 1.1 riastrad engine->name, i, **vaddr, expect); 167 1.1 riastrad return -EINVAL; 168 1.1 riastrad } 169 1.1 riastrad ++*vaddr; 170 1.1 riastrad } 171 1.1 riastrad 172 1.1 riastrad return 0; 173 1.1 riastrad } 174 1.1 riastrad 175 1.1 riastrad static bool mcr_range(struct drm_i915_private *i915, u32 offset) 176 1.1 riastrad { 177 1.1 riastrad /* 178 1.1 riastrad * Registers in this range are affected by the MCR selector 179 1.1 riastrad * which only controls CPU initiated MMIO. Routing does not 180 1.1 riastrad * work for CS access so we cannot verify them on this path. 181 1.1 riastrad */ 182 1.1 riastrad return INTEL_GEN(i915) >= 8 && offset >= 0xb000 && offset <= 0xb4ff; 183 1.1 riastrad } 184 1.1 riastrad 185 1.1 riastrad static int check_l3cc_table(struct intel_engine_cs *engine, 186 1.1 riastrad const struct drm_i915_mocs_table *table, 187 1.1 riastrad uint32_t **vaddr) 188 1.1 riastrad { 189 1.1 riastrad /* Can we read the MCR range 0xb00 directly? See intel_workarounds! */ 190 1.1 riastrad u32 reg = i915_mmio_reg_offset(GEN9_LNCFCMOCS(0)); 191 1.1 riastrad unsigned int i; 192 1.1 riastrad u32 expect; 193 1.1 riastrad 194 1.1 riastrad for_each_l3cc(expect, table, i) { 195 1.1 riastrad if (!mcr_range(engine->i915, reg) && **vaddr != expect) { 196 1.1 riastrad pr_err("%s: Invalid L3CC[%d] entry, found %08x, expected %08x\n", 197 1.1 riastrad engine->name, i, **vaddr, expect); 198 1.1 riastrad return -EINVAL; 199 1.1 riastrad } 200 1.1 riastrad ++*vaddr; 201 1.1 riastrad reg += 4; 202 1.1 riastrad } 203 1.1 riastrad 204 1.1 riastrad return 0; 205 1.1 riastrad } 206 1.1 riastrad 207 1.1 riastrad static int check_mocs_engine(struct live_mocs *arg, 208 1.1 riastrad struct intel_context *ce) 209 1.1 riastrad { 210 1.1 riastrad struct i915_vma *vma = arg->scratch; 211 1.1 riastrad struct i915_request *rq; 212 1.1 riastrad u32 offset; 213 1.1 riastrad u32 *vaddr; 214 1.1 riastrad int err; 215 1.1 riastrad 216 1.1 riastrad memset32(arg->vaddr, STACK_MAGIC, PAGE_SIZE / sizeof(u32)); 217 1.1 riastrad 218 1.1 riastrad rq = intel_context_create_request(ce); 219 1.1 riastrad if (IS_ERR(rq)) 220 1.1 riastrad return PTR_ERR(rq); 221 1.1 riastrad 222 1.1 riastrad i915_vma_lock(vma); 223 1.1 riastrad err = i915_request_await_object(rq, vma->obj, true); 224 1.1 riastrad if (!err) 225 1.1 riastrad err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); 226 1.1 riastrad i915_vma_unlock(vma); 227 1.1 riastrad 228 1.1 riastrad /* Read the mocs tables back using SRM */ 229 1.1 riastrad offset = i915_ggtt_offset(vma); 230 1.1 riastrad if (!err) 231 1.1 riastrad err = read_mocs_table(rq, &arg->table, &offset); 232 1.1 riastrad if (!err && ce->engine->class == RENDER_CLASS) 233 1.1 riastrad err = read_l3cc_table(rq, &arg->table, &offset); 234 1.1 riastrad offset -= i915_ggtt_offset(vma); 235 1.1 riastrad GEM_BUG_ON(offset > PAGE_SIZE); 236 1.1 riastrad 237 1.1 riastrad err = request_add_sync(rq, err); 238 1.1 riastrad if (err) 239 1.1 riastrad return err; 240 1.1 riastrad 241 1.1 riastrad /* Compare the results against the expected tables */ 242 1.1 riastrad vaddr = arg->vaddr; 243 1.1 riastrad if (!err) 244 1.1 riastrad err = check_mocs_table(ce->engine, &arg->table, &vaddr); 245 1.1 riastrad if (!err && ce->engine->class == RENDER_CLASS) 246 1.1 riastrad err = check_l3cc_table(ce->engine, &arg->table, &vaddr); 247 1.1 riastrad if (err) 248 1.1 riastrad return err; 249 1.1 riastrad 250 1.1 riastrad GEM_BUG_ON(arg->vaddr + offset != vaddr); 251 1.1 riastrad return 0; 252 1.1 riastrad } 253 1.1 riastrad 254 1.1 riastrad static int live_mocs_kernel(void *arg) 255 1.1 riastrad { 256 1.1 riastrad struct intel_gt *gt = arg; 257 1.1 riastrad struct intel_engine_cs *engine; 258 1.1 riastrad enum intel_engine_id id; 259 1.1 riastrad struct live_mocs mocs; 260 1.1 riastrad int err; 261 1.1 riastrad 262 1.1 riastrad /* Basic check the system is configured with the expected mocs table */ 263 1.1 riastrad 264 1.1 riastrad err = live_mocs_init(&mocs, gt); 265 1.1 riastrad if (err) 266 1.1 riastrad return err; 267 1.1 riastrad 268 1.1 riastrad for_each_engine(engine, gt, id) { 269 1.1 riastrad intel_engine_pm_get(engine); 270 1.1 riastrad err = check_mocs_engine(&mocs, engine->kernel_context); 271 1.1 riastrad intel_engine_pm_put(engine); 272 1.1 riastrad if (err) 273 1.1 riastrad break; 274 1.1 riastrad } 275 1.1 riastrad 276 1.1 riastrad live_mocs_fini(&mocs); 277 1.1 riastrad return err; 278 1.1 riastrad } 279 1.1 riastrad 280 1.1 riastrad static int live_mocs_clean(void *arg) 281 1.1 riastrad { 282 1.1 riastrad struct intel_gt *gt = arg; 283 1.1 riastrad struct intel_engine_cs *engine; 284 1.1 riastrad enum intel_engine_id id; 285 1.1 riastrad struct live_mocs mocs; 286 1.1 riastrad int err; 287 1.1 riastrad 288 1.1 riastrad /* Every new context should see the same mocs table */ 289 1.1 riastrad 290 1.1 riastrad err = live_mocs_init(&mocs, gt); 291 1.1 riastrad if (err) 292 1.1 riastrad return err; 293 1.1 riastrad 294 1.1 riastrad for_each_engine(engine, gt, id) { 295 1.1 riastrad struct intel_context *ce; 296 1.1 riastrad 297 1.1 riastrad ce = intel_context_create(engine); 298 1.1 riastrad if (IS_ERR(ce)) { 299 1.1 riastrad err = PTR_ERR(ce); 300 1.1 riastrad break; 301 1.1 riastrad } 302 1.1 riastrad 303 1.1 riastrad err = check_mocs_engine(&mocs, ce); 304 1.1 riastrad intel_context_put(ce); 305 1.1 riastrad if (err) 306 1.1 riastrad break; 307 1.1 riastrad } 308 1.1 riastrad 309 1.1 riastrad live_mocs_fini(&mocs); 310 1.1 riastrad return err; 311 1.1 riastrad } 312 1.1 riastrad 313 1.1 riastrad static int active_engine_reset(struct intel_context *ce, 314 1.1 riastrad const char *reason) 315 1.1 riastrad { 316 1.1 riastrad struct igt_spinner spin; 317 1.1 riastrad struct i915_request *rq; 318 1.1 riastrad int err; 319 1.1 riastrad 320 1.1 riastrad err = igt_spinner_init(&spin, ce->engine->gt); 321 1.1 riastrad if (err) 322 1.1 riastrad return err; 323 1.1 riastrad 324 1.1 riastrad rq = igt_spinner_create_request(&spin, ce, MI_NOOP); 325 1.1 riastrad if (IS_ERR(rq)) { 326 1.1 riastrad igt_spinner_fini(&spin); 327 1.1 riastrad return PTR_ERR(rq); 328 1.1 riastrad } 329 1.1 riastrad 330 1.1 riastrad err = request_add_spin(rq, &spin); 331 1.1 riastrad if (err == 0) 332 1.1 riastrad err = intel_engine_reset(ce->engine, reason); 333 1.1 riastrad 334 1.1 riastrad igt_spinner_end(&spin); 335 1.1 riastrad igt_spinner_fini(&spin); 336 1.1 riastrad 337 1.1 riastrad return err; 338 1.1 riastrad } 339 1.1 riastrad 340 1.1 riastrad static int __live_mocs_reset(struct live_mocs *mocs, 341 1.1 riastrad struct intel_context *ce) 342 1.1 riastrad { 343 1.1 riastrad int err; 344 1.1 riastrad 345 1.1 riastrad err = intel_engine_reset(ce->engine, "mocs"); 346 1.1 riastrad if (err) 347 1.1 riastrad return err; 348 1.1 riastrad 349 1.1 riastrad err = check_mocs_engine(mocs, ce); 350 1.1 riastrad if (err) 351 1.1 riastrad return err; 352 1.1 riastrad 353 1.1 riastrad err = active_engine_reset(ce, "mocs"); 354 1.1 riastrad if (err) 355 1.1 riastrad return err; 356 1.1 riastrad 357 1.1 riastrad err = check_mocs_engine(mocs, ce); 358 1.1 riastrad if (err) 359 1.1 riastrad return err; 360 1.1 riastrad 361 1.1 riastrad intel_gt_reset(ce->engine->gt, ce->engine->mask, "mocs"); 362 1.1 riastrad 363 1.1 riastrad err = check_mocs_engine(mocs, ce); 364 1.1 riastrad if (err) 365 1.1 riastrad return err; 366 1.1 riastrad 367 1.1 riastrad return 0; 368 1.1 riastrad } 369 1.1 riastrad 370 1.1 riastrad static int live_mocs_reset(void *arg) 371 1.1 riastrad { 372 1.1 riastrad struct intel_gt *gt = arg; 373 1.1 riastrad struct intel_engine_cs *engine; 374 1.1 riastrad enum intel_engine_id id; 375 1.1 riastrad struct live_mocs mocs; 376 1.1 riastrad int err = 0; 377 1.1 riastrad 378 1.1 riastrad /* Check the mocs setup is retained over per-engine and global resets */ 379 1.1 riastrad 380 1.1 riastrad if (!intel_has_reset_engine(gt)) 381 1.1 riastrad return 0; 382 1.1 riastrad 383 1.1 riastrad err = live_mocs_init(&mocs, gt); 384 1.1 riastrad if (err) 385 1.1 riastrad return err; 386 1.1 riastrad 387 1.1 riastrad igt_global_reset_lock(gt); 388 1.1 riastrad for_each_engine(engine, gt, id) { 389 1.1 riastrad struct intel_context *ce; 390 1.1 riastrad 391 1.1 riastrad ce = intel_context_create(engine); 392 1.1 riastrad if (IS_ERR(ce)) { 393 1.1 riastrad err = PTR_ERR(ce); 394 1.1 riastrad break; 395 1.1 riastrad } 396 1.1 riastrad 397 1.1 riastrad intel_engine_pm_get(engine); 398 1.1 riastrad err = __live_mocs_reset(&mocs, ce); 399 1.1 riastrad intel_engine_pm_put(engine); 400 1.1 riastrad 401 1.1 riastrad intel_context_put(ce); 402 1.1 riastrad if (err) 403 1.1 riastrad break; 404 1.1 riastrad } 405 1.1 riastrad igt_global_reset_unlock(gt); 406 1.1 riastrad 407 1.1 riastrad live_mocs_fini(&mocs); 408 1.1 riastrad return err; 409 1.1 riastrad } 410 1.1 riastrad 411 1.1 riastrad int intel_mocs_live_selftests(struct drm_i915_private *i915) 412 1.1 riastrad { 413 1.1 riastrad static const struct i915_subtest tests[] = { 414 1.1 riastrad SUBTEST(live_mocs_kernel), 415 1.1 riastrad SUBTEST(live_mocs_clean), 416 1.1 riastrad SUBTEST(live_mocs_reset), 417 1.1 riastrad }; 418 1.1 riastrad struct drm_i915_mocs_table table; 419 1.1 riastrad 420 1.1 riastrad if (!get_mocs_settings(i915, &table)) 421 1.1 riastrad return 0; 422 1.1 riastrad 423 1.1 riastrad return intel_gt_live_subtests(tests, &i915->gt); 424 1.1 riastrad } 425