1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2019 Intel Corporation
4  */
5 
6 #include "i915_drv.h"
7 #include "i915_vma.h"
8 #include "intel_context.h"
9 #include "intel_engine_pm.h"
10 #include "intel_gpu_commands.h"
11 #include "intel_lrc.h"
12 #include "intel_ring.h"
13 #include "intel_sseu.h"
14 
15 static int gen8_emit_rpcs_config(struct i915_request *rq,
16 				 const struct intel_context *ce,
17 				 const struct intel_sseu sseu)
18 {
19 	u64 offset;
20 	u32 *cs;
21 
22 	cs = intel_ring_begin(rq, 4);
23 	if (IS_ERR(cs))
24 		return PTR_ERR(cs);
25 
26 	offset = i915_ggtt_offset(ce->state) +
27 		 LRC_STATE_OFFSET + CTX_R_PWR_CLK_STATE * 4;
28 
29 	*cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
30 	*cs++ = lower_32_bits(offset);
31 	*cs++ = upper_32_bits(offset);
32 	*cs++ = intel_sseu_make_rpcs(rq->engine->gt, &sseu);
33 
34 	intel_ring_advance(rq, cs);
35 
36 	return 0;
37 }
38 
39 static int
40 gen8_modify_rpcs(struct intel_context *ce, const struct intel_sseu sseu)
41 {
42 	struct i915_request *rq;
43 	int ret;
44 
45 	lockdep_assert_held(&ce->pin_mutex);
46 
47 	/*
48 	 * If the context is not idle, we have to submit an ordered request to
49 	 * modify its context image via the kernel context (writing to our own
50 	 * image, or into the registers directory, does not stick). Pristine
51 	 * and idle contexts will be configured on pinning.
52 	 */
53 	if (!intel_context_pin_if_active(ce))
54 		return 0;
55 
56 	rq = intel_engine_create_kernel_request(ce->engine);
57 	if (IS_ERR(rq)) {
58 		ret = PTR_ERR(rq);
59 		goto out_unpin;
60 	}
61 
62 	/* Serialise with the remote context */
63 	ret = intel_context_prepare_remote_request(ce, rq);
64 	if (ret == 0)
65 		ret = gen8_emit_rpcs_config(rq, ce, sseu);
66 
67 	i915_request_add(rq);
68 out_unpin:
69 	intel_context_unpin(ce);
70 	return ret;
71 }
72 
73 int
74 intel_context_reconfigure_sseu(struct intel_context *ce,
75 			       const struct intel_sseu sseu)
76 {
77 	int ret;
78 
79 	GEM_BUG_ON(GRAPHICS_VER(ce->engine->i915) < 8);
80 
81 	ret = intel_context_lock_pinned(ce);
82 	if (ret)
83 		return ret;
84 
85 	/* Nothing to do if unmodified. */
86 	if (!memcmp(&ce->sseu, &sseu, sizeof(sseu)))
87 		goto unlock;
88 
89 	ret = gen8_modify_rpcs(ce, sseu);
90 	if (!ret)
91 		ce->sseu = sseu;
92 
93 unlock:
94 	intel_context_unlock_pinned(ce);
95 	return ret;
96 }
97