• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "vpe_command.h"
27 #include "config_writer.h"
28 #include "reg_helper.h"
29 #include "common.h"
30 
31 // in bytes
32 #define MAX_DIRECT_CONFIG_SIZE   (4 * 0x10000)
33 #define MAX_INDIRECT_CONFIG_SIZE ((4 + 16 * 3) * sizeof(uint32_t))
34 
config_writer_init(struct config_writer * writer,struct vpe_buf * buf)35 void config_writer_init(struct config_writer *writer, struct vpe_buf *buf)
36 {
37     writer->base_cpu_va  = buf->cpu_va;
38     writer->base_gpu_va  = buf->gpu_va;
39     writer->buf          = buf;
40     writer->type         = CONFIG_TYPE_UNKNOWN;
41     writer->callback_ctx = NULL;
42     writer->callback     = NULL;
43     writer->completed    = false;
44     writer->status       = VPE_STATUS_OK;
45 }
46 
config_writer_set_callback(struct config_writer * writer,void * callback_ctx,config_callback_t callback)47 void config_writer_set_callback(
48     struct config_writer *writer, void *callback_ctx, config_callback_t callback)
49 {
50     writer->callback_ctx = callback_ctx;
51     writer->callback     = callback;
52 }
53 
config_writer_new(struct config_writer * writer)54 static inline void config_writer_new(struct config_writer *writer)
55 {
56     if (writer->status != VPE_STATUS_OK)
57         return;
58 
59     /* Buffer does not have enough space to write */
60     if (writer->buf->size < sizeof(uint32_t)) {
61         writer->status = VPE_STATUS_BUFFER_OVERFLOW;
62         return;
63     }
64     // new base
65     writer->base_cpu_va = writer->buf->cpu_va;
66     writer->base_gpu_va = writer->buf->gpu_va;
67 
68     // new header. don't need to fill it yet until completion
69     writer->buf->cpu_va += sizeof(uint32_t);
70     writer->buf->gpu_va += sizeof(uint32_t);
71     writer->buf->size -= sizeof(uint32_t);
72     writer->completed = false;
73 }
74 
config_writer_set_type(struct config_writer * writer,enum config_type type)75 void config_writer_set_type(struct config_writer *writer, enum config_type type)
76 {
77     VPE_ASSERT(type != CONFIG_TYPE_UNKNOWN);
78 
79     if (writer->status != VPE_STATUS_OK)
80         return;
81 
82     if (writer->type != type) {
83         if (writer->type == CONFIG_TYPE_UNKNOWN) {
84             // new header. don't need to fill it yet until completion
85             config_writer_new(writer);
86         } else {
87             // a new config type, close the previous one
88             config_writer_complete(writer);
89 
90             config_writer_new(writer);
91         }
92         writer->type = type;
93     }
94 }
95 
config_writer_fill(struct config_writer * writer,uint32_t value)96 void config_writer_fill(struct config_writer *writer, uint32_t value)
97 {
98     uint32_t *cmd_space;
99     uint64_t  size = writer->buf->cpu_va - writer->base_cpu_va;
100 
101     VPE_ASSERT(writer->type != CONFIG_TYPE_UNKNOWN);
102 
103     if (writer->status != VPE_STATUS_OK)
104         return;
105 
106     // check overflow, open a new one if it is
107     if (writer->type == CONFIG_TYPE_DIRECT) {
108         if (size >= MAX_DIRECT_CONFIG_SIZE) {
109             config_writer_complete(writer);
110             config_writer_new(writer);
111         } else if (writer->completed) {
112             config_writer_new(writer);
113         }
114     } else {
115         if (size >= MAX_INDIRECT_CONFIG_SIZE) {
116             config_writer_complete(writer);
117             config_writer_new(writer);
118         } else if (writer->completed) {
119             config_writer_new(writer);
120         }
121     }
122 
123     /* Buffer does not have enough space to write */
124     if (writer->buf->size < sizeof(uint32_t)) {
125         writer->status = VPE_STATUS_BUFFER_OVERFLOW;
126         return;
127     }
128 
129     cmd_space    = (uint32_t *)(uintptr_t)writer->buf->cpu_va;
130     *cmd_space++ = value;
131     writer->buf->cpu_va += sizeof(uint32_t);
132     writer->buf->gpu_va += sizeof(uint32_t);
133     writer->buf->size -= sizeof(uint32_t);
134 }
135 
config_writer_fill_direct_config_packet_header(struct config_writer * writer,struct vpep_direct_config_packet * packet)136 void config_writer_fill_direct_config_packet_header(
137     struct config_writer *writer, struct vpep_direct_config_packet *packet)
138 {
139     uint32_t *cmd_space;
140     uint64_t  size = writer->buf->cpu_va - writer->base_cpu_va;
141     uint64_t  w_size = sizeof(uint32_t);
142 
143     VPE_ASSERT(writer->type == CONFIG_TYPE_DIRECT);
144 
145     if (writer->status != VPE_STATUS_OK)
146         return;
147 
148     // first + 1 for header, DATA_SIZE + 1 for real data size
149     // for estimate overflow, this function only write packet header
150     if (size + (1 + packet->bits.VPEP_CONFIG_DATA_SIZE + 1) * sizeof(uint32_t) >=
151         MAX_DIRECT_CONFIG_SIZE) {
152         config_writer_complete(writer);
153         config_writer_new(writer);
154     } else if (writer->completed) {
155         config_writer_new(writer);
156     }
157 
158     /* Buffer does not have enough space to write */
159     if (writer->buf->size < w_size) {
160         writer->status = VPE_STATUS_BUFFER_OVERFLOW;
161         return;
162     }
163 
164     cmd_space    = (uint32_t *)(uintptr_t)writer->buf->cpu_va;
165     *cmd_space++ = packet->u32all;
166     writer->buf->cpu_va += w_size;
167     writer->buf->gpu_va += w_size;
168     writer->buf->size -= w_size;
169 }
170 
config_writer_fill_direct_config_packet(struct config_writer * writer,struct vpep_direct_config_packet * packet)171 void config_writer_fill_direct_config_packet(
172     struct config_writer *writer, struct vpep_direct_config_packet *packet)
173 {
174     uint32_t *cmd_space;
175     uint64_t  size = writer->buf->cpu_va - writer->base_cpu_va;
176     uint64_t  w_size = 2 * sizeof(uint32_t);
177 
178     VPE_ASSERT(writer->type == CONFIG_TYPE_DIRECT);
179     VPE_ASSERT(packet->bits.VPEP_CONFIG_DATA_SIZE == 0);
180     if (writer->status != VPE_STATUS_OK)
181         return;
182 
183     // first + 1 for header, DATA_SIZE + 1 for real data size
184     // this function writes both header and the data
185     if (size + 1 + (packet->bits.VPEP_CONFIG_DATA_SIZE + 1) * sizeof(uint32_t) >=
186         MAX_DIRECT_CONFIG_SIZE) {
187         config_writer_complete(writer);
188         config_writer_new(writer);
189     } else if (writer->completed) {
190         config_writer_new(writer);
191     }
192 
193     if (writer->buf->size < w_size) {
194         writer->status = VPE_STATUS_BUFFER_OVERFLOW;
195         return;
196     }
197 
198     cmd_space    = (uint32_t *)(uintptr_t)writer->buf->cpu_va;
199     *cmd_space++ = packet->u32all; // Write header
200     writer->buf->cpu_va += sizeof(uint32_t);
201     writer->buf->gpu_va += sizeof(uint32_t);
202     writer->buf->size -= sizeof(uint32_t);
203     *cmd_space++ = packet->data[0]; // Write data
204     writer->buf->cpu_va += sizeof(uint32_t);
205     writer->buf->gpu_va += sizeof(uint32_t);
206     writer->buf->size -= sizeof(uint32_t);
207 }
208 
config_writer_fill_indirect_data_array(struct config_writer * writer,const uint64_t data_gpuva,uint32_t size)209 void config_writer_fill_indirect_data_array(
210     struct config_writer *writer, const uint64_t data_gpuva, uint32_t size)
211 {
212     VPE_ASSERT(writer->type == CONFIG_TYPE_INDIRECT);
213     VPE_ASSERT(size > 0);
214 
215     // the DATA_ARRAY_SIZE is 1-based, hence -1 from actual size
216     config_writer_fill(writer, VPEC_FIELD_VALUE(VPE_IND_CFG_DATA_ARRAY_SIZE, size - 1));
217     config_writer_fill(writer, ADDR_LO(data_gpuva));
218     config_writer_fill(writer, ADDR_HI(data_gpuva));
219 }
220 
config_writer_fill_indirect_destination(struct config_writer * writer,const uint32_t offset_index,const uint32_t start_index,const uint32_t offset_data)221 void config_writer_fill_indirect_destination(struct config_writer *writer,
222     const uint32_t offset_index, const uint32_t start_index, const uint32_t offset_data)
223 {
224     VPE_ASSERT(writer->type == CONFIG_TYPE_INDIRECT);
225     config_writer_fill(writer, VPEC_FIELD_VALUE(VPE_IND_CFG_PKT_REGISTER_OFFSET, offset_index));
226     config_writer_fill(writer, start_index);
227     config_writer_fill(writer, VPEC_FIELD_VALUE(VPE_IND_CFG_PKT_REGISTER_OFFSET, offset_data));
228 }
229 
config_writer_complete(struct config_writer * writer)230 void config_writer_complete(struct config_writer *writer)
231 {
232     uint32_t *cmd_space = (uint32_t *)(uintptr_t)writer->base_cpu_va;
233     uint64_t  size      = writer->buf->cpu_va - writer->base_cpu_va;
234 
235     if (writer->status != VPE_STATUS_OK)
236         return;
237 
238     VPE_ASSERT(writer->type != CONFIG_TYPE_UNKNOWN);
239     VPE_ASSERT(writer->buf->cpu_va != writer->base_cpu_va);
240 
241     if (writer->type == CONFIG_TYPE_DIRECT) {
242         // -4 for exclude header
243         // VPEP_DIRECT_CONFIG_ARRAY_SIZE is 1-based, hence need -1
244         *cmd_space = VPE_DIR_CFG_CMD_HEADER(((size - 4) / sizeof(uint32_t) - 1));
245     } else {
246         // -4 DW for header, data array size, data array lo and data array hi
247         // /3 DW for each destination reg
248         // NUM_DST is 1-based, hence need -1
249         uint32_t num_dst = (uint32_t)((size - (4 * sizeof(uint32_t))) / (3 * sizeof(uint32_t)) - 1);
250         *cmd_space       = VPE_IND_CFG_CMD_HEADER(num_dst);
251     }
252 
253     writer->completed = true;
254 
255     if (writer->callback) {
256         writer->callback(writer->callback_ctx, writer->base_gpu_va, writer->base_cpu_va, size);
257     }
258 }
259