diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/intel/xe_oa.c | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/tests/intel/xe_oa.c b/tests/intel/xe_oa.c index badd29ba0..b83e7f5ea 100644 --- a/tests/intel/xe_oa.c +++ b/tests/intel/xe_oa.c @@ -3805,6 +3805,317 @@ test_whitelisted_registers_userspace_config(void) xe_oa_remove_config(drm_fd, config_id); } +#define OAG_OASTATUS (0xdafc) +#define OAG_MMIOTRIGGER (0xdb1c) + +static const uint32_t oa_wl[] = { + OAG_MMIOTRIGGER, + OAG_OASTATUS, +}; + +static const uint32_t nonpriv_slot_offsets[] = { + 0x4d0, 0x4d4, 0x4d8, 0x4dc, 0x4e0, 0x4e4, 0x4e8, 0x4ec, + 0x4f0, 0x4f4, 0x4f8, 0x4fc, 0x010, 0x014, 0x018, 0x01c, + 0x1e0, 0x1e4, 0x1e8, 0x1ec, +}; + +struct test_perf { + const uint32_t *slots; + uint32_t num_slots; + const uint32_t *wl; + uint32_t num_wl; +} perf; + +#define HAS_OA_MMIO_TRIGGER(__d) \ + (IS_DG2(__d) || IS_PONTEVECCHIO(__d) || IS_METEORLAKE(__d) || \ + intel_graphics_ver(devid) >= IP_VER(20, 0)) + +static void perf_init_whitelist(void) +{ + perf.slots = nonpriv_slot_offsets; + perf.num_slots = 20; + perf.wl = oa_wl; + perf.num_wl = ARRAY_SIZE(oa_wl); +} + +static void +emit_oa_reg_read(struct intel_bb *ibb, struct intel_buf *dst, uint32_t offset, + uint32_t reg) +{ + intel_bb_add_intel_buf(ibb, dst, true); + + intel_bb_out(ibb, MI_STORE_REGISTER_MEM | 2); + intel_bb_out(ibb, reg); + intel_bb_emit_reloc(ibb, dst->handle, + I915_GEM_DOMAIN_INSTRUCTION, + I915_GEM_DOMAIN_INSTRUCTION, + offset, dst->addr.offset); + intel_bb_out(ibb, lower_32_bits(offset)); + intel_bb_out(ibb, upper_32_bits(offset)); +} + +static void +emit_mmio_triggered_report(struct intel_bb *ibb, uint32_t value) +{ + intel_bb_out(ibb, MI_LOAD_REGISTER_IMM(1)); + intel_bb_out(ibb, OAG_MMIOTRIGGER); + intel_bb_out(ibb, value); +} + +static void dump_whitelist(uint32_t mmio_base, const char *msg) +{ + int i; + + igt_debug("%s\n", msg); + + for (i = 0; i < perf.num_slots; i++) + igt_debug("FORCE_TO_NON_PRIV_%02d = %08x\n", + i, intel_register_read(&mmio_data, + mmio_base + perf.slots[i])); +} + +static bool in_whitelist(uint32_t mmio_base, uint32_t reg) +{ + int i; + + if (reg & MMIO_BASE_OFFSET) + reg = (reg & ~MMIO_BASE_OFFSET) + mmio_base; + + for (i = 0; i < perf.num_slots; i++) { + uint32_t fpriv = intel_register_read(&mmio_data, + mmio_base + perf.slots[i]); + + if ((fpriv & RING_FORCE_TO_NONPRIV_ADDRESS_MASK) == reg) + return true; + } + + return false; +} + +static void oa_regs_in_whitelist(uint32_t mmio_base, bool are_present) +{ + int i; + + if (are_present) { + for (i = 0; i < perf.num_wl; i++) + igt_assert(in_whitelist(mmio_base, perf.wl[i])); + } else { + for (i = 0; i < perf.num_wl; i++) + igt_assert(!in_whitelist(mmio_base, perf.wl[i])); + } +} + +static u32 oa_get_mmio_base(const struct drm_xe_engine_class_instance *hwe) +{ + u32 mmio_base = 0x2000; + + switch (hwe->engine_class) { + case DRM_XE_ENGINE_CLASS_RENDER: + mmio_base = 0x2000; + break; + case DRM_XE_ENGINE_CLASS_COMPUTE: + switch (hwe->engine_instance) { + case 0: + mmio_base = 0x1a000; + break; + case 1: + mmio_base = 0x1c000; + break; + case 2: + mmio_base = 0x1e000; + break; + case 3: + mmio_base = 0x26000; + break; + } + } + + return mmio_base; +} + +/** + * SUBTEST: oa-regs-whitelisted + * Description: Verify that OA registers are whitelisted + */ +static void test_oa_regs_whitelist(const struct drm_xe_engine_class_instance *hwe) +{ + struct intel_xe_perf_metric_set *test_set = metric_set(hwe); + uint64_t properties[] = { + DRM_XE_OA_PROPERTY_OA_UNIT_ID, 0, + DRM_XE_OA_PROPERTY_SAMPLE_OA, true, + DRM_XE_OA_PROPERTY_OA_METRIC_SET, test_set->perf_oa_metrics_set, + DRM_XE_OA_PROPERTY_OA_FORMAT, __ff(test_set->perf_oa_format), + DRM_XE_OA_PROPERTY_OA_PERIOD_EXPONENT, oa_exp_1_millisec, + }; + struct intel_xe_oa_open_prop param = { + .num_properties = sizeof(properties) / 16, + .properties_ptr = to_user_pointer(properties), + }; + // uint32_t mmio_base = gem_engine_mmio_base(drm_fd, e->name); + u32 mmio_base; + + /* FIXME: Add support for OAM whitelist testing */ + if (hwe->engine_class != DRM_XE_ENGINE_CLASS_RENDER && + hwe->engine_class != DRM_XE_ENGINE_CLASS_COMPUTE) + return; + + mmio_base = oa_get_mmio_base(hwe); + + intel_register_access_init(&mmio_data, + igt_device_get_pci_device(drm_fd), + 0, drm_fd); + stream_fd = __perf_open(drm_fd, ¶m, false); + + dump_whitelist(mmio_base, "oa whitelisted"); + + oa_regs_in_whitelist(mmio_base, true); + + __perf_close(stream_fd); + + dump_whitelist(mmio_base, "oa remove whitelist"); + + /* + * after perf close, check that registers are removed from the nonpriv + * slots + * FIXME if needed: currently regs remain added forever + */ + // oa_regs_in_whitelist(mmio_base, false); + + intel_register_access_fini(&mmio_data); +} + +static void +__test_mmio_triggered_reports(struct drm_xe_engine_class_instance *hwe) +{ + struct intel_xe_perf_metric_set *test_set = default_test_set; + int oa_exponent = max_oa_exponent_for_period_lte(2 * NSEC_PER_SEC); + uint64_t properties[] = { + DRM_XE_OA_PROPERTY_SAMPLE_OA, true, + DRM_XE_OA_PROPERTY_OA_METRIC_SET, test_set->perf_oa_metrics_set, + DRM_XE_OA_PROPERTY_OA_FORMAT, __ff(test_set->perf_oa_format), + DRM_XE_OA_PROPERTY_OA_PERIOD_EXPONENT, oa_exponent, + DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE, hwe->engine_instance, + }; + struct intel_xe_oa_open_prop param = { + .num_properties = sizeof(properties) / 16, + .properties_ptr = to_user_pointer(properties), + }; + size_t format_size = get_oa_format(test_set->perf_oa_format).size; + uint32_t oa_buffer, offset_tail1, offset_tail2; + struct intel_buf src, dst, *dst_buf; + uint32_t mmio_triggered_reports = 0; + uint32_t *start, *end; + struct buf_ops *bops; + struct intel_bb *ibb; + uint32_t context, vm; + int height = 600; + int width = 800; + uint8_t *buf; + + bops = buf_ops_create(drm_fd); + + dst_buf = intel_buf_create(bops, 4096, 1, 8, 64, + I915_TILING_NONE, + I915_COMPRESSION_NONE); + buf_map(drm_fd, dst_buf, true); + memset(dst_buf->ptr, 0, 4096); + intel_buf_unmap(dst_buf); + + scratch_buf_init(bops, &src, width, height, 0xff0000ff); + scratch_buf_init(bops, &dst, width, height, 0x00ff00ff); + + vm = xe_vm_create(drm_fd, 0, 0); + context = xe_exec_queue_create(drm_fd, vm, hwe, 0); + igt_assert(context); + ibb = intel_bb_create_with_context(drm_fd, context, vm, NULL, BATCH_SZ); + + stream_fd = __perf_open(drm_fd, ¶m, false); + set_fd_flags(stream_fd, O_CLOEXEC); + + buf = mmap(0, OA_BUFFER_SIZE, PROT_READ, MAP_PRIVATE, stream_fd, 0); + igt_assert(buf != NULL); + + emit_oa_reg_read(ibb, dst_buf, 0, OAG_OABUFFER); + emit_oa_reg_read(ibb, dst_buf, 4, OAG_OATAILPTR); + emit_mmio_triggered_report(ibb, 0xc0ffee11); + + if (render_copy) + render_copy(ibb, + &src, 0, 0, width, height, + &dst, 0, 0); + + emit_mmio_triggered_report(ibb, 0xc0ffee22); + + emit_oa_reg_read(ibb, dst_buf, 8, OAG_OATAILPTR); + + intel_bb_flush_render(ibb); + intel_bb_sync(ibb); + + buf_map(drm_fd, dst_buf, false); + + oa_buffer = dst_buf->ptr[0] & OAG_OATAILPTR_MASK; + offset_tail1 = (dst_buf->ptr[1] & OAG_OATAILPTR_MASK) - oa_buffer; + offset_tail2 = (dst_buf->ptr[2] & OAG_OATAILPTR_MASK) - oa_buffer; + + igt_debug("oa_buffer = %08x, tail1 = %08x, tail2 = %08x\n", + oa_buffer, offset_tail1, offset_tail2); + + start = (uint32_t *)(buf + offset_tail1); + end = (uint32_t *)(buf + offset_tail2); + while (start < end) { + if (!report_reason(start)) + mmio_triggered_reports++; + + if (get_oa_format(test_set->perf_oa_format).report_hdr_64bit) { + u64 *start64 = (u64 *)start; + + igt_debug("hdr: %016lx %016lx %016lx %016lx\n", + start64[0], start64[1], start64[2], start64[3]); + } else { + igt_debug("hdr: %08x %08x %08x %08x\n", + start[0], start[1], start[2], start[3]); + } + + start += format_size / 4; + } + + igt_assert_eq(mmio_triggered_reports, 2); + + munmap(buf, OA_BUFFER_SIZE); + intel_buf_close(bops, &src); + intel_buf_close(bops, &dst); + intel_buf_unmap(dst_buf); + intel_buf_destroy(dst_buf); + intel_bb_destroy(ibb); + xe_exec_queue_destroy(drm_fd, context); + xe_vm_destroy(drm_fd, vm); + buf_ops_destroy(bops); + __perf_close(stream_fd); +} + +/** + * SUBTEST: mmio-triggered-reports + * Description: Test MMIO trigger functionality + */ +static void +test_mmio_triggered_reports(struct drm_xe_engine_class_instance *hwe) +{ + struct igt_helper_process child = {}; + int ret; + + write_u64_file("/proc/sys/dev/xe/observation_paranoid", 0); + igt_fork_helper(&child) { + igt_drop_root(); + + __test_mmio_triggered_reports(hwe); + } + ret = igt_wait_helper(&child); + write_u64_file("/proc/sys/dev/xe/observation_paranoid", 1); + + igt_assert(WEXITSTATUS(ret) == EAGAIN || + WEXITSTATUS(ret) == 0); +} + /** * SUBTEST: xe-ref-count * Description: Check that an open oa stream holds a reference on the xe module @@ -4478,6 +4789,22 @@ igt_main closed_fd_and_unmapped_access(hwe); } + igt_subtest_group { + igt_fixture { + perf_init_whitelist(); + } + + igt_subtest_with_dynamic("oa-regs-whitelisted") + __for_one_hwe_in_oag(hwe) + test_oa_regs_whitelist(hwe); + + igt_subtest_with_dynamic("mmio-triggered-reports") { + igt_require(HAS_OA_MMIO_TRIGGER(devid)); + __for_one_hwe_in_oag(hwe) + test_mmio_triggered_reports(hwe); + } + } + igt_fixture { /* leave sysctl options in their default state... */ write_u64_file("/proc/sys/dev/xe/observation_paranoid", 1); |