Skip to content

Commit dc9ac12

Browse files
aalteresRadhakrishna Sripada
authored andcommitted
drm/i915/pxp: Add GSC-CS backend to send GSC fw messages
Add GSC engine based method for sending PXP firmware packets to the GSC firmware for MTL (and future) products. Use the newly added helpers to populate the GSC-CS memory header and send the message packet to the FW by dispatching the GSC_HECI_CMD_PKT instruction on the GSC engine. We use non-priveleged batches for submission to GSC engine which require two buffers for the request: - a buffer for the HECI packet that contains PXP FW commands - a batch-buffer that contains the engine instruction for sending the HECI packet to the GSC firmware. Thus, add the allocation and freeing of these buffers in gsccs init and fini. The GSC-fw may reply to commands with a SUCCESS but with an additional pending-bit set in the reply packet. This bit means the GSC-FW is currently busy and the caller needs to try again with the gsc_message_handle the fw returned. Thus, add a wrapper to continuously retry send_message while replaying the gsc_message_handle. Retries need to follow the arch-spec count and delay until GSC-FW replies with the real SUCCESS or timeout after that spec'd delay. The GSC-fw requires a non-zero host_session_handle provided by the caller to enable gsc_message_handle tracking. Thus, allocate the host_session_handle at init and destroy it at fini (the latter requiring an FYI to the gsc-firmware). Signed-off-by: Alan Previn <alan.previn.teres.alexis@intel.com> Reviewed-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Signed-off-by: Radhakrishna Sripada <radhakrishna.sripada@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20230511231738.1077674-5-alan.previn.teres.alexis@intel.com
1 parent e5e1e6d commit dc9ac12

5 files changed

Lines changed: 254 additions & 2 deletions

File tree

drivers/gpu/drm/i915/gt/uc/intel_gsc_uc_heci_cmd_submit.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ struct intel_gsc_mtl_header {
5151
* we distinguish the flags using OUTFLAG or INFLAG
5252
*/
5353
u32 flags;
54-
#define GSC_OUTFLAG_MSG_PENDING 1
54+
#define GSC_OUTFLAG_MSG_PENDING BIT(0)
55+
#define GSC_INFLAG_MSG_CLEANUP BIT(1)
5556

5657
u32 status;
5758
} __packed;

drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_43.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
/* PXP-Cmd-Op definitions */
1313
#define PXP43_CMDID_START_HUC_AUTH 0x0000003A
1414

15+
/* PXP-Packet sizes for MTL's GSCCS-HECI instruction */
16+
#define PXP43_MAX_HECI_INOUT_SIZE (SZ_32K)
17+
1518
/* PXP-Input-Packet: HUC-Authentication */
1619
struct pxp43_start_huc_auth_in {
1720
struct pxp_cmd_header header;

drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.c

Lines changed: 239 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,240 @@
66
#include "gem/i915_gem_internal.h"
77

88
#include "gt/intel_context.h"
9+
#include "gt/uc/intel_gsc_uc_heci_cmd_submit.h"
910

1011
#include "i915_drv.h"
1112
#include "intel_pxp_cmd_interface_43.h"
1213
#include "intel_pxp_gsccs.h"
1314
#include "intel_pxp_types.h"
1415

16+
static int
17+
gsccs_send_message(struct intel_pxp *pxp,
18+
void *msg_in, size_t msg_in_size,
19+
void *msg_out, size_t msg_out_size_max,
20+
size_t *msg_out_len,
21+
u64 *gsc_msg_handle_retry)
22+
{
23+
struct intel_gt *gt = pxp->ctrl_gt;
24+
struct drm_i915_private *i915 = gt->i915;
25+
struct gsccs_session_resources *exec_res = &pxp->gsccs_res;
26+
struct intel_gsc_mtl_header *header = exec_res->pkt_vaddr;
27+
struct intel_gsc_heci_non_priv_pkt pkt;
28+
size_t max_msg_size;
29+
u32 reply_size;
30+
int ret;
31+
32+
if (!exec_res->ce)
33+
return -ENODEV;
34+
35+
max_msg_size = PXP43_MAX_HECI_INOUT_SIZE - sizeof(*header);
36+
37+
if (msg_in_size > max_msg_size || msg_out_size_max > max_msg_size)
38+
return -ENOSPC;
39+
40+
if (!exec_res->pkt_vma || !exec_res->bb_vma)
41+
return -ENOENT;
42+
43+
GEM_BUG_ON(exec_res->pkt_vma->size < (2 * PXP43_MAX_HECI_INOUT_SIZE));
44+
45+
mutex_lock(&pxp->tee_mutex);
46+
47+
memset(header, 0, sizeof(*header));
48+
intel_gsc_uc_heci_cmd_emit_mtl_header(header, HECI_MEADDRESS_PXP,
49+
msg_in_size + sizeof(*header),
50+
exec_res->host_session_handle);
51+
52+
/* check if this is a host-session-handle cleanup call (empty packet) */
53+
if (!msg_in && !msg_out)
54+
header->flags |= GSC_INFLAG_MSG_CLEANUP;
55+
56+
/* copy caller provided gsc message handle if this is polling for a prior msg completion */
57+
header->gsc_message_handle = *gsc_msg_handle_retry;
58+
59+
/* NOTE: zero size packets are used for session-cleanups */
60+
if (msg_in && msg_in_size)
61+
memcpy(exec_res->pkt_vaddr + sizeof(*header), msg_in, msg_in_size);
62+
63+
pkt.addr_in = i915_vma_offset(exec_res->pkt_vma);
64+
pkt.size_in = header->message_size;
65+
pkt.addr_out = pkt.addr_in + PXP43_MAX_HECI_INOUT_SIZE;
66+
pkt.size_out = msg_out_size_max + sizeof(*header);
67+
pkt.heci_pkt_vma = exec_res->pkt_vma;
68+
pkt.bb_vma = exec_res->bb_vma;
69+
70+
/*
71+
* Before submitting, let's clear-out the validity marker on the reply offset.
72+
* We use offset PXP43_MAX_HECI_INOUT_SIZE for reply location so point header there.
73+
*/
74+
header = exec_res->pkt_vaddr + PXP43_MAX_HECI_INOUT_SIZE;
75+
header->validity_marker = 0;
76+
77+
ret = intel_gsc_uc_heci_cmd_submit_nonpriv(&gt->uc.gsc,
78+
exec_res->ce, &pkt, exec_res->bb_vaddr,
79+
GSC_REPLY_LATENCY_MS);
80+
if (ret) {
81+
drm_err(&i915->drm, "failed to send gsc PXP msg (%d)\n", ret);
82+
goto unlock;
83+
}
84+
85+
/* Response validity marker, status and busyness */
86+
if (header->validity_marker != GSC_HECI_VALIDITY_MARKER) {
87+
drm_err(&i915->drm, "gsc PXP reply with invalid validity marker\n");
88+
ret = -EINVAL;
89+
goto unlock;
90+
}
91+
if (header->status != 0) {
92+
drm_dbg(&i915->drm, "gsc PXP reply status has error = 0x%08x\n",
93+
header->status);
94+
ret = -EINVAL;
95+
goto unlock;
96+
}
97+
if (header->flags & GSC_OUTFLAG_MSG_PENDING) {
98+
drm_dbg(&i915->drm, "gsc PXP reply is busy\n");
99+
/*
100+
* When the GSC firmware replies with pending bit, it means that the requested
101+
* operation has begun but the completion is pending and the caller needs
102+
* to re-request with the gsc_message_handle that was returned by the firmware.
103+
* until the pending bit is turned off.
104+
*/
105+
*gsc_msg_handle_retry = header->gsc_message_handle;
106+
ret = -EAGAIN;
107+
goto unlock;
108+
}
109+
110+
reply_size = header->message_size - sizeof(*header);
111+
if (reply_size > msg_out_size_max) {
112+
drm_warn(&i915->drm, "caller with insufficient PXP reply size %u (%ld)\n",
113+
reply_size, msg_out_size_max);
114+
reply_size = msg_out_size_max;
115+
}
116+
117+
if (msg_out)
118+
memcpy(msg_out, exec_res->pkt_vaddr + PXP43_MAX_HECI_INOUT_SIZE + sizeof(*header),
119+
reply_size);
120+
if (msg_out_len)
121+
*msg_out_len = reply_size;
122+
123+
unlock:
124+
mutex_unlock(&pxp->tee_mutex);
125+
return ret;
126+
}
127+
128+
static int
129+
gsccs_send_message_retry_complete(struct intel_pxp *pxp,
130+
void *msg_in, size_t msg_in_size,
131+
void *msg_out, size_t msg_out_size_max,
132+
size_t *msg_out_len)
133+
{
134+
u64 gsc_session_retry = 0;
135+
int ret, tries = 0;
136+
137+
/*
138+
* Keep sending request if GSC firmware was busy. Based on fw specs +
139+
* sw overhead (and testing) we expect a worst case pending-bit delay of
140+
* GSC_PENDING_RETRY_MAXCOUNT x GSC_PENDING_RETRY_PAUSE_MS millisecs.
141+
*/
142+
do {
143+
ret = gsccs_send_message(pxp, msg_in, msg_in_size, msg_out, msg_out_size_max,
144+
msg_out_len, &gsc_session_retry);
145+
/* Only try again if gsc says so */
146+
if (ret != -EAGAIN)
147+
break;
148+
149+
msleep(GSC_PENDING_RETRY_PAUSE_MS);
150+
} while (++tries < GSC_PENDING_RETRY_MAXCOUNT);
151+
152+
return ret;
153+
}
154+
155+
static void
156+
gsccs_cleanup_fw_host_session_handle(struct intel_pxp *pxp)
157+
{
158+
struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
159+
int ret;
160+
161+
ret = gsccs_send_message_retry_complete(pxp, NULL, 0, NULL, 0, NULL);
162+
if (ret)
163+
drm_dbg(&i915->drm, "Failed to send gsccs msg host-session-cleanup: ret=[%d]\n",
164+
ret);
165+
}
166+
15167
static void
16168
gsccs_destroy_execution_resource(struct intel_pxp *pxp)
17169
{
18170
struct gsccs_session_resources *exec_res = &pxp->gsccs_res;
19171

172+
if (exec_res->host_session_handle)
173+
gsccs_cleanup_fw_host_session_handle(pxp);
20174
if (exec_res->ce)
21175
intel_context_put(exec_res->ce);
176+
if (exec_res->bb_vma)
177+
i915_vma_unpin_and_release(&exec_res->bb_vma, I915_VMA_RELEASE_MAP);
178+
if (exec_res->pkt_vma)
179+
i915_vma_unpin_and_release(&exec_res->pkt_vma, I915_VMA_RELEASE_MAP);
22180

23181
memset(exec_res, 0, sizeof(*exec_res));
24182
}
25183

184+
static int
185+
gsccs_create_buffer(struct intel_gt *gt,
186+
const char *bufname, size_t size,
187+
struct i915_vma **vma, void **map)
188+
{
189+
struct drm_i915_private *i915 = gt->i915;
190+
struct drm_i915_gem_object *obj;
191+
int err = 0;
192+
193+
obj = i915_gem_object_create_internal(i915, size);
194+
if (IS_ERR(obj)) {
195+
drm_err(&i915->drm, "Failed to allocate gsccs backend %s.\n", bufname);
196+
err = PTR_ERR(obj);
197+
goto out_none;
198+
}
199+
200+
*vma = i915_vma_instance(obj, gt->vm, NULL);
201+
if (IS_ERR(*vma)) {
202+
drm_err(&i915->drm, "Failed to vma-instance gsccs backend %s.\n", bufname);
203+
err = PTR_ERR(*vma);
204+
goto out_put;
205+
}
206+
207+
/* return a virtual pointer */
208+
*map = i915_gem_object_pin_map_unlocked(obj, i915_coherent_map_type(i915, obj, true));
209+
if (IS_ERR(*map)) {
210+
drm_err(&i915->drm, "Failed to map gsccs backend %s.\n", bufname);
211+
err = PTR_ERR(*map);
212+
goto out_put;
213+
}
214+
215+
/* all PXP sessions commands are treated as non-privileged */
216+
err = i915_vma_pin(*vma, 0, 0, PIN_USER);
217+
if (err) {
218+
drm_err(&i915->drm, "Failed to vma-pin gsccs backend %s.\n", bufname);
219+
goto out_unmap;
220+
}
221+
222+
return 0;
223+
224+
out_unmap:
225+
i915_gem_object_unpin_map(obj);
226+
out_put:
227+
i915_gem_object_put(obj);
228+
out_none:
229+
*vma = NULL;
230+
*map = NULL;
231+
232+
return err;
233+
}
234+
26235
static int
27236
gsccs_allocate_execution_resource(struct intel_pxp *pxp)
28237
{
29238
struct intel_gt *gt = pxp->ctrl_gt;
30239
struct gsccs_session_resources *exec_res = &pxp->gsccs_res;
31240
struct intel_engine_cs *engine = gt->engine[GSC0];
32241
struct intel_context *ce;
242+
int err = 0;
33243

34244
/*
35245
* First, ensure the GSC engine is present.
@@ -38,18 +248,46 @@ gsccs_allocate_execution_resource(struct intel_pxp *pxp)
38248
if (!engine)
39249
return -ENODEV;
40250

251+
/*
252+
* Now, allocate, pin and map two objects, one for the heci message packet
253+
* and another for the batch buffer we submit into GSC engine (that includes the packet).
254+
* NOTE: GSC-CS backend is currently only supported on MTL, so we allocate shmem.
255+
*/
256+
err = gsccs_create_buffer(pxp->ctrl_gt, "Heci Packet",
257+
2 * PXP43_MAX_HECI_INOUT_SIZE,
258+
&exec_res->pkt_vma, &exec_res->pkt_vaddr);
259+
if (err)
260+
return err;
261+
262+
err = gsccs_create_buffer(pxp->ctrl_gt, "Batch Buffer", PAGE_SIZE,
263+
&exec_res->bb_vma, &exec_res->bb_vaddr);
264+
if (err)
265+
goto free_pkt;
266+
41267
/* Finally, create an intel_context to be used during the submission */
42268
ce = intel_context_create(engine);
43269
if (IS_ERR(ce)) {
44270
drm_err(&gt->i915->drm, "Failed creating gsccs backend ctx\n");
45-
return PTR_ERR(ce);
271+
err = PTR_ERR(ce);
272+
goto free_batch;
46273
}
47274

48275
i915_vm_put(ce->vm);
49276
ce->vm = i915_vm_get(pxp->ctrl_gt->vm);
50277
exec_res->ce = ce;
51278

279+
/* initialize host-session-handle (for all i915-to-gsc-firmware PXP cmds) */
280+
get_random_bytes(&exec_res->host_session_handle, sizeof(exec_res->host_session_handle));
281+
52282
return 0;
283+
284+
free_batch:
285+
i915_vma_unpin_and_release(&exec_res->bb_vma, I915_VMA_RELEASE_MAP);
286+
free_pkt:
287+
i915_vma_unpin_and_release(&exec_res->pkt_vma, I915_VMA_RELEASE_MAP);
288+
memset(exec_res, 0, sizeof(*exec_res));
289+
290+
return err;
53291
}
54292

55293
void intel_pxp_gsccs_fini(struct intel_pxp *pxp)

drivers/gpu/drm/i915/pxp/intel_pxp_gsccs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
struct intel_pxp;
1212

13+
#define GSC_REPLY_LATENCY_MS 200
14+
#define GSC_PENDING_RETRY_MAXCOUNT 40
15+
#define GSC_PENDING_RETRY_PAUSE_MS 50
16+
1317
#ifdef CONFIG_DRM_I915_PXP
1418
void intel_pxp_gsccs_fini(struct intel_pxp *pxp);
1519
int intel_pxp_gsccs_init(struct intel_pxp *pxp);

drivers/gpu/drm/i915/pxp/intel_pxp_types.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ struct intel_pxp {
3838
struct gsccs_session_resources {
3939
u64 host_session_handle; /* used by firmware to link commands to sessions */
4040
struct intel_context *ce; /* context for gsc command submission */
41+
42+
struct i915_vma *pkt_vma; /* GSC FW cmd packet vma */
43+
void *pkt_vaddr; /* GSC FW cmd packet virt pointer */
44+
45+
struct i915_vma *bb_vma; /* HECI_PKT batch buffer vma */
46+
void *bb_vaddr; /* HECI_PKT batch buffer virt pointer */
4147
} gsccs_res;
4248

4349
/**

0 commit comments

Comments
 (0)