xref: /aosp_15_r20/external/mesa3d/src/amd/vpelib/src/core/config_writer.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /* Copyright 2022 Advanced Micro Devices, Inc.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a
4  * copy of this software and associated documentation files (the "Software"),
5  * to deal in the Software without restriction, including without limitation
6  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7  * and/or sell copies of the Software, and to permit persons to whom the
8  * Software is furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
16  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
17  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19  * OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * Authors: AMD
22  *
23  */
24 
25 #include "vpe_assert.h"
26 #include "config_writer.h"
27 #include "reg_helper.h"
28 #include "common.h"
29 
30 // in bytes
31 #define MAX_DIRECT_CONFIG_SIZE   (4 * 0x10000)
32 #define MAX_INDIRECT_CONFIG_SIZE ((4 + 16 * 3) * sizeof(uint32_t))
33 
config_writer_init(struct config_writer * writer,struct vpe_buf * buf)34 void config_writer_init(struct config_writer *writer, struct vpe_buf *buf)
35 {
36     writer->base_cpu_va  = buf->cpu_va;
37     writer->base_gpu_va  = buf->gpu_va;
38     writer->buf          = buf;
39     writer->type         = CONFIG_TYPE_UNKNOWN;
40     writer->callback_ctx = NULL;
41     writer->callback     = NULL;
42     writer->completed    = false;
43     writer->status       = VPE_STATUS_OK;
44 }
45 
config_writer_set_callback(struct config_writer * writer,void * callback_ctx,config_callback_t callback)46 void config_writer_set_callback(
47     struct config_writer *writer, void *callback_ctx, config_callback_t callback)
48 {
49     writer->callback_ctx = callback_ctx;
50     writer->callback     = callback;
51 }
52 
config_writer_new(struct config_writer * writer)53 static inline void config_writer_new(struct config_writer *writer)
54 {
55     if (writer->status != VPE_STATUS_OK)
56         return;
57 
58     /* Buffer does not have enough space to write */
59     if (writer->buf->size < sizeof(uint32_t)) {
60         writer->status = VPE_STATUS_BUFFER_OVERFLOW;
61         return;
62     }
63     // new base
64     writer->base_cpu_va = writer->buf->cpu_va;
65     writer->base_gpu_va = writer->buf->gpu_va;
66 
67     // new header. don't need to fill it yet until completion
68     writer->buf->cpu_va += sizeof(uint32_t);
69     writer->buf->gpu_va += sizeof(uint32_t);
70     writer->buf->size -= sizeof(uint32_t);
71     writer->completed = false;
72 }
73 
config_writer_set_type(struct config_writer * writer,enum config_type type)74 void config_writer_set_type(struct config_writer *writer, enum config_type type)
75 {
76     VPE_ASSERT(type != CONFIG_TYPE_UNKNOWN);
77 
78     if (writer->status != VPE_STATUS_OK)
79         return;
80 
81     if (writer->type != type) {
82         if (writer->type == CONFIG_TYPE_UNKNOWN) {
83             // new header. don't need to fill it yet until completion
84             config_writer_new(writer);
85         } else {
86             // a new config type, close the previous one
87             config_writer_complete(writer);
88 
89             config_writer_new(writer);
90         }
91         writer->type = type;
92     }
93 }
94 
config_writer_force_new_with_type(struct config_writer * writer,enum config_type type)95 void config_writer_force_new_with_type(struct config_writer *writer, enum config_type type)
96 {
97     VPE_ASSERT(type != CONFIG_TYPE_UNKNOWN);
98 
99     if (writer->status != VPE_STATUS_OK)
100         return;
101 
102     uint64_t size = writer->buf->cpu_va - writer->base_cpu_va;
103 
104     if (writer->type == CONFIG_TYPE_UNKNOWN) {
105         // new header. don't need to fill it yet until completion
106         config_writer_new(writer);
107     } else if (size > 0) {
108         // command not empty, close the previous one
109         config_writer_complete(writer);
110         config_writer_new(writer);
111     }
112     writer->type = type;
113 }
114 
config_writer_fill(struct config_writer * writer,uint32_t value)115 void config_writer_fill(struct config_writer *writer, uint32_t value)
116 {
117     uint32_t *cmd_space;
118     uint64_t  size = writer->buf->cpu_va - writer->base_cpu_va;
119 
120     VPE_ASSERT(writer->type != CONFIG_TYPE_UNKNOWN);
121 
122     if (writer->status != VPE_STATUS_OK)
123         return;
124 
125     // check overflow, open a new one if it is
126     if (writer->type == CONFIG_TYPE_DIRECT) {
127         if (size >= MAX_DIRECT_CONFIG_SIZE) {
128             config_writer_complete(writer);
129             config_writer_new(writer);
130         } else if (writer->completed) {
131             config_writer_new(writer);
132         }
133     } else {
134         if (size >= MAX_INDIRECT_CONFIG_SIZE) {
135             config_writer_complete(writer);
136             config_writer_new(writer);
137         } else if (writer->completed) {
138             config_writer_new(writer);
139         }
140     }
141 
142     /* Buffer does not have enough space to write */
143     if (writer->buf->size < sizeof(uint32_t)) {
144         writer->status = VPE_STATUS_BUFFER_OVERFLOW;
145         return;
146     }
147 
148     cmd_space    = (uint32_t *)(uintptr_t)writer->buf->cpu_va;
149     *cmd_space++ = value;
150     writer->buf->cpu_va += sizeof(uint32_t);
151     writer->buf->gpu_va += sizeof(uint32_t);
152     writer->buf->size -= sizeof(uint32_t);
153 }
154 
config_writer_fill_direct_config_packet_header(struct config_writer * writer,struct vpep_direct_config_packet * packet)155 void config_writer_fill_direct_config_packet_header(
156     struct config_writer *writer, struct vpep_direct_config_packet *packet)
157 {
158     uint32_t *cmd_space;
159     uint64_t  size = writer->buf->cpu_va - writer->base_cpu_va;
160     uint64_t  w_size = sizeof(uint32_t);
161 
162     VPE_ASSERT(writer->type == CONFIG_TYPE_DIRECT);
163 
164     if (writer->status != VPE_STATUS_OK)
165         return;
166 
167     // first + 1 for header, DATA_SIZE + 1 for real data size
168     // for estimate overflow, this function only write packet header
169     if (size + (1 + packet->bits.VPEP_CONFIG_DATA_SIZE + 1) * sizeof(uint32_t) >=
170         MAX_DIRECT_CONFIG_SIZE) {
171         config_writer_complete(writer);
172         config_writer_new(writer);
173     } else if (writer->completed) {
174         config_writer_new(writer);
175     }
176 
177     /* Buffer does not have enough space to write */
178     if (writer->buf->size < w_size) {
179         writer->status = VPE_STATUS_BUFFER_OVERFLOW;
180         return;
181     }
182 
183     cmd_space    = (uint32_t *)(uintptr_t)writer->buf->cpu_va;
184     *cmd_space++ = packet->u32all;
185     writer->buf->cpu_va += w_size;
186     writer->buf->gpu_va += w_size;
187     writer->buf->size -= w_size;
188 }
189 
config_writer_fill_direct_config_packet(struct config_writer * writer,struct vpep_direct_config_packet * packet)190 void config_writer_fill_direct_config_packet(
191     struct config_writer *writer, struct vpep_direct_config_packet *packet)
192 {
193     uint32_t *cmd_space;
194     uint64_t  size = writer->buf->cpu_va - writer->base_cpu_va;
195     uint64_t  w_size = 2 * sizeof(uint32_t);
196 
197     VPE_ASSERT(writer->type == CONFIG_TYPE_DIRECT);
198     VPE_ASSERT(packet->bits.VPEP_CONFIG_DATA_SIZE == 0);
199     if (writer->status != VPE_STATUS_OK)
200         return;
201 
202     // first + 1 for header, DATA_SIZE + 1 for real data size
203     // this function writes both header and the data
204     if (size + 1 + (packet->bits.VPEP_CONFIG_DATA_SIZE + 1) * sizeof(uint32_t) >=
205         MAX_DIRECT_CONFIG_SIZE) {
206         config_writer_complete(writer);
207         config_writer_new(writer);
208     } else if (writer->completed) {
209         config_writer_new(writer);
210     }
211 
212     if (writer->buf->size < w_size) {
213         writer->status = VPE_STATUS_BUFFER_OVERFLOW;
214         return;
215     }
216 
217     cmd_space    = (uint32_t *)(uintptr_t)writer->buf->cpu_va;
218     *cmd_space++ = packet->u32all; // Write header
219     writer->buf->cpu_va += sizeof(uint32_t);
220     writer->buf->gpu_va += sizeof(uint32_t);
221     writer->buf->size -= sizeof(uint32_t);
222     *cmd_space++ = packet->data[0]; // Write data
223     writer->buf->cpu_va += sizeof(uint32_t);
224     writer->buf->gpu_va += sizeof(uint32_t);
225     writer->buf->size -= sizeof(uint32_t);
226 }
227 
config_writer_fill_indirect_data_array(struct config_writer * writer,const uint64_t data_gpuva,uint32_t size)228 void config_writer_fill_indirect_data_array(
229     struct config_writer *writer, const uint64_t data_gpuva, uint32_t size)
230 {
231     VPE_ASSERT(writer->type == CONFIG_TYPE_INDIRECT);
232     VPE_ASSERT(size > 0);
233 
234     // the DATA_ARRAY_SIZE is 1-based, hence -1 from actual size
235     config_writer_fill(writer, VPEC_FIELD_VALUE(VPE_IND_CFG_DATA_ARRAY_SIZE, size - 1));
236     config_writer_fill(writer, ADDR_LO(data_gpuva));
237     config_writer_fill(writer, ADDR_HI(data_gpuva));
238 }
239 
config_writer_fill_indirect_destination(struct config_writer * writer,const uint32_t offset_index,const uint32_t start_index,const uint32_t offset_data)240 void config_writer_fill_indirect_destination(struct config_writer *writer,
241     const uint32_t offset_index, const uint32_t start_index, const uint32_t offset_data)
242 {
243     VPE_ASSERT(writer->type == CONFIG_TYPE_INDIRECT);
244     config_writer_fill(writer, VPEC_FIELD_VALUE(VPE_IND_CFG_PKT_REGISTER_OFFSET, offset_index));
245     config_writer_fill(writer, start_index);
246     config_writer_fill(writer, VPEC_FIELD_VALUE(VPE_IND_CFG_PKT_REGISTER_OFFSET, offset_data));
247 }
248 
config_writer_complete(struct config_writer * writer)249 void config_writer_complete(struct config_writer *writer)
250 {
251     uint32_t *cmd_space = (uint32_t *)(uintptr_t)writer->base_cpu_va;
252     uint64_t  size      = writer->buf->cpu_va - writer->base_cpu_va;
253 
254     if (writer->status != VPE_STATUS_OK)
255         return;
256 
257     VPE_ASSERT(writer->type != CONFIG_TYPE_UNKNOWN);
258     VPE_ASSERT(writer->buf->cpu_va != writer->base_cpu_va);
259 
260     if (writer->type == CONFIG_TYPE_DIRECT) {
261         // -4 for exclude header
262         // VPEP_DIRECT_CONFIG_ARRAY_SIZE is 1-based, hence need -1
263         *cmd_space = VPE_DIR_CFG_CMD_HEADER(((size - 4) / sizeof(uint32_t) - 1));
264     } else {
265         // -4 DW for header, data array size, data array lo and data array hi
266         // /3 DW for each destination reg
267         // NUM_DST is 1-based, hence need -1
268         uint32_t num_dst = (uint32_t)((size - (4 * sizeof(uint32_t))) / (3 * sizeof(uint32_t)) - 1);
269         *cmd_space       = VPE_IND_CFG_CMD_HEADER(num_dst);
270     }
271 
272     writer->completed = true;
273 
274     if (writer->callback) {
275         writer->callback(writer->callback_ctx, writer->base_gpu_va, writer->base_cpu_va, size);
276     }
277 }
278