0001
0002
0003
0004
0005
0006 #include "gt/intel_gpu_commands.h"
0007 #include "gt/intel_gt.h"
0008
0009 #include "gem/i915_gem_internal.h"
0010 #include "gem/selftests/igt_gem_utils.h"
0011
0012 #include "igt_spinner.h"
0013
0014 int igt_spinner_init(struct igt_spinner *spin, struct intel_gt *gt)
0015 {
0016 int err;
0017
0018 memset(spin, 0, sizeof(*spin));
0019 spin->gt = gt;
0020
0021 spin->hws = i915_gem_object_create_internal(gt->i915, PAGE_SIZE);
0022 if (IS_ERR(spin->hws)) {
0023 err = PTR_ERR(spin->hws);
0024 goto err;
0025 }
0026 i915_gem_object_set_cache_coherency(spin->hws, I915_CACHE_LLC);
0027
0028 spin->obj = i915_gem_object_create_internal(gt->i915, PAGE_SIZE);
0029 if (IS_ERR(spin->obj)) {
0030 err = PTR_ERR(spin->obj);
0031 goto err_hws;
0032 }
0033
0034 return 0;
0035
0036 err_hws:
0037 i915_gem_object_put(spin->hws);
0038 err:
0039 return err;
0040 }
0041
0042 static void *igt_spinner_pin_obj(struct intel_context *ce,
0043 struct i915_gem_ww_ctx *ww,
0044 struct drm_i915_gem_object *obj,
0045 unsigned int mode, struct i915_vma **vma)
0046 {
0047 void *vaddr;
0048 int ret;
0049
0050 *vma = i915_vma_instance(obj, ce->vm, NULL);
0051 if (IS_ERR(*vma))
0052 return ERR_CAST(*vma);
0053
0054 ret = i915_gem_object_lock(obj, ww);
0055 if (ret)
0056 return ERR_PTR(ret);
0057
0058 vaddr = i915_gem_object_pin_map(obj, mode);
0059
0060 if (!ww)
0061 i915_gem_object_unlock(obj);
0062
0063 if (IS_ERR(vaddr))
0064 return vaddr;
0065
0066 if (ww)
0067 ret = i915_vma_pin_ww(*vma, ww, 0, 0, PIN_USER);
0068 else
0069 ret = i915_vma_pin(*vma, 0, 0, PIN_USER);
0070
0071 if (ret) {
0072 i915_gem_object_unpin_map(obj);
0073 return ERR_PTR(ret);
0074 }
0075
0076 return vaddr;
0077 }
0078
0079 int igt_spinner_pin(struct igt_spinner *spin,
0080 struct intel_context *ce,
0081 struct i915_gem_ww_ctx *ww)
0082 {
0083 void *vaddr;
0084
0085 if (spin->ce && WARN_ON(spin->ce != ce))
0086 return -ENODEV;
0087 spin->ce = ce;
0088
0089 if (!spin->seqno) {
0090 vaddr = igt_spinner_pin_obj(ce, ww, spin->hws, I915_MAP_WB, &spin->hws_vma);
0091 if (IS_ERR(vaddr))
0092 return PTR_ERR(vaddr);
0093
0094 spin->seqno = memset(vaddr, 0xff, PAGE_SIZE);
0095 }
0096
0097 if (!spin->batch) {
0098 unsigned int mode;
0099
0100 mode = i915_coherent_map_type(spin->gt->i915, spin->obj, false);
0101 vaddr = igt_spinner_pin_obj(ce, ww, spin->obj, mode, &spin->batch_vma);
0102 if (IS_ERR(vaddr))
0103 return PTR_ERR(vaddr);
0104
0105 spin->batch = vaddr;
0106 }
0107
0108 return 0;
0109 }
0110
0111 static unsigned int seqno_offset(u64 fence)
0112 {
0113 return offset_in_page(sizeof(u32) * fence);
0114 }
0115
0116 static u64 hws_address(const struct i915_vma *hws,
0117 const struct i915_request *rq)
0118 {
0119 return hws->node.start + seqno_offset(rq->fence.context);
0120 }
0121
0122 static int move_to_active(struct i915_vma *vma,
0123 struct i915_request *rq,
0124 unsigned int flags)
0125 {
0126 int err;
0127
0128 i915_vma_lock(vma);
0129 err = i915_request_await_object(rq, vma->obj,
0130 flags & EXEC_OBJECT_WRITE);
0131 if (err == 0)
0132 err = i915_vma_move_to_active(vma, rq, flags);
0133 i915_vma_unlock(vma);
0134
0135 return err;
0136 }
0137
0138 struct i915_request *
0139 igt_spinner_create_request(struct igt_spinner *spin,
0140 struct intel_context *ce,
0141 u32 arbitration_command)
0142 {
0143 struct intel_engine_cs *engine = ce->engine;
0144 struct i915_request *rq = NULL;
0145 struct i915_vma *hws, *vma;
0146 unsigned int flags;
0147 u32 *batch;
0148 int err;
0149
0150 GEM_BUG_ON(spin->gt != ce->vm->gt);
0151
0152 if (!intel_engine_can_store_dword(ce->engine))
0153 return ERR_PTR(-ENODEV);
0154
0155 if (!spin->batch) {
0156 err = igt_spinner_pin(spin, ce, NULL);
0157 if (err)
0158 return ERR_PTR(err);
0159 }
0160
0161 hws = spin->hws_vma;
0162 vma = spin->batch_vma;
0163
0164 rq = intel_context_create_request(ce);
0165 if (IS_ERR(rq))
0166 return ERR_CAST(rq);
0167
0168 err = move_to_active(vma, rq, 0);
0169 if (err)
0170 goto cancel_rq;
0171
0172 err = move_to_active(hws, rq, 0);
0173 if (err)
0174 goto cancel_rq;
0175
0176 batch = spin->batch;
0177
0178 if (GRAPHICS_VER(rq->engine->i915) >= 8) {
0179 *batch++ = MI_STORE_DWORD_IMM_GEN4;
0180 *batch++ = lower_32_bits(hws_address(hws, rq));
0181 *batch++ = upper_32_bits(hws_address(hws, rq));
0182 } else if (GRAPHICS_VER(rq->engine->i915) >= 6) {
0183 *batch++ = MI_STORE_DWORD_IMM_GEN4;
0184 *batch++ = 0;
0185 *batch++ = hws_address(hws, rq);
0186 } else if (GRAPHICS_VER(rq->engine->i915) >= 4) {
0187 *batch++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
0188 *batch++ = 0;
0189 *batch++ = hws_address(hws, rq);
0190 } else {
0191 *batch++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL;
0192 *batch++ = hws_address(hws, rq);
0193 }
0194 *batch++ = rq->fence.seqno;
0195
0196 *batch++ = arbitration_command;
0197
0198 if (GRAPHICS_VER(rq->engine->i915) >= 8)
0199 *batch++ = MI_BATCH_BUFFER_START | BIT(8) | 1;
0200 else if (IS_HASWELL(rq->engine->i915))
0201 *batch++ = MI_BATCH_BUFFER_START | MI_BATCH_PPGTT_HSW;
0202 else if (GRAPHICS_VER(rq->engine->i915) >= 6)
0203 *batch++ = MI_BATCH_BUFFER_START;
0204 else
0205 *batch++ = MI_BATCH_BUFFER_START | MI_BATCH_GTT;
0206 *batch++ = lower_32_bits(vma->node.start);
0207 *batch++ = upper_32_bits(vma->node.start);
0208
0209 *batch++ = MI_BATCH_BUFFER_END;
0210
0211 intel_gt_chipset_flush(engine->gt);
0212
0213 if (engine->emit_init_breadcrumb) {
0214 err = engine->emit_init_breadcrumb(rq);
0215 if (err)
0216 goto cancel_rq;
0217 }
0218
0219 flags = 0;
0220 if (GRAPHICS_VER(rq->engine->i915) <= 5)
0221 flags |= I915_DISPATCH_SECURE;
0222 err = engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, flags);
0223
0224 cancel_rq:
0225 if (err) {
0226 i915_request_set_error_once(rq, err);
0227 i915_request_add(rq);
0228 }
0229 return err ? ERR_PTR(err) : rq;
0230 }
0231
0232 static u32
0233 hws_seqno(const struct igt_spinner *spin, const struct i915_request *rq)
0234 {
0235 u32 *seqno = spin->seqno + seqno_offset(rq->fence.context);
0236
0237 return READ_ONCE(*seqno);
0238 }
0239
0240 void igt_spinner_end(struct igt_spinner *spin)
0241 {
0242 if (!spin->batch)
0243 return;
0244
0245 *spin->batch = MI_BATCH_BUFFER_END;
0246 intel_gt_chipset_flush(spin->gt);
0247 }
0248
0249 void igt_spinner_fini(struct igt_spinner *spin)
0250 {
0251 igt_spinner_end(spin);
0252
0253 if (spin->batch) {
0254 i915_vma_unpin(spin->batch_vma);
0255 i915_gem_object_unpin_map(spin->obj);
0256 }
0257 i915_gem_object_put(spin->obj);
0258
0259 if (spin->seqno) {
0260 i915_vma_unpin(spin->hws_vma);
0261 i915_gem_object_unpin_map(spin->hws);
0262 }
0263 i915_gem_object_put(spin->hws);
0264 }
0265
0266 bool igt_wait_for_spinner(struct igt_spinner *spin, struct i915_request *rq)
0267 {
0268 if (i915_request_is_ready(rq))
0269 intel_engine_flush_submission(rq->engine);
0270
0271 return !(wait_for_us(i915_seqno_passed(hws_seqno(spin, rq),
0272 rq->fence.seqno),
0273 100) &&
0274 wait_for(i915_seqno_passed(hws_seqno(spin, rq),
0275 rq->fence.seqno),
0276 50));
0277 }