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+
15167static void
16168gsccs_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+
26235static int
27236gsccs_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
55293void intel_pxp_gsccs_fini (struct intel_pxp * pxp )
0 commit comments