1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2019 Raspberry Pi Ltd
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#ifndef V3DV_CL_H
25bf215546Sopenharmony_ci#define V3DV_CL_H
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "broadcom/cle/v3d_packet_helpers.h"
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "list.h"
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_cistruct v3dv_bo;
32bf215546Sopenharmony_cistruct v3dv_job;
33bf215546Sopenharmony_cistruct v3dv_cl;
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_civoid v3dv_job_add_bo(struct v3dv_job *job, struct v3dv_bo *bo);
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci/**
38bf215546Sopenharmony_ci * Undefined structure, used for typechecking that you're passing the pointers
39bf215546Sopenharmony_ci * to these functions correctly.
40bf215546Sopenharmony_ci */
41bf215546Sopenharmony_cistruct v3dv_cl_out;
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci/** A reference to a BO used in the CL packing functions */
44bf215546Sopenharmony_cistruct v3dv_cl_reloc {
45bf215546Sopenharmony_ci   struct v3dv_bo *bo;
46bf215546Sopenharmony_ci   uint32_t offset;
47bf215546Sopenharmony_ci};
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_cistatic inline void
50bf215546Sopenharmony_cipack_emit_reloc(void *cl, const void *reloc) {}
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci#define __gen_user_data struct v3dv_cl
53bf215546Sopenharmony_ci#define __gen_address_type struct v3dv_cl_reloc
54bf215546Sopenharmony_ci#define __gen_address_offset(reloc) (((reloc)->bo ? (reloc)->bo->offset : 0) + \
55bf215546Sopenharmony_ci                                     (reloc)->offset)
56bf215546Sopenharmony_ci#define __gen_emit_reloc cl_pack_emit_reloc
57bf215546Sopenharmony_ci#define __gen_unpack_address(cl, s, e) __unpack_address(cl, s, e)
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_cistruct v3dv_cl {
60bf215546Sopenharmony_ci   void *base;
61bf215546Sopenharmony_ci   struct v3dv_job *job;
62bf215546Sopenharmony_ci   struct v3dv_cl_out *next;
63bf215546Sopenharmony_ci   struct v3dv_bo *bo;
64bf215546Sopenharmony_ci   uint32_t size;
65bf215546Sopenharmony_ci   struct list_head bo_list;
66bf215546Sopenharmony_ci};
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_cistatic inline struct v3dv_cl_reloc
69bf215546Sopenharmony_ci__unpack_address(const uint8_t *cl, uint32_t s, uint32_t e)
70bf215546Sopenharmony_ci{
71bf215546Sopenharmony_ci    struct v3dv_cl_reloc reloc =
72bf215546Sopenharmony_ci            { NULL, __gen_unpack_uint(cl, s, e) << (31 - (e - s)) };
73bf215546Sopenharmony_ci    return reloc;
74bf215546Sopenharmony_ci}
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_cistatic inline uint32_t
77bf215546Sopenharmony_civ3dv_cl_offset(struct v3dv_cl *cl)
78bf215546Sopenharmony_ci{
79bf215546Sopenharmony_ci   return (char *)cl->next - (char *)cl->base;
80bf215546Sopenharmony_ci}
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_cistatic inline struct v3dv_cl_reloc
83bf215546Sopenharmony_civ3dv_cl_address(struct v3dv_bo *bo, uint32_t offset)
84bf215546Sopenharmony_ci{
85bf215546Sopenharmony_ci   struct v3dv_cl_reloc reloc = {
86bf215546Sopenharmony_ci      .bo = bo,
87bf215546Sopenharmony_ci      .offset = offset,
88bf215546Sopenharmony_ci   };
89bf215546Sopenharmony_ci   return reloc;
90bf215546Sopenharmony_ci}
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_cistatic inline struct v3dv_cl_reloc
93bf215546Sopenharmony_civ3dv_cl_get_address(struct v3dv_cl *cl)
94bf215546Sopenharmony_ci{
95bf215546Sopenharmony_ci   return (struct v3dv_cl_reloc){ .bo = cl->bo, .offset = v3dv_cl_offset(cl) };
96bf215546Sopenharmony_ci}
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_civoid v3dv_cl_init(struct v3dv_job *job, struct v3dv_cl *cl);
99bf215546Sopenharmony_civoid v3dv_cl_destroy(struct v3dv_cl *cl);
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_cistatic inline struct v3dv_cl_out *
102bf215546Sopenharmony_cicl_start(struct v3dv_cl *cl)
103bf215546Sopenharmony_ci{
104bf215546Sopenharmony_ci   return cl->next;
105bf215546Sopenharmony_ci}
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_cistatic inline void
108bf215546Sopenharmony_cicl_end(struct v3dv_cl *cl, struct v3dv_cl_out *next)
109bf215546Sopenharmony_ci{
110bf215546Sopenharmony_ci   cl->next = next;
111bf215546Sopenharmony_ci   assert(v3dv_cl_offset(cl) <= cl->size);
112bf215546Sopenharmony_ci}
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_cistatic inline void
115bf215546Sopenharmony_cicl_advance(struct v3dv_cl_out **cl, uint32_t n)
116bf215546Sopenharmony_ci{
117bf215546Sopenharmony_ci   (*cl) = (struct v3dv_cl_out *)((char *)(*cl) + n);
118bf215546Sopenharmony_ci}
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_cistatic inline void
121bf215546Sopenharmony_cicl_aligned_u32(struct v3dv_cl_out **cl, uint32_t n)
122bf215546Sopenharmony_ci{
123bf215546Sopenharmony_ci   *(uint32_t *)(*cl) = n;
124bf215546Sopenharmony_ci   cl_advance(cl, 4);
125bf215546Sopenharmony_ci}
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_cistatic inline void
128bf215546Sopenharmony_cicl_aligned_f(struct v3dv_cl_out **cl, float f)
129bf215546Sopenharmony_ci{
130bf215546Sopenharmony_ci   cl_aligned_u32(cl, fui(f));
131bf215546Sopenharmony_ci}
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_cistatic inline void
134bf215546Sopenharmony_cicl_aligned_reloc(struct v3dv_cl *cl,
135bf215546Sopenharmony_ci                 struct v3dv_cl_out **cl_out,
136bf215546Sopenharmony_ci                 struct v3dv_bo *bo,
137bf215546Sopenharmony_ci                 uint32_t offset)
138bf215546Sopenharmony_ci{
139bf215546Sopenharmony_ci   cl_aligned_u32(cl_out, bo->offset + offset);
140bf215546Sopenharmony_ci   v3dv_job_add_bo(cl->job, bo);
141bf215546Sopenharmony_ci}
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ciuint32_t v3dv_cl_ensure_space(struct v3dv_cl *cl, uint32_t space, uint32_t alignment);
144bf215546Sopenharmony_civoid v3dv_cl_ensure_space_with_branch(struct v3dv_cl *cl, uint32_t space);
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci/* We redefine ALIGN as a macro as we want to use cl_aligned_packet_length for
147bf215546Sopenharmony_ci * struct fields
148bf215546Sopenharmony_ci */
149bf215546Sopenharmony_ci#define ALIGN(value, alignment)                           \
150bf215546Sopenharmony_ci        (((value) + (alignment) - 1) & ~((alignment) - 1))
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci#define cl_packet_header(packet) V3DX(packet ## _header)
153bf215546Sopenharmony_ci#define cl_packet_length(packet) V3DX(packet ## _length)
154bf215546Sopenharmony_ci#define cl_aligned_packet_length(packet, alignment) ALIGN(cl_packet_length(packet), alignment)
155bf215546Sopenharmony_ci#define cl_packet_pack(packet)   V3DX(packet ## _pack)
156bf215546Sopenharmony_ci#define cl_packet_struct(packet) V3DX(packet)
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci/* Macro for setting up an emit of a CL struct.  A temporary unpacked struct
159bf215546Sopenharmony_ci * is created, which you get to set fields in of the form:
160bf215546Sopenharmony_ci *
161bf215546Sopenharmony_ci * cl_emit(bcl, FLAT_SHADE_FLAGS, flags) {
162bf215546Sopenharmony_ci *     .flags.flat_shade_flags = 1 << 2,
163bf215546Sopenharmony_ci * }
164bf215546Sopenharmony_ci *
165bf215546Sopenharmony_ci * or default values only can be emitted with just:
166bf215546Sopenharmony_ci *
167bf215546Sopenharmony_ci * cl_emit(bcl, FLAT_SHADE_FLAGS, flags);
168bf215546Sopenharmony_ci *
169bf215546Sopenharmony_ci * The trick here is that we make a for loop that will execute the body
170bf215546Sopenharmony_ci * (either the block or the ';' after the macro invocation) exactly once.
171bf215546Sopenharmony_ci */
172bf215546Sopenharmony_ci#define cl_emit(cl, packet, name)                                \
173bf215546Sopenharmony_ci        for (struct cl_packet_struct(packet) name = {            \
174bf215546Sopenharmony_ci                cl_packet_header(packet)                         \
175bf215546Sopenharmony_ci        },                                                       \
176bf215546Sopenharmony_ci        *_loop_terminate = &name;                                \
177bf215546Sopenharmony_ci        __builtin_expect(_loop_terminate != NULL, 1);            \
178bf215546Sopenharmony_ci        ({                                                       \
179bf215546Sopenharmony_ci                struct v3dv_cl_out *cl_out = cl_start(cl);        \
180bf215546Sopenharmony_ci                cl_packet_pack(packet)(cl, (uint8_t *)cl_out, &name); \
181bf215546Sopenharmony_ci                cl_advance(&cl_out, cl_packet_length(packet));   \
182bf215546Sopenharmony_ci                cl_end(cl, cl_out);                              \
183bf215546Sopenharmony_ci                _loop_terminate = NULL;                          \
184bf215546Sopenharmony_ci        }))                                                      \
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci#define cl_emit_with_prepacked(cl, packet, prepacked, name)      \
187bf215546Sopenharmony_ci        for (struct cl_packet_struct(packet) name = {            \
188bf215546Sopenharmony_ci                cl_packet_header(packet)                         \
189bf215546Sopenharmony_ci        },                                                       \
190bf215546Sopenharmony_ci        *_loop_terminate = &name;                                \
191bf215546Sopenharmony_ci        __builtin_expect(_loop_terminate != NULL, 1);            \
192bf215546Sopenharmony_ci        ({                                                       \
193bf215546Sopenharmony_ci                struct v3dv_cl_out *cl_out = cl_start(cl);        \
194bf215546Sopenharmony_ci                uint8_t packed[cl_packet_length(packet)];         \
195bf215546Sopenharmony_ci                cl_packet_pack(packet)(cl, packed, &name);       \
196bf215546Sopenharmony_ci                for (int _i = 0; _i < cl_packet_length(packet); _i++) \
197bf215546Sopenharmony_ci                        ((uint8_t *)cl_out)[_i] = packed[_i] | (prepacked)[_i]; \
198bf215546Sopenharmony_ci                cl_advance(&cl_out, cl_packet_length(packet));   \
199bf215546Sopenharmony_ci                cl_end(cl, cl_out);                              \
200bf215546Sopenharmony_ci                _loop_terminate = NULL;                          \
201bf215546Sopenharmony_ci        }))                                                      \
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_ci/**
204bf215546Sopenharmony_ci * Helper function called by the XML-generated pack functions for filling in
205bf215546Sopenharmony_ci * an address field in shader records.
206bf215546Sopenharmony_ci *
207bf215546Sopenharmony_ci * Since we have a private address space as of V3D, our BOs can have lifelong
208bf215546Sopenharmony_ci * offsets, and all the kernel needs to know is which BOs need to be paged in
209bf215546Sopenharmony_ci * for this exec.
210bf215546Sopenharmony_ci */
211bf215546Sopenharmony_cistatic inline void
212bf215546Sopenharmony_cicl_pack_emit_reloc(struct v3dv_cl *cl, const struct v3dv_cl_reloc *reloc)
213bf215546Sopenharmony_ci{
214bf215546Sopenharmony_ci        if (reloc->bo)
215bf215546Sopenharmony_ci                v3dv_job_add_bo(cl->job, reloc->bo);
216bf215546Sopenharmony_ci}
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci#define cl_emit_prepacked_sized(cl, packet, size) do {                \
219bf215546Sopenharmony_ci        memcpy((cl)->next, packet, size);             \
220bf215546Sopenharmony_ci        cl_advance(&(cl)->next, size);                \
221bf215546Sopenharmony_ci} while (0)
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci#define cl_emit_prepacked(cl, packet) \
224bf215546Sopenharmony_ci        cl_emit_prepacked_sized(cl, packet, sizeof(*(packet)))
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ci#define v3dvx_pack(packed, packet, name)                         \
227bf215546Sopenharmony_ci        for (struct cl_packet_struct(packet) name = {            \
228bf215546Sopenharmony_ci                cl_packet_header(packet)                         \
229bf215546Sopenharmony_ci        },                                                       \
230bf215546Sopenharmony_ci        *_loop_terminate = &name;                                \
231bf215546Sopenharmony_ci        __builtin_expect(_loop_terminate != NULL, 1);            \
232bf215546Sopenharmony_ci        ({                                                       \
233bf215546Sopenharmony_ci                cl_packet_pack(packet)(NULL, (uint8_t *)packed, &name); \
234bf215546Sopenharmony_ci                VG(VALGRIND_CHECK_MEM_IS_DEFINED((uint8_t *)packed, \
235bf215546Sopenharmony_ci                                                 cl_packet_length(packet))); \
236bf215546Sopenharmony_ci                _loop_terminate = NULL;                          \
237bf215546Sopenharmony_ci        }))                                                      \
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci#endif /* V3DV_CL_H */
240