1// SPDX-License-Identifier: MIT
2/*
3 * Copyright © 2023 Intel Corporation
4 */
5
6#include "gt/intel_context.h"
7#include "gt/intel_engine_pm.h"
8#include "gt/intel_gpu_commands.h"
9#include "gt/intel_gt.h"
10#include "gt/intel_ring.h"
11
12#include "i915_wait_util.h"
13#include "intel_gsc_uc_heci_cmd_submit.h"
14
15struct gsc_heci_pkt {
16 u64 addr_in;
17 u32 size_in;
18 u64 addr_out;
19 u32 size_out;
20};
21
22static int emit_gsc_heci_pkt(struct i915_request *rq, struct gsc_heci_pkt *pkt)
23{
24 u32 *cs;
25
26 cs = intel_ring_begin(rq, num_dwords: 8);
27 if (IS_ERR(ptr: cs))
28 return PTR_ERR(ptr: cs);
29
30 *cs++ = GSC_HECI_CMD_PKT;
31 *cs++ = lower_32_bits(pkt->addr_in);
32 *cs++ = upper_32_bits(pkt->addr_in);
33 *cs++ = pkt->size_in;
34 *cs++ = lower_32_bits(pkt->addr_out);
35 *cs++ = upper_32_bits(pkt->addr_out);
36 *cs++ = pkt->size_out;
37 *cs++ = 0;
38
39 intel_ring_advance(rq, cs);
40
41 return 0;
42}
43
44int intel_gsc_uc_heci_cmd_submit_packet(struct intel_gsc_uc *gsc, u64 addr_in,
45 u32 size_in, u64 addr_out,
46 u32 size_out)
47{
48 struct intel_context *ce = gsc->ce;
49 struct i915_request *rq;
50 struct gsc_heci_pkt pkt = {
51 .addr_in = addr_in,
52 .size_in = size_in,
53 .addr_out = addr_out,
54 .size_out = size_out
55 };
56 int err;
57
58 if (!ce)
59 return -ENODEV;
60
61 rq = i915_request_create(ce);
62 if (IS_ERR(ptr: rq))
63 return PTR_ERR(ptr: rq);
64
65 if (ce->engine->emit_init_breadcrumb) {
66 err = ce->engine->emit_init_breadcrumb(rq);
67 if (err)
68 goto out_rq;
69 }
70
71 err = emit_gsc_heci_pkt(rq, pkt: &pkt);
72
73 if (err)
74 goto out_rq;
75
76 err = ce->engine->emit_flush(rq, 0);
77
78out_rq:
79 i915_request_get(rq);
80
81 if (unlikely(err))
82 i915_request_set_error_once(rq, error: err);
83
84 i915_request_add(rq);
85
86 if (!err) {
87 /*
88 * Start timeout for i915_request_wait only after considering one possible
89 * pending GSC-HECI submission cycle on the other (non-privileged) path.
90 */
91 if (wait_for(i915_request_started(rq), GSC_HECI_REPLY_LATENCY_MS))
92 drm_dbg(&gsc_uc_to_gt(gsc)->i915->drm,
93 "Delay in gsc-heci-priv submission to gsccs-hw");
94 if (i915_request_wait(rq, flags: 0, timeout: msecs_to_jiffies(GSC_HECI_REPLY_LATENCY_MS)) < 0)
95 err = -ETIME;
96 }
97
98 i915_request_put(rq);
99
100 if (err)
101 drm_err(&gsc_uc_to_gt(gsc)->i915->drm,
102 "Request submission for GSC heci cmd failed (%d)\n",
103 err);
104
105 return err;
106}
107
108void intel_gsc_uc_heci_cmd_emit_mtl_header(struct intel_gsc_mtl_header *header,
109 u8 heci_client_id, u32 message_size,
110 u64 host_session_id)
111{
112 host_session_id &= ~HOST_SESSION_MASK;
113 if (host_session_id && heci_client_id == HECI_MEADDRESS_PXP)
114 host_session_id |= HOST_SESSION_PXP_SINGLE;
115
116 header->validity_marker = GSC_HECI_VALIDITY_MARKER;
117 header->heci_client_id = heci_client_id;
118 header->host_session_handle = host_session_id;
119 header->header_version = MTL_GSC_HEADER_VERSION;
120 header->message_size = message_size;
121}
122
123static void
124emit_gsc_heci_pkt_nonpriv(u32 *cmd, struct intel_gsc_heci_non_priv_pkt *pkt)
125{
126 *cmd++ = GSC_HECI_CMD_PKT;
127 *cmd++ = lower_32_bits(pkt->addr_in);
128 *cmd++ = upper_32_bits(pkt->addr_in);
129 *cmd++ = pkt->size_in;
130 *cmd++ = lower_32_bits(pkt->addr_out);
131 *cmd++ = upper_32_bits(pkt->addr_out);
132 *cmd++ = pkt->size_out;
133 *cmd++ = 0;
134 *cmd++ = MI_BATCH_BUFFER_END;
135}
136
137int
138intel_gsc_uc_heci_cmd_submit_nonpriv(struct intel_gsc_uc *gsc,
139 struct intel_context *ce,
140 struct intel_gsc_heci_non_priv_pkt *pkt,
141 u32 *cmd, int timeout_ms)
142{
143 struct intel_engine_cs *engine;
144 struct i915_gem_ww_ctx ww;
145 struct i915_request *rq;
146 int err, trials = 0;
147
148 i915_gem_ww_ctx_init(ctx: &ww, intr: false);
149retry:
150 err = i915_gem_object_lock(obj: pkt->bb_vma->obj, ww: &ww);
151 if (err)
152 goto out_ww;
153 err = i915_gem_object_lock(obj: pkt->heci_pkt_vma->obj, ww: &ww);
154 if (err)
155 goto out_ww;
156 err = intel_context_pin_ww(ce, ww: &ww);
157 if (err)
158 goto out_ww;
159
160 rq = i915_request_create(ce);
161 if (IS_ERR(ptr: rq)) {
162 err = PTR_ERR(ptr: rq);
163 goto out_unpin_ce;
164 }
165
166 emit_gsc_heci_pkt_nonpriv(cmd, pkt);
167
168 err = i915_vma_move_to_active(vma: pkt->bb_vma, rq, flags: 0);
169 if (err)
170 goto out_rq;
171 err = i915_vma_move_to_active(vma: pkt->heci_pkt_vma, rq, EXEC_OBJECT_WRITE);
172 if (err)
173 goto out_rq;
174
175 engine = rq->context->engine;
176 if (engine->emit_init_breadcrumb) {
177 err = engine->emit_init_breadcrumb(rq);
178 if (err)
179 goto out_rq;
180 }
181
182 err = engine->emit_bb_start(rq, i915_vma_offset(vma: pkt->bb_vma), PAGE_SIZE, 0);
183 if (err)
184 goto out_rq;
185
186 err = ce->engine->emit_flush(rq, 0);
187 if (err)
188 drm_err(&gsc_uc_to_gt(gsc)->i915->drm,
189 "Failed emit-flush for gsc-heci-non-priv-pkterr=%d\n", err);
190
191out_rq:
192 i915_request_get(rq);
193
194 if (unlikely(err))
195 i915_request_set_error_once(rq, error: err);
196
197 i915_request_add(rq);
198
199 if (!err) {
200 /*
201 * Start timeout for i915_request_wait only after considering one possible
202 * pending GSC-HECI submission cycle on the other (privileged) path.
203 */
204 if (wait_for(i915_request_started(rq), GSC_HECI_REPLY_LATENCY_MS))
205 drm_dbg(&gsc_uc_to_gt(gsc)->i915->drm,
206 "Delay in gsc-heci-non-priv submission to gsccs-hw");
207 if (i915_request_wait(rq, I915_WAIT_INTERRUPTIBLE,
208 timeout: msecs_to_jiffies(m: timeout_ms)) < 0)
209 err = -ETIME;
210 }
211
212 i915_request_put(rq);
213
214out_unpin_ce:
215 intel_context_unpin(ce);
216out_ww:
217 if (err == -EDEADLK) {
218 err = i915_gem_ww_ctx_backoff(ctx: &ww);
219 if (!err) {
220 if (++trials < 10)
221 goto retry;
222 else
223 err = -EAGAIN;
224 }
225 }
226 i915_gem_ww_ctx_fini(ctx: &ww);
227
228 return err;
229}
230