File Index
Files and directories
Sign in
FILE

intel_pxp_gsccs.c

File preview with syntax highlighting.

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