1 /* 2 * SPDX-License-Identifier: MIT 3 * 4 * Copyright © 2019 Intel Corporation 5 */ 6 7 #include <linux/kref.h> 8 9 #include "gem/i915_gem_pm.h" 10 #include "gt/intel_gt.h" 11 12 #include "i915_selftest.h" 13 14 #include "igt_flush_test.h" 15 #include "lib_sw_fence.h" 16 17 #define TEST_OA_CONFIG_UUID "12345678-1234-1234-1234-1234567890ab" 18 19 static int 20 alloc_empty_config(struct i915_perf *perf) 21 { 22 struct i915_oa_config *oa_config; 23 24 oa_config = kzalloc(sizeof(*oa_config), GFP_KERNEL); 25 if (!oa_config) 26 return -ENOMEM; 27 28 oa_config->perf = perf; 29 kref_init(&oa_config->ref); 30 31 strlcpy(oa_config->uuid, TEST_OA_CONFIG_UUID, sizeof(oa_config->uuid)); 32 33 mutex_lock(&perf->metrics_lock); 34 35 oa_config->id = idr_alloc(&perf->metrics_idr, oa_config, 2, 0, GFP_KERNEL); 36 if (oa_config->id < 0) { 37 mutex_unlock(&perf->metrics_lock); 38 i915_oa_config_put(oa_config); 39 return -ENOMEM; 40 } 41 42 mutex_unlock(&perf->metrics_lock); 43 44 return 0; 45 } 46 47 static void 48 destroy_empty_config(struct i915_perf *perf) 49 { 50 struct i915_oa_config *oa_config = NULL, *tmp; 51 int id; 52 53 mutex_lock(&perf->metrics_lock); 54 55 idr_for_each_entry(&perf->metrics_idr, tmp, id) { 56 if (!strcmp(tmp->uuid, TEST_OA_CONFIG_UUID)) { 57 oa_config = tmp; 58 break; 59 } 60 } 61 62 if (oa_config) 63 idr_remove(&perf->metrics_idr, oa_config->id); 64 65 mutex_unlock(&perf->metrics_lock); 66 67 if (oa_config) 68 i915_oa_config_put(oa_config); 69 } 70 71 static struct i915_oa_config * 72 get_empty_config(struct i915_perf *perf) 73 { 74 struct i915_oa_config *oa_config = NULL, *tmp; 75 int id; 76 77 mutex_lock(&perf->metrics_lock); 78 79 idr_for_each_entry(&perf->metrics_idr, tmp, id) { 80 if (!strcmp(tmp->uuid, TEST_OA_CONFIG_UUID)) { 81 oa_config = i915_oa_config_get(tmp); 82 break; 83 } 84 } 85 86 mutex_unlock(&perf->metrics_lock); 87 88 return oa_config; 89 } 90 91 static struct i915_perf_stream * 92 test_stream(struct i915_perf *perf) 93 { 94 struct drm_i915_perf_open_param param = {}; 95 struct i915_oa_config *oa_config = get_empty_config(perf); 96 struct perf_open_properties props = { 97 .engine = intel_engine_lookup_user(perf->i915, 98 I915_ENGINE_CLASS_RENDER, 99 0), 100 .sample_flags = SAMPLE_OA_REPORT, 101 .oa_format = IS_GEN(perf->i915, 12) ? 102 I915_OA_FORMAT_A32u40_A4u32_B8_C8 : I915_OA_FORMAT_C4_B8, 103 }; 104 struct i915_perf_stream *stream; 105 106 if (!oa_config) 107 return NULL; 108 109 props.metrics_set = oa_config->id; 110 111 stream = kzalloc(sizeof(*stream), GFP_KERNEL); 112 if (!stream) { 113 i915_oa_config_put(oa_config); 114 return NULL; 115 } 116 117 stream->perf = perf; 118 119 mutex_lock(&perf->lock); 120 if (i915_oa_stream_init(stream, ¶m, &props)) { 121 kfree(stream); 122 stream = NULL; 123 } 124 mutex_unlock(&perf->lock); 125 126 i915_oa_config_put(oa_config); 127 128 return stream; 129 } 130 131 static void stream_destroy(struct i915_perf_stream *stream) 132 { 133 struct i915_perf *perf = stream->perf; 134 135 mutex_lock(&perf->lock); 136 i915_perf_destroy_locked(stream); 137 mutex_unlock(&perf->lock); 138 } 139 140 static int live_sanitycheck(void *arg) 141 { 142 struct drm_i915_private *i915 = arg; 143 struct i915_perf_stream *stream; 144 145 /* Quick check we can create a perf stream */ 146 147 stream = test_stream(&i915->perf); 148 if (!stream) 149 return -EINVAL; 150 151 stream_destroy(stream); 152 return 0; 153 } 154 155 static int write_timestamp(struct i915_request *rq, int slot) 156 { 157 u32 *cs; 158 int len; 159 160 cs = intel_ring_begin(rq, 6); 161 if (IS_ERR(cs)) 162 return PTR_ERR(cs); 163 164 len = 5; 165 if (INTEL_GEN(rq->i915) >= 8) 166 len++; 167 168 *cs++ = GFX_OP_PIPE_CONTROL(len); 169 *cs++ = PIPE_CONTROL_GLOBAL_GTT_IVB | 170 PIPE_CONTROL_STORE_DATA_INDEX | 171 PIPE_CONTROL_WRITE_TIMESTAMP; 172 *cs++ = slot * sizeof(u32); 173 *cs++ = 0; 174 *cs++ = 0; 175 *cs++ = 0; 176 177 intel_ring_advance(rq, cs); 178 179 return 0; 180 } 181 182 static ktime_t poll_status(struct i915_request *rq, int slot) 183 { 184 while (!intel_read_status_page(rq->engine, slot) && 185 !i915_request_completed(rq)) 186 cpu_relax(); 187 188 return ktime_get(); 189 } 190 191 static int live_noa_delay(void *arg) 192 { 193 struct drm_i915_private *i915 = arg; 194 struct i915_perf_stream *stream; 195 struct i915_request *rq; 196 ktime_t t0, t1; 197 u64 expected; 198 u32 delay; 199 int err; 200 int i; 201 202 /* Check that the GPU delays matches expectations */ 203 204 stream = test_stream(&i915->perf); 205 if (!stream) 206 return -ENOMEM; 207 208 expected = atomic64_read(&stream->perf->noa_programming_delay); 209 210 if (stream->engine->class != RENDER_CLASS) { 211 err = -ENODEV; 212 goto out; 213 } 214 215 for (i = 0; i < 4; i++) 216 intel_write_status_page(stream->engine, 0x100 + i, 0); 217 218 rq = intel_engine_create_kernel_request(stream->engine); 219 if (IS_ERR(rq)) { 220 err = PTR_ERR(rq); 221 goto out; 222 } 223 224 if (rq->engine->emit_init_breadcrumb) { 225 err = rq->engine->emit_init_breadcrumb(rq); 226 if (err) { 227 i915_request_add(rq); 228 goto out; 229 } 230 } 231 232 err = write_timestamp(rq, 0x100); 233 if (err) { 234 i915_request_add(rq); 235 goto out; 236 } 237 238 err = rq->engine->emit_bb_start(rq, 239 i915_ggtt_offset(stream->noa_wait), 0, 240 I915_DISPATCH_SECURE); 241 if (err) { 242 i915_request_add(rq); 243 goto out; 244 } 245 246 err = write_timestamp(rq, 0x102); 247 if (err) { 248 i915_request_add(rq); 249 goto out; 250 } 251 252 i915_request_get(rq); 253 i915_request_add(rq); 254 255 preempt_disable(); 256 t0 = poll_status(rq, 0x100); 257 t1 = poll_status(rq, 0x102); 258 preempt_enable(); 259 260 pr_info("CPU delay: %lluns, expected %lluns\n", 261 ktime_sub(t1, t0), expected); 262 263 delay = intel_read_status_page(stream->engine, 0x102); 264 delay -= intel_read_status_page(stream->engine, 0x100); 265 delay = i915_cs_timestamp_ticks_to_ns(i915, delay); 266 pr_info("GPU delay: %uns, expected %lluns\n", 267 delay, expected); 268 269 if (4 * delay < 3 * expected || 2 * delay > 3 * expected) { 270 pr_err("GPU delay [%uus] outside of expected threshold! [%lluus, %lluus]\n", 271 delay / 1000, 272 div_u64(3 * expected, 4000), 273 div_u64(3 * expected, 2000)); 274 err = -EINVAL; 275 } 276 277 i915_request_put(rq); 278 out: 279 stream_destroy(stream); 280 return err; 281 } 282 283 int i915_perf_live_selftests(struct drm_i915_private *i915) 284 { 285 static const struct i915_subtest tests[] = { 286 SUBTEST(live_sanitycheck), 287 SUBTEST(live_noa_delay), 288 }; 289 struct i915_perf *perf = &i915->perf; 290 int err; 291 292 if (!perf->metrics_kobj || !perf->ops.enable_metric_set) 293 return 0; 294 295 if (intel_gt_is_wedged(&i915->gt)) 296 return 0; 297 298 err = alloc_empty_config(&i915->perf); 299 if (err) 300 return err; 301 302 err = i915_subtests(tests, i915); 303 304 destroy_empty_config(&i915->perf); 305 306 return err; 307 } 308