xref: /openbsd-src/sys/dev/pci/drm/i915/pxp/intel_pxp_gsccs.c (revision ab5e6dadf341f5a44f6bd51c6b25dc4cda8bf18f)
1f005ef32Sjsg // SPDX-License-Identifier: MIT
2f005ef32Sjsg /*
3f005ef32Sjsg  * Copyright(c) 2023 Intel Corporation.
4f005ef32Sjsg  */
5f005ef32Sjsg 
6f005ef32Sjsg #include "gem/i915_gem_internal.h"
7f005ef32Sjsg 
8f005ef32Sjsg #include "gt/intel_context.h"
9f005ef32Sjsg #include "gt/intel_gt.h"
10f005ef32Sjsg #include "gt/uc/intel_gsc_fw.h"
11f005ef32Sjsg #include "gt/uc/intel_gsc_uc_heci_cmd_submit.h"
12f005ef32Sjsg 
13f005ef32Sjsg #include "i915_drv.h"
14f005ef32Sjsg #include "intel_pxp.h"
15f005ef32Sjsg #include "intel_pxp_cmd_interface_42.h"
16f005ef32Sjsg #include "intel_pxp_cmd_interface_43.h"
17f005ef32Sjsg #include "intel_pxp_gsccs.h"
18f005ef32Sjsg #include "intel_pxp_types.h"
19f005ef32Sjsg 
20f005ef32Sjsg static bool
is_fw_err_platform_config(u32 type)21f005ef32Sjsg is_fw_err_platform_config(u32 type)
22f005ef32Sjsg {
23f005ef32Sjsg 	switch (type) {
24f005ef32Sjsg 	case PXP_STATUS_ERROR_API_VERSION:
25f005ef32Sjsg 	case PXP_STATUS_PLATFCONFIG_KF1_NOVERIF:
26f005ef32Sjsg 	case PXP_STATUS_PLATFCONFIG_KF1_BAD:
27f005ef32Sjsg 		return true;
28f005ef32Sjsg 	default:
29f005ef32Sjsg 		break;
30f005ef32Sjsg 	}
31f005ef32Sjsg 	return false;
32f005ef32Sjsg }
33f005ef32Sjsg 
34f005ef32Sjsg static const char *
fw_err_to_string(u32 type)35f005ef32Sjsg fw_err_to_string(u32 type)
36f005ef32Sjsg {
37f005ef32Sjsg 	switch (type) {
38f005ef32Sjsg 	case PXP_STATUS_ERROR_API_VERSION:
39f005ef32Sjsg 		return "ERR_API_VERSION";
40f005ef32Sjsg 	case PXP_STATUS_NOT_READY:
41f005ef32Sjsg 		return "ERR_NOT_READY";
42f005ef32Sjsg 	case PXP_STATUS_PLATFCONFIG_KF1_NOVERIF:
43f005ef32Sjsg 	case PXP_STATUS_PLATFCONFIG_KF1_BAD:
44f005ef32Sjsg 		return "ERR_PLATFORM_CONFIG";
45f005ef32Sjsg 	default:
46f005ef32Sjsg 		break;
47f005ef32Sjsg 	}
48f005ef32Sjsg 	return NULL;
49f005ef32Sjsg }
50f005ef32Sjsg 
51f005ef32Sjsg static int
gsccs_send_message(struct intel_pxp * pxp,void * msg_in,size_t msg_in_size,void * msg_out,size_t msg_out_size_max,size_t * msg_out_len,u64 * gsc_msg_handle_retry)52f005ef32Sjsg gsccs_send_message(struct intel_pxp *pxp,
53f005ef32Sjsg 		   void *msg_in, size_t msg_in_size,
54f005ef32Sjsg 		   void *msg_out, size_t msg_out_size_max,
55f005ef32Sjsg 		   size_t *msg_out_len,
56f005ef32Sjsg 		   u64 *gsc_msg_handle_retry)
57f005ef32Sjsg {
58f005ef32Sjsg 	struct intel_gt *gt = pxp->ctrl_gt;
59f005ef32Sjsg 	struct drm_i915_private *i915 = gt->i915;
60f005ef32Sjsg 	struct gsccs_session_resources *exec_res =  &pxp->gsccs_res;
61f005ef32Sjsg 	struct intel_gsc_mtl_header *header = exec_res->pkt_vaddr;
62f005ef32Sjsg 	struct intel_gsc_heci_non_priv_pkt pkt;
63f005ef32Sjsg 	size_t max_msg_size;
64f005ef32Sjsg 	u32 reply_size;
65f005ef32Sjsg 	int ret;
66f005ef32Sjsg 
67f005ef32Sjsg 	if (!exec_res->ce)
68f005ef32Sjsg 		return -ENODEV;
69f005ef32Sjsg 
70f005ef32Sjsg 	max_msg_size = PXP43_MAX_HECI_INOUT_SIZE - sizeof(*header);
71f005ef32Sjsg 
72f005ef32Sjsg 	if (msg_in_size > max_msg_size || msg_out_size_max > max_msg_size)
73f005ef32Sjsg 		return -ENOSPC;
74f005ef32Sjsg 
75f005ef32Sjsg 	if (!exec_res->pkt_vma || !exec_res->bb_vma)
76f005ef32Sjsg 		return -ENOENT;
77f005ef32Sjsg 
78f005ef32Sjsg 	GEM_BUG_ON(exec_res->pkt_vma->size < (2 * PXP43_MAX_HECI_INOUT_SIZE));
79f005ef32Sjsg 
80f005ef32Sjsg 	mutex_lock(&pxp->tee_mutex);
81f005ef32Sjsg 
82f005ef32Sjsg 	memset(header, 0, sizeof(*header));
83f005ef32Sjsg 	intel_gsc_uc_heci_cmd_emit_mtl_header(header, HECI_MEADDRESS_PXP,
84f005ef32Sjsg 					      msg_in_size + sizeof(*header),
85f005ef32Sjsg 					      exec_res->host_session_handle);
86f005ef32Sjsg 
87f005ef32Sjsg 	/* check if this is a host-session-handle cleanup call (empty packet) */
88f005ef32Sjsg 	if (!msg_in && !msg_out)
89f005ef32Sjsg 		header->flags |= GSC_INFLAG_MSG_CLEANUP;
90f005ef32Sjsg 
91f005ef32Sjsg 	/* copy caller provided gsc message handle if this is polling for a prior msg completion */
92f005ef32Sjsg 	header->gsc_message_handle = *gsc_msg_handle_retry;
93f005ef32Sjsg 
94f005ef32Sjsg 	/* NOTE: zero size packets are used for session-cleanups */
95f005ef32Sjsg 	if (msg_in && msg_in_size)
96f005ef32Sjsg 		memcpy(exec_res->pkt_vaddr + sizeof(*header), msg_in, msg_in_size);
97f005ef32Sjsg 
98f005ef32Sjsg 	pkt.addr_in = i915_vma_offset(exec_res->pkt_vma);
99f005ef32Sjsg 	pkt.size_in = header->message_size;
100f005ef32Sjsg 	pkt.addr_out = pkt.addr_in + PXP43_MAX_HECI_INOUT_SIZE;
101f005ef32Sjsg 	pkt.size_out = msg_out_size_max + sizeof(*header);
102f005ef32Sjsg 	pkt.heci_pkt_vma = exec_res->pkt_vma;
103f005ef32Sjsg 	pkt.bb_vma = exec_res->bb_vma;
104f005ef32Sjsg 
105f005ef32Sjsg 	/*
106f005ef32Sjsg 	 * Before submitting, let's clear-out the validity marker on the reply offset.
107f005ef32Sjsg 	 * We use offset PXP43_MAX_HECI_INOUT_SIZE for reply location so point header there.
108f005ef32Sjsg 	 */
109f005ef32Sjsg 	header = exec_res->pkt_vaddr + PXP43_MAX_HECI_INOUT_SIZE;
110f005ef32Sjsg 	header->validity_marker = 0;
111f005ef32Sjsg 
112f005ef32Sjsg 	ret = intel_gsc_uc_heci_cmd_submit_nonpriv(&gt->uc.gsc,
113f005ef32Sjsg 						   exec_res->ce, &pkt, exec_res->bb_vaddr,
114*ab5e6dadSjsg 						   GSC_HECI_REPLY_LATENCY_MS);
115f005ef32Sjsg 	if (ret) {
116f005ef32Sjsg 		drm_err(&i915->drm, "failed to send gsc PXP msg (%d)\n", ret);
117f005ef32Sjsg 		goto unlock;
118f005ef32Sjsg 	}
119f005ef32Sjsg 
120f005ef32Sjsg 	/* Response validity marker, status and busyness */
121f005ef32Sjsg 	if (header->validity_marker != GSC_HECI_VALIDITY_MARKER) {
122f005ef32Sjsg 		drm_err(&i915->drm, "gsc PXP reply with invalid validity marker\n");
123f005ef32Sjsg 		ret = -EINVAL;
124f005ef32Sjsg 		goto unlock;
125f005ef32Sjsg 	}
126f005ef32Sjsg 	if (header->status != 0) {
127f005ef32Sjsg 		drm_dbg(&i915->drm, "gsc PXP reply status has error = 0x%08x\n",
128f005ef32Sjsg 			header->status);
129f005ef32Sjsg 		ret = -EINVAL;
130f005ef32Sjsg 		goto unlock;
131f005ef32Sjsg 	}
132f005ef32Sjsg 	if (header->flags & GSC_OUTFLAG_MSG_PENDING) {
133f005ef32Sjsg 		drm_dbg(&i915->drm, "gsc PXP reply is busy\n");
134f005ef32Sjsg 		/*
135f005ef32Sjsg 		 * When the GSC firmware replies with pending bit, it means that the requested
136f005ef32Sjsg 		 * operation has begun but the completion is pending and the caller needs
137f005ef32Sjsg 		 * to re-request with the gsc_message_handle that was returned by the firmware.
138f005ef32Sjsg 		 * until the pending bit is turned off.
139f005ef32Sjsg 		 */
140f005ef32Sjsg 		*gsc_msg_handle_retry = header->gsc_message_handle;
141f005ef32Sjsg 		ret = -EAGAIN;
142f005ef32Sjsg 		goto unlock;
143f005ef32Sjsg 	}
144f005ef32Sjsg 
145f005ef32Sjsg 	reply_size = header->message_size - sizeof(*header);
146f005ef32Sjsg 	if (reply_size > msg_out_size_max) {
147f005ef32Sjsg 		drm_warn(&i915->drm, "caller with insufficient PXP reply size %u (%zu)\n",
148f005ef32Sjsg 			 reply_size, msg_out_size_max);
149f005ef32Sjsg 		reply_size = msg_out_size_max;
150f005ef32Sjsg 	}
151f005ef32Sjsg 
152f005ef32Sjsg 	if (msg_out)
153f005ef32Sjsg 		memcpy(msg_out, exec_res->pkt_vaddr + PXP43_MAX_HECI_INOUT_SIZE + sizeof(*header),
154f005ef32Sjsg 		       reply_size);
155f005ef32Sjsg 	if (msg_out_len)
156f005ef32Sjsg 		*msg_out_len = reply_size;
157f005ef32Sjsg 
158f005ef32Sjsg unlock:
159f005ef32Sjsg 	mutex_unlock(&pxp->tee_mutex);
160f005ef32Sjsg 	return ret;
161f005ef32Sjsg }
162f005ef32Sjsg 
163f005ef32Sjsg static int
gsccs_send_message_retry_complete(struct intel_pxp * pxp,void * msg_in,size_t msg_in_size,void * msg_out,size_t msg_out_size_max,size_t * msg_out_len)164f005ef32Sjsg gsccs_send_message_retry_complete(struct intel_pxp *pxp,
165f005ef32Sjsg 				  void *msg_in, size_t msg_in_size,
166f005ef32Sjsg 				  void *msg_out, size_t msg_out_size_max,
167f005ef32Sjsg 				  size_t *msg_out_len)
168f005ef32Sjsg {
169f005ef32Sjsg 	u64 gsc_session_retry = 0;
170f005ef32Sjsg 	int ret, tries = 0;
171f005ef32Sjsg 
172f005ef32Sjsg 	/*
173f005ef32Sjsg 	 * Keep sending request if GSC firmware was busy. Based on fw specs +
174f005ef32Sjsg 	 * sw overhead (and testing) we expect a worst case pending-bit delay of
175f005ef32Sjsg 	 * GSC_PENDING_RETRY_MAXCOUNT x GSC_PENDING_RETRY_PAUSE_MS millisecs.
176f005ef32Sjsg 	 */
177f005ef32Sjsg 	do {
178f005ef32Sjsg 		ret = gsccs_send_message(pxp, msg_in, msg_in_size, msg_out, msg_out_size_max,
179f005ef32Sjsg 					 msg_out_len, &gsc_session_retry);
180f005ef32Sjsg 		/* Only try again if gsc says so */
181f005ef32Sjsg 		if (ret != -EAGAIN)
182f005ef32Sjsg 			break;
183f005ef32Sjsg 
184f005ef32Sjsg 		drm_msleep(GSC_PENDING_RETRY_PAUSE_MS);
185f005ef32Sjsg 	} while (++tries < GSC_PENDING_RETRY_MAXCOUNT);
186f005ef32Sjsg 
187f005ef32Sjsg 	return ret;
188f005ef32Sjsg }
189f005ef32Sjsg 
intel_pxp_gsccs_is_ready_for_sessions(struct intel_pxp * pxp)190f005ef32Sjsg bool intel_pxp_gsccs_is_ready_for_sessions(struct intel_pxp *pxp)
191f005ef32Sjsg {
192f005ef32Sjsg 	/*
193f005ef32Sjsg 	 * GSC-fw loading, HuC-fw loading, HuC-fw authentication and
194f005ef32Sjsg 	 * GSC-proxy init flow (requiring an mei component driver)
195f005ef32Sjsg 	 * must all occur first before we can start requesting for PXP
196f005ef32Sjsg 	 * sessions. Checking for completion on HuC authentication and
197f005ef32Sjsg 	 * gsc-proxy init flow (the last set of dependencies that
198f005ef32Sjsg 	 * are out of order) will suffice.
199f005ef32Sjsg 	 */
200f005ef32Sjsg 	if (intel_huc_is_authenticated(&pxp->ctrl_gt->uc.huc, INTEL_HUC_AUTH_BY_GSC) &&
201f005ef32Sjsg 	    intel_gsc_uc_fw_proxy_init_done(&pxp->ctrl_gt->uc.gsc, true))
202f005ef32Sjsg 		return true;
203f005ef32Sjsg 
204f005ef32Sjsg 	return false;
205f005ef32Sjsg }
206f005ef32Sjsg 
intel_pxp_gsccs_create_session(struct intel_pxp * pxp,int arb_session_id)207f005ef32Sjsg int intel_pxp_gsccs_create_session(struct intel_pxp *pxp,
208f005ef32Sjsg 				   int arb_session_id)
209f005ef32Sjsg {
210f005ef32Sjsg 	struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
211f005ef32Sjsg 	struct pxp43_create_arb_in msg_in = {0};
212f005ef32Sjsg 	struct pxp43_create_arb_out msg_out = {0};
213f005ef32Sjsg 	int ret;
214f005ef32Sjsg 
215f005ef32Sjsg 	msg_in.header.api_version = PXP_APIVER(4, 3);
216f005ef32Sjsg 	msg_in.header.command_id = PXP43_CMDID_INIT_SESSION;
217f005ef32Sjsg 	msg_in.header.stream_id = (FIELD_PREP(PXP43_INIT_SESSION_APPID, arb_session_id) |
218f005ef32Sjsg 				   FIELD_PREP(PXP43_INIT_SESSION_VALID, 1) |
219f005ef32Sjsg 				   FIELD_PREP(PXP43_INIT_SESSION_APPTYPE, 0));
220f005ef32Sjsg 	msg_in.header.buffer_len = sizeof(msg_in) - sizeof(msg_in.header);
221f005ef32Sjsg 	msg_in.protection_mode = PXP43_INIT_SESSION_PROTECTION_ARB;
222f005ef32Sjsg 
223f005ef32Sjsg 	ret = gsccs_send_message_retry_complete(pxp,
224f005ef32Sjsg 						&msg_in, sizeof(msg_in),
225f005ef32Sjsg 						&msg_out, sizeof(msg_out), NULL);
226f005ef32Sjsg 	if (ret) {
227f005ef32Sjsg 		drm_err(&i915->drm, "Failed to init session %d, ret=[%d]\n", arb_session_id, ret);
228f005ef32Sjsg 	} else if (msg_out.header.status != 0) {
229f005ef32Sjsg 		if (is_fw_err_platform_config(msg_out.header.status)) {
230f005ef32Sjsg 			drm_info_once(&i915->drm,
231f005ef32Sjsg 				      "PXP init-session-%d failed due to BIOS/SOC:0x%08x:%s\n",
232f005ef32Sjsg 				      arb_session_id, msg_out.header.status,
233f005ef32Sjsg 				      fw_err_to_string(msg_out.header.status));
234f005ef32Sjsg 		} else {
235f005ef32Sjsg 			drm_dbg(&i915->drm, "PXP init-session-%d failed 0x%08x:%st:\n",
236f005ef32Sjsg 				arb_session_id, msg_out.header.status,
237f005ef32Sjsg 				fw_err_to_string(msg_out.header.status));
238f005ef32Sjsg 			drm_dbg(&i915->drm, "     cmd-detail: ID=[0x%08x],API-Ver-[0x%08x]\n",
239f005ef32Sjsg 				msg_in.header.command_id, msg_in.header.api_version);
240f005ef32Sjsg 		}
241f005ef32Sjsg 	}
242f005ef32Sjsg 
243f005ef32Sjsg 	return ret;
244f005ef32Sjsg }
245f005ef32Sjsg 
intel_pxp_gsccs_end_arb_fw_session(struct intel_pxp * pxp,u32 session_id)246f005ef32Sjsg void intel_pxp_gsccs_end_arb_fw_session(struct intel_pxp *pxp, u32 session_id)
247f005ef32Sjsg {
248f005ef32Sjsg 	struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
249f005ef32Sjsg 	struct pxp42_inv_stream_key_in msg_in = {0};
250f005ef32Sjsg 	struct pxp42_inv_stream_key_out msg_out = {0};
251f005ef32Sjsg 	int ret = 0;
252f005ef32Sjsg 
253f005ef32Sjsg 	/*
254f005ef32Sjsg 	 * Stream key invalidation reuses the same version 4.2 input/output
255f005ef32Sjsg 	 * command format but firmware requires 4.3 API interaction
256f005ef32Sjsg 	 */
257f005ef32Sjsg 	msg_in.header.api_version = PXP_APIVER(4, 3);
258f005ef32Sjsg 	msg_in.header.command_id = PXP42_CMDID_INVALIDATE_STREAM_KEY;
259f005ef32Sjsg 	msg_in.header.buffer_len = sizeof(msg_in) - sizeof(msg_in.header);
260f005ef32Sjsg 
261f005ef32Sjsg 	msg_in.header.stream_id = FIELD_PREP(PXP_CMDHDR_EXTDATA_SESSION_VALID, 1);
262f005ef32Sjsg 	msg_in.header.stream_id |= FIELD_PREP(PXP_CMDHDR_EXTDATA_APP_TYPE, 0);
263f005ef32Sjsg 	msg_in.header.stream_id |= FIELD_PREP(PXP_CMDHDR_EXTDATA_SESSION_ID, session_id);
264f005ef32Sjsg 
265f005ef32Sjsg 	ret = gsccs_send_message_retry_complete(pxp,
266f005ef32Sjsg 						&msg_in, sizeof(msg_in),
267f005ef32Sjsg 						&msg_out, sizeof(msg_out), NULL);
268f005ef32Sjsg 	if (ret) {
269f005ef32Sjsg 		drm_err(&i915->drm, "Failed to inv-stream-key-%u, ret=[%d]\n",
270f005ef32Sjsg 			session_id, ret);
271f005ef32Sjsg 	} else if (msg_out.header.status != 0) {
272f005ef32Sjsg 		if (is_fw_err_platform_config(msg_out.header.status)) {
273f005ef32Sjsg 			drm_info_once(&i915->drm,
274f005ef32Sjsg 				      "PXP inv-stream-key-%u failed due to BIOS/SOC :0x%08x:%s\n",
275f005ef32Sjsg 				      session_id, msg_out.header.status,
276f005ef32Sjsg 				      fw_err_to_string(msg_out.header.status));
277f005ef32Sjsg 		} else {
278f005ef32Sjsg 			drm_dbg(&i915->drm, "PXP inv-stream-key-%u failed 0x%08x:%s:\n",
279f005ef32Sjsg 				session_id, msg_out.header.status,
280f005ef32Sjsg 				fw_err_to_string(msg_out.header.status));
281f005ef32Sjsg 			drm_dbg(&i915->drm, "     cmd-detail: ID=[0x%08x],API-Ver-[0x%08x]\n",
282f005ef32Sjsg 				msg_in.header.command_id, msg_in.header.api_version);
283f005ef32Sjsg 		}
284f005ef32Sjsg 	}
285f005ef32Sjsg }
286f005ef32Sjsg 
287f005ef32Sjsg static void
gsccs_cleanup_fw_host_session_handle(struct intel_pxp * pxp)288f005ef32Sjsg gsccs_cleanup_fw_host_session_handle(struct intel_pxp *pxp)
289f005ef32Sjsg {
290f005ef32Sjsg 	struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
291f005ef32Sjsg 	int ret;
292f005ef32Sjsg 
293f005ef32Sjsg 	ret = gsccs_send_message_retry_complete(pxp, NULL, 0, NULL, 0, NULL);
294f005ef32Sjsg 	if (ret)
295f005ef32Sjsg 		drm_dbg(&i915->drm, "Failed to send gsccs msg host-session-cleanup: ret=[%d]\n",
296f005ef32Sjsg 			ret);
297f005ef32Sjsg }
298f005ef32Sjsg 
299f005ef32Sjsg static void
gsccs_destroy_execution_resource(struct intel_pxp * pxp)300f005ef32Sjsg gsccs_destroy_execution_resource(struct intel_pxp *pxp)
301f005ef32Sjsg {
302f005ef32Sjsg 	struct gsccs_session_resources *exec_res = &pxp->gsccs_res;
303f005ef32Sjsg 
304f005ef32Sjsg 	if (exec_res->host_session_handle)
305f005ef32Sjsg 		gsccs_cleanup_fw_host_session_handle(pxp);
306f005ef32Sjsg 	if (exec_res->ce)
307f005ef32Sjsg 		intel_context_put(exec_res->ce);
308f005ef32Sjsg 	if (exec_res->bb_vma)
309f005ef32Sjsg 		i915_vma_unpin_and_release(&exec_res->bb_vma, I915_VMA_RELEASE_MAP);
310f005ef32Sjsg 	if (exec_res->pkt_vma)
311f005ef32Sjsg 		i915_vma_unpin_and_release(&exec_res->pkt_vma, I915_VMA_RELEASE_MAP);
312f005ef32Sjsg 
313f005ef32Sjsg 	memset(exec_res, 0, sizeof(*exec_res));
314f005ef32Sjsg }
315f005ef32Sjsg 
316f005ef32Sjsg static int
gsccs_create_buffer(struct intel_gt * gt,const char * bufname,size_t size,struct i915_vma ** vma,void ** map)317f005ef32Sjsg gsccs_create_buffer(struct intel_gt *gt,
318f005ef32Sjsg 		    const char *bufname, size_t size,
319f005ef32Sjsg 		    struct i915_vma **vma, void **map)
320f005ef32Sjsg {
321f005ef32Sjsg 	struct drm_i915_private *i915 = gt->i915;
322f005ef32Sjsg 	struct drm_i915_gem_object *obj;
323f005ef32Sjsg 	int err = 0;
324f005ef32Sjsg 
325f005ef32Sjsg 	obj = i915_gem_object_create_internal(i915, size);
326f005ef32Sjsg 	if (IS_ERR(obj)) {
327f005ef32Sjsg 		drm_err(&i915->drm, "Failed to allocate gsccs backend %s.\n", bufname);
328f005ef32Sjsg 		err = PTR_ERR(obj);
329f005ef32Sjsg 		goto out_none;
330f005ef32Sjsg 	}
331f005ef32Sjsg 
332f005ef32Sjsg 	*vma = i915_vma_instance(obj, gt->vm, NULL);
333f005ef32Sjsg 	if (IS_ERR(*vma)) {
334f005ef32Sjsg 		drm_err(&i915->drm, "Failed to vma-instance gsccs backend %s.\n", bufname);
335f005ef32Sjsg 		err = PTR_ERR(*vma);
336f005ef32Sjsg 		goto out_put;
337f005ef32Sjsg 	}
338f005ef32Sjsg 
339f005ef32Sjsg 	/* return a virtual pointer */
340f005ef32Sjsg 	*map = i915_gem_object_pin_map_unlocked(obj, intel_gt_coherent_map_type(gt, obj, true));
341f005ef32Sjsg 	if (IS_ERR(*map)) {
342f005ef32Sjsg 		drm_err(&i915->drm, "Failed to map gsccs backend %s.\n", bufname);
343f005ef32Sjsg 		err = PTR_ERR(*map);
344f005ef32Sjsg 		goto out_put;
345f005ef32Sjsg 	}
346f005ef32Sjsg 
347f005ef32Sjsg 	/* all PXP sessions commands are treated as non-privileged */
348f005ef32Sjsg 	err = i915_vma_pin(*vma, 0, 0, PIN_USER);
349f005ef32Sjsg 	if (err) {
350f005ef32Sjsg 		drm_err(&i915->drm, "Failed to vma-pin gsccs backend %s.\n", bufname);
351f005ef32Sjsg 		goto out_unmap;
352f005ef32Sjsg 	}
353f005ef32Sjsg 
354f005ef32Sjsg 	return 0;
355f005ef32Sjsg 
356f005ef32Sjsg out_unmap:
357f005ef32Sjsg 	i915_gem_object_unpin_map(obj);
358f005ef32Sjsg out_put:
359f005ef32Sjsg 	i915_gem_object_put(obj);
360f005ef32Sjsg out_none:
361f005ef32Sjsg 	*vma = NULL;
362f005ef32Sjsg 	*map = NULL;
363f005ef32Sjsg 
364f005ef32Sjsg 	return err;
365f005ef32Sjsg }
366f005ef32Sjsg 
367f005ef32Sjsg static int
gsccs_allocate_execution_resource(struct intel_pxp * pxp)368f005ef32Sjsg gsccs_allocate_execution_resource(struct intel_pxp *pxp)
369f005ef32Sjsg {
370f005ef32Sjsg 	struct intel_gt *gt = pxp->ctrl_gt;
371f005ef32Sjsg 	struct gsccs_session_resources *exec_res = &pxp->gsccs_res;
372f005ef32Sjsg 	struct intel_engine_cs *engine = gt->engine[GSC0];
373f005ef32Sjsg 	struct intel_context *ce;
374f005ef32Sjsg 	int err = 0;
375f005ef32Sjsg 
376f005ef32Sjsg 	/*
377f005ef32Sjsg 	 * First, ensure the GSC engine is present.
378f005ef32Sjsg 	 * NOTE: Backend would only be called with the correct gt.
379f005ef32Sjsg 	 */
380f005ef32Sjsg 	if (!engine)
381f005ef32Sjsg 		return -ENODEV;
382f005ef32Sjsg 
383f005ef32Sjsg 	/*
384f005ef32Sjsg 	 * Now, allocate, pin and map two objects, one for the heci message packet
385f005ef32Sjsg 	 * and another for the batch buffer we submit into GSC engine (that includes the packet).
386f005ef32Sjsg 	 * NOTE: GSC-CS backend is currently only supported on MTL, so we allocate shmem.
387f005ef32Sjsg 	 */
388f005ef32Sjsg 	err = gsccs_create_buffer(pxp->ctrl_gt, "Heci Packet",
389f005ef32Sjsg 				  2 * PXP43_MAX_HECI_INOUT_SIZE,
390f005ef32Sjsg 				  &exec_res->pkt_vma, &exec_res->pkt_vaddr);
391f005ef32Sjsg 	if (err)
392f005ef32Sjsg 		return err;
393f005ef32Sjsg 
394f005ef32Sjsg 	err = gsccs_create_buffer(pxp->ctrl_gt, "Batch Buffer", PAGE_SIZE,
395f005ef32Sjsg 				  &exec_res->bb_vma, &exec_res->bb_vaddr);
396f005ef32Sjsg 	if (err)
397f005ef32Sjsg 		goto free_pkt;
398f005ef32Sjsg 
399f005ef32Sjsg 	/* Finally, create an intel_context to be used during the submission */
400f005ef32Sjsg 	ce = intel_context_create(engine);
401f005ef32Sjsg 	if (IS_ERR(ce)) {
402f005ef32Sjsg 		drm_err(&gt->i915->drm, "Failed creating gsccs backend ctx\n");
403f005ef32Sjsg 		err = PTR_ERR(ce);
404f005ef32Sjsg 		goto free_batch;
405f005ef32Sjsg 	}
406f005ef32Sjsg 
407f005ef32Sjsg 	i915_vm_put(ce->vm);
408f005ef32Sjsg 	ce->vm = i915_vm_get(pxp->ctrl_gt->vm);
409f005ef32Sjsg 	exec_res->ce = ce;
410f005ef32Sjsg 
411f005ef32Sjsg 	/* initialize host-session-handle (for all i915-to-gsc-firmware PXP cmds) */
412f005ef32Sjsg 	get_random_bytes(&exec_res->host_session_handle, sizeof(exec_res->host_session_handle));
413f005ef32Sjsg 
414f005ef32Sjsg 	return 0;
415f005ef32Sjsg 
416f005ef32Sjsg free_batch:
417f005ef32Sjsg 	i915_vma_unpin_and_release(&exec_res->bb_vma, I915_VMA_RELEASE_MAP);
418f005ef32Sjsg free_pkt:
419f005ef32Sjsg 	i915_vma_unpin_and_release(&exec_res->pkt_vma, I915_VMA_RELEASE_MAP);
420f005ef32Sjsg 	memset(exec_res, 0, sizeof(*exec_res));
421f005ef32Sjsg 
422f005ef32Sjsg 	return err;
423f005ef32Sjsg }
424f005ef32Sjsg 
intel_pxp_gsccs_fini(struct intel_pxp * pxp)425f005ef32Sjsg void intel_pxp_gsccs_fini(struct intel_pxp *pxp)
426f005ef32Sjsg {
427f005ef32Sjsg 	intel_wakeref_t wakeref;
428f005ef32Sjsg 
429f005ef32Sjsg 	gsccs_destroy_execution_resource(pxp);
430f005ef32Sjsg 	with_intel_runtime_pm(&pxp->ctrl_gt->i915->runtime_pm, wakeref)
431f005ef32Sjsg 		intel_pxp_fini_hw(pxp);
432f005ef32Sjsg }
433f005ef32Sjsg 
intel_pxp_gsccs_init(struct intel_pxp * pxp)434f005ef32Sjsg int intel_pxp_gsccs_init(struct intel_pxp *pxp)
435f005ef32Sjsg {
436f005ef32Sjsg 	int ret;
437f005ef32Sjsg 	intel_wakeref_t wakeref;
438f005ef32Sjsg 
439f005ef32Sjsg 	ret = gsccs_allocate_execution_resource(pxp);
440f005ef32Sjsg 	if (!ret) {
441f005ef32Sjsg 		with_intel_runtime_pm(&pxp->ctrl_gt->i915->runtime_pm, wakeref)
442f005ef32Sjsg 			intel_pxp_init_hw(pxp);
443f005ef32Sjsg 	}
444f005ef32Sjsg 	return ret;
445f005ef32Sjsg }
446