xref: /linux/drivers/gpu/drm/xe/xe_gsc_submit.c (revision af8e51644a70f612974a6e767fa7d896d3c23f88)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2023 Intel Corporation
4  */
5 
6 #include "xe_gsc_submit.h"
7 
8 #include <linux/poison.h>
9 
10 #include "abi/gsc_command_header_abi.h"
11 #include "xe_bb.h"
12 #include "xe_exec_queue.h"
13 #include "xe_gt_printk.h"
14 #include "xe_gt_types.h"
15 #include "xe_map.h"
16 #include "xe_sched_job.h"
17 #include "instructions/xe_gsc_commands.h"
18 #include "regs/xe_gsc_regs.h"
19 
20 #define GSC_HDR_SIZE (sizeof(struct intel_gsc_mtl_header)) /* shorthand define */
21 
22 #define mtl_gsc_header_wr(xe_, map_, offset_, field_, val_) \
23 	xe_map_wr_field(xe_, map_, offset_, struct intel_gsc_mtl_header, field_, val_)
24 
25 #define mtl_gsc_header_rd(xe_, map_, offset_, field_) \
26 	xe_map_rd_field(xe_, map_, offset_, struct intel_gsc_mtl_header, field_)
27 
28 /*
29  * GSC FW allows us to define the host_session_handle as we see fit, as long
30  * as we use unique identifier for each user, with handle 0 being reserved for
31  * kernel usage.
32  * To be able to differentiate which client subsystem owns the given session, we
33  * include the client id in the top 8 bits of the handle.
34  */
35 #define HOST_SESSION_CLIENT_MASK GENMASK_ULL(63, 56)
36 
37 static struct xe_gt *
38 gsc_to_gt(struct xe_gsc *gsc)
39 {
40 	return container_of(gsc, struct xe_gt, uc.gsc);
41 }
42 
43 /**
44  * xe_gsc_create_host_session_id - Creates a random 64 bit host_session id with
45  * bits 56-63 masked.
46  *
47  * Returns: random host_session_id which can be used to send messages to gsc cs
48  */
49 u64 xe_gsc_create_host_session_id(void)
50 {
51 	u64 host_session_id;
52 
53 	get_random_bytes(&host_session_id, sizeof(u64));
54 	host_session_id &= ~HOST_SESSION_CLIENT_MASK;
55 	return host_session_id;
56 }
57 
58 /**
59  * xe_gsc_emit_header - write the MTL GSC header in memory
60  * @xe: the Xe device
61  * @map: the iosys map to write to
62  * @offset: offset from the start of the map at which to write the header
63  * @heci_client_id: client id identifying the type of command (see abi for values)
64  * @host_session_id: host session ID of the caller
65  * @payload_size: size of the payload that follows the header
66  *
67  * Returns: offset memory location following the header
68  */
69 u32 xe_gsc_emit_header(struct xe_device *xe, struct iosys_map *map, u32 offset,
70 		       u8 heci_client_id, u64 host_session_id, u32 payload_size)
71 {
72 	xe_assert(xe, !(host_session_id & HOST_SESSION_CLIENT_MASK));
73 
74 	if (host_session_id)
75 		host_session_id |= FIELD_PREP(HOST_SESSION_CLIENT_MASK, heci_client_id);
76 
77 	xe_map_memset(xe, map, offset, 0, GSC_HDR_SIZE);
78 
79 	mtl_gsc_header_wr(xe, map, offset, validity_marker, GSC_HECI_VALIDITY_MARKER);
80 	mtl_gsc_header_wr(xe, map, offset, heci_client_id, heci_client_id);
81 	mtl_gsc_header_wr(xe, map, offset, host_session_handle, host_session_id);
82 	mtl_gsc_header_wr(xe, map, offset, header_version, MTL_GSC_HEADER_VERSION);
83 	mtl_gsc_header_wr(xe, map, offset, message_size, payload_size + GSC_HDR_SIZE);
84 
85 	return offset + GSC_HDR_SIZE;
86 };
87 
88 /**
89  * xe_gsc_poison_header - poison the MTL GSC header in memory
90  * @xe: the Xe device
91  * @map: the iosys map to write to
92  * @offset: offset from the start of the map at which the header resides
93  */
94 void xe_gsc_poison_header(struct xe_device *xe, struct iosys_map *map, u32 offset)
95 {
96 	xe_map_memset(xe, map, offset, POISON_FREE, GSC_HDR_SIZE);
97 };
98 
99 /**
100  * xe_gsc_check_and_update_pending - check the pending bit and update the input
101  * header with the retry handle from the output header
102  * @xe: the Xe device
103  * @in: the iosys map containing the input buffer
104  * @offset_in: offset within the iosys at which the input buffer is located
105  * @out: the iosys map containing the output buffer
106  * @offset_out: offset within the iosys at which the output buffer is located
107  *
108  * Returns: true if the pending bit was set, false otherwise
109  */
110 bool xe_gsc_check_and_update_pending(struct xe_device *xe,
111 				     struct iosys_map *in, u32 offset_in,
112 				     struct iosys_map *out, u32 offset_out)
113 {
114 	if (mtl_gsc_header_rd(xe, out, offset_out, flags) & GSC_OUTFLAG_MSG_PENDING) {
115 		u64 handle = mtl_gsc_header_rd(xe, out, offset_out, gsc_message_handle);
116 
117 		mtl_gsc_header_wr(xe, in, offset_in, gsc_message_handle, handle);
118 
119 		return true;
120 	}
121 
122 	return false;
123 }
124 
125 /**
126  * xe_gsc_read_out_header - reads and validates the output header and returns
127  * the offset of the reply following the header
128  * @xe: the Xe device
129  * @map: the iosys map containing the output buffer
130  * @offset: offset within the iosys at which the output buffer is located
131  * @min_payload_size: minimum size of the message excluding the gsc header
132  * @payload_offset: optional pointer to be set to the payload offset
133  *
134  * Returns: -errno value on failure, 0 otherwise
135  */
136 int xe_gsc_read_out_header(struct xe_device *xe,
137 			   struct iosys_map *map, u32 offset,
138 			   u32 min_payload_size,
139 			   u32 *payload_offset)
140 {
141 	u32 marker = mtl_gsc_header_rd(xe, map, offset, validity_marker);
142 	u32 size = mtl_gsc_header_rd(xe, map, offset, message_size);
143 	u32 status = mtl_gsc_header_rd(xe, map, offset, status);
144 	u32 payload_size = size - GSC_HDR_SIZE;
145 
146 	if (marker != GSC_HECI_VALIDITY_MARKER)
147 		return -EPROTO;
148 
149 	if (status != 0) {
150 		drm_err(&xe->drm, "GSC header readout indicates error: %d\n",
151 			status);
152 		return -EINVAL;
153 	}
154 
155 	if (size < GSC_HDR_SIZE || payload_size < min_payload_size)
156 		return -ENODATA;
157 
158 	if (payload_offset)
159 		*payload_offset = offset + GSC_HDR_SIZE;
160 
161 	return 0;
162 }
163 
164 /**
165  * xe_gsc_pkt_submit_kernel - submit a kernel heci pkt to the GSC
166  * @gsc: the GSC uC
167  * @addr_in: GGTT address of the message to send to the GSC
168  * @size_in: size of the message to send to the GSC
169  * @addr_out: GGTT address for the GSC to write the reply to
170  * @size_out: size of the memory reserved for the reply
171  */
172 int xe_gsc_pkt_submit_kernel(struct xe_gsc *gsc, u64 addr_in, u32 size_in,
173 			     u64 addr_out, u32 size_out)
174 {
175 	struct xe_gt *gt = gsc_to_gt(gsc);
176 	struct xe_bb *bb;
177 	struct xe_sched_job *job;
178 	struct dma_fence *fence;
179 	long timeout;
180 
181 	if (size_in < GSC_HDR_SIZE)
182 		return -ENODATA;
183 
184 	if (size_out < GSC_HDR_SIZE)
185 		return -ENOMEM;
186 
187 	bb = xe_bb_new(gt, 8, false);
188 	if (IS_ERR(bb))
189 		return PTR_ERR(bb);
190 
191 	bb->cs[bb->len++] = GSC_HECI_CMD_PKT;
192 	bb->cs[bb->len++] = lower_32_bits(addr_in);
193 	bb->cs[bb->len++] = upper_32_bits(addr_in);
194 	bb->cs[bb->len++] = size_in;
195 	bb->cs[bb->len++] = lower_32_bits(addr_out);
196 	bb->cs[bb->len++] = upper_32_bits(addr_out);
197 	bb->cs[bb->len++] = size_out;
198 	bb->cs[bb->len++] = 0;
199 
200 	job = xe_bb_create_job(gsc->q, bb);
201 	if (IS_ERR(job)) {
202 		xe_bb_free(bb, NULL);
203 		return PTR_ERR(job);
204 	}
205 
206 	xe_sched_job_arm(job);
207 	fence = dma_fence_get(&job->drm.s_fence->finished);
208 	xe_sched_job_push(job);
209 
210 	timeout = dma_fence_wait_timeout(fence, false, HZ);
211 	dma_fence_put(fence);
212 	xe_bb_free(bb, NULL);
213 	if (timeout < 0)
214 		return timeout;
215 	else if (!timeout)
216 		return -ETIME;
217 
218 	return 0;
219 }
220