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