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

source code of linux/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.c