xref: /aosp_15_r20/external/libdrm/radeon/radeon_cs_space.c (revision 7688df22e49036ff52a766b7101da3a49edadb8c)
1*7688df22SAndroid Build Coastguard Worker /*
2*7688df22SAndroid Build Coastguard Worker  * Copyright © 2009 Red Hat Inc.
3*7688df22SAndroid Build Coastguard Worker  * All Rights Reserved.
4*7688df22SAndroid Build Coastguard Worker  *
5*7688df22SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining
6*7688df22SAndroid Build Coastguard Worker  * a copy of this software and associated documentation files (the
7*7688df22SAndroid Build Coastguard Worker  * "Software"), to deal in the Software without restriction, including
8*7688df22SAndroid Build Coastguard Worker  * without limitation the rights to use, copy, modify, merge, publish,
9*7688df22SAndroid Build Coastguard Worker  * distribute, sub license, and/or sell copies of the Software, and to
10*7688df22SAndroid Build Coastguard Worker  * permit persons to whom the Software is furnished to do so, subject to
11*7688df22SAndroid Build Coastguard Worker  * the following conditions:
12*7688df22SAndroid Build Coastguard Worker  *
13*7688df22SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14*7688df22SAndroid Build Coastguard Worker  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15*7688df22SAndroid Build Coastguard Worker  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16*7688df22SAndroid Build Coastguard Worker  * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
17*7688df22SAndroid Build Coastguard Worker  * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18*7688df22SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*7688df22SAndroid Build Coastguard Worker  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20*7688df22SAndroid Build Coastguard Worker  * USE OR OTHER DEALINGS IN THE SOFTWARE.
21*7688df22SAndroid Build Coastguard Worker  *
22*7688df22SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the
23*7688df22SAndroid Build Coastguard Worker  * next paragraph) shall be included in all copies or substantial portions
24*7688df22SAndroid Build Coastguard Worker  * of the Software.
25*7688df22SAndroid Build Coastguard Worker  */
26*7688df22SAndroid Build Coastguard Worker /*
27*7688df22SAndroid Build Coastguard Worker  */
28*7688df22SAndroid Build Coastguard Worker #include <assert.h>
29*7688df22SAndroid Build Coastguard Worker #include <errno.h>
30*7688df22SAndroid Build Coastguard Worker #include <stdlib.h>
31*7688df22SAndroid Build Coastguard Worker #include "libdrm_macros.h"
32*7688df22SAndroid Build Coastguard Worker #include "radeon_cs.h"
33*7688df22SAndroid Build Coastguard Worker #include "radeon_bo_int.h"
34*7688df22SAndroid Build Coastguard Worker #include "radeon_cs_int.h"
35*7688df22SAndroid Build Coastguard Worker 
36*7688df22SAndroid Build Coastguard Worker struct rad_sizes {
37*7688df22SAndroid Build Coastguard Worker     int32_t op_read;
38*7688df22SAndroid Build Coastguard Worker     int32_t op_gart_write;
39*7688df22SAndroid Build Coastguard Worker     int32_t op_vram_write;
40*7688df22SAndroid Build Coastguard Worker };
41*7688df22SAndroid Build Coastguard Worker 
radeon_cs_setup_bo(struct radeon_cs_space_check * sc,struct rad_sizes * sizes)42*7688df22SAndroid Build Coastguard Worker static inline int radeon_cs_setup_bo(struct radeon_cs_space_check *sc, struct rad_sizes *sizes)
43*7688df22SAndroid Build Coastguard Worker {
44*7688df22SAndroid Build Coastguard Worker     uint32_t read_domains, write_domain;
45*7688df22SAndroid Build Coastguard Worker     struct radeon_bo_int *bo;
46*7688df22SAndroid Build Coastguard Worker 
47*7688df22SAndroid Build Coastguard Worker     bo = sc->bo;
48*7688df22SAndroid Build Coastguard Worker     sc->new_accounted = 0;
49*7688df22SAndroid Build Coastguard Worker     read_domains = sc->read_domains;
50*7688df22SAndroid Build Coastguard Worker     write_domain = sc->write_domain;
51*7688df22SAndroid Build Coastguard Worker 
52*7688df22SAndroid Build Coastguard Worker     /* legacy needs a static check */
53*7688df22SAndroid Build Coastguard Worker     if (radeon_bo_is_static((struct radeon_bo *)sc->bo)) {
54*7688df22SAndroid Build Coastguard Worker         bo->space_accounted = sc->new_accounted = (read_domains << 16) | write_domain;
55*7688df22SAndroid Build Coastguard Worker         return 0;
56*7688df22SAndroid Build Coastguard Worker     }
57*7688df22SAndroid Build Coastguard Worker 
58*7688df22SAndroid Build Coastguard Worker     /* already accounted this bo */
59*7688df22SAndroid Build Coastguard Worker     if (write_domain && (write_domain == bo->space_accounted)) {
60*7688df22SAndroid Build Coastguard Worker         sc->new_accounted = bo->space_accounted;
61*7688df22SAndroid Build Coastguard Worker         return 0;
62*7688df22SAndroid Build Coastguard Worker     }
63*7688df22SAndroid Build Coastguard Worker     if (read_domains && ((read_domains << 16) == bo->space_accounted)) {
64*7688df22SAndroid Build Coastguard Worker         sc->new_accounted = bo->space_accounted;
65*7688df22SAndroid Build Coastguard Worker         return 0;
66*7688df22SAndroid Build Coastguard Worker     }
67*7688df22SAndroid Build Coastguard Worker 
68*7688df22SAndroid Build Coastguard Worker     if (bo->space_accounted == 0) {
69*7688df22SAndroid Build Coastguard Worker         if (write_domain) {
70*7688df22SAndroid Build Coastguard Worker             if (write_domain == RADEON_GEM_DOMAIN_VRAM)
71*7688df22SAndroid Build Coastguard Worker                 sizes->op_vram_write += bo->size;
72*7688df22SAndroid Build Coastguard Worker             else if (write_domain == RADEON_GEM_DOMAIN_GTT)
73*7688df22SAndroid Build Coastguard Worker                 sizes->op_gart_write += bo->size;
74*7688df22SAndroid Build Coastguard Worker             sc->new_accounted = write_domain;
75*7688df22SAndroid Build Coastguard Worker         } else {
76*7688df22SAndroid Build Coastguard Worker             sizes->op_read += bo->size;
77*7688df22SAndroid Build Coastguard Worker             sc->new_accounted = read_domains << 16;
78*7688df22SAndroid Build Coastguard Worker         }
79*7688df22SAndroid Build Coastguard Worker     } else {
80*7688df22SAndroid Build Coastguard Worker         uint16_t old_read, old_write;
81*7688df22SAndroid Build Coastguard Worker 
82*7688df22SAndroid Build Coastguard Worker         old_read = bo->space_accounted >> 16;
83*7688df22SAndroid Build Coastguard Worker         old_write = bo->space_accounted & 0xffff;
84*7688df22SAndroid Build Coastguard Worker 
85*7688df22SAndroid Build Coastguard Worker         if (write_domain && (old_read & write_domain)) {
86*7688df22SAndroid Build Coastguard Worker             sc->new_accounted = write_domain;
87*7688df22SAndroid Build Coastguard Worker             /* moving from read to a write domain */
88*7688df22SAndroid Build Coastguard Worker             if (write_domain == RADEON_GEM_DOMAIN_VRAM) {
89*7688df22SAndroid Build Coastguard Worker                 sizes->op_read -= bo->size;
90*7688df22SAndroid Build Coastguard Worker                 sizes->op_vram_write += bo->size;
91*7688df22SAndroid Build Coastguard Worker             } else if (write_domain == RADEON_GEM_DOMAIN_GTT) {
92*7688df22SAndroid Build Coastguard Worker                 sizes->op_read -= bo->size;
93*7688df22SAndroid Build Coastguard Worker                 sizes->op_gart_write += bo->size;
94*7688df22SAndroid Build Coastguard Worker             }
95*7688df22SAndroid Build Coastguard Worker         } else if (read_domains & old_write) {
96*7688df22SAndroid Build Coastguard Worker             sc->new_accounted = bo->space_accounted & 0xffff;
97*7688df22SAndroid Build Coastguard Worker         } else {
98*7688df22SAndroid Build Coastguard Worker             /* rewrite the domains */
99*7688df22SAndroid Build Coastguard Worker             if (write_domain != old_write)
100*7688df22SAndroid Build Coastguard Worker                 fprintf(stderr,"WRITE DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, write_domain, old_write);
101*7688df22SAndroid Build Coastguard Worker             if (read_domains != old_read)
102*7688df22SAndroid Build Coastguard Worker                fprintf(stderr,"READ DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, read_domains, old_read);
103*7688df22SAndroid Build Coastguard Worker             return RADEON_CS_SPACE_FLUSH;
104*7688df22SAndroid Build Coastguard Worker         }
105*7688df22SAndroid Build Coastguard Worker     }
106*7688df22SAndroid Build Coastguard Worker     return 0;
107*7688df22SAndroid Build Coastguard Worker }
108*7688df22SAndroid Build Coastguard Worker 
radeon_cs_do_space_check(struct radeon_cs_int * cs,struct radeon_cs_space_check * new_tmp)109*7688df22SAndroid Build Coastguard Worker static int radeon_cs_do_space_check(struct radeon_cs_int *cs, struct radeon_cs_space_check *new_tmp)
110*7688df22SAndroid Build Coastguard Worker {
111*7688df22SAndroid Build Coastguard Worker     struct radeon_cs_manager *csm = cs->csm;
112*7688df22SAndroid Build Coastguard Worker     int i;
113*7688df22SAndroid Build Coastguard Worker     struct radeon_bo_int *bo;
114*7688df22SAndroid Build Coastguard Worker     struct rad_sizes sizes;
115*7688df22SAndroid Build Coastguard Worker     int ret;
116*7688df22SAndroid Build Coastguard Worker 
117*7688df22SAndroid Build Coastguard Worker     /* check the totals for this operation */
118*7688df22SAndroid Build Coastguard Worker 
119*7688df22SAndroid Build Coastguard Worker     if (cs->bo_count == 0 && !new_tmp)
120*7688df22SAndroid Build Coastguard Worker         return 0;
121*7688df22SAndroid Build Coastguard Worker 
122*7688df22SAndroid Build Coastguard Worker     memset(&sizes, 0, sizeof(struct rad_sizes));
123*7688df22SAndroid Build Coastguard Worker 
124*7688df22SAndroid Build Coastguard Worker     /* prepare */
125*7688df22SAndroid Build Coastguard Worker     for (i = 0; i < cs->bo_count; i++) {
126*7688df22SAndroid Build Coastguard Worker         ret = radeon_cs_setup_bo(&cs->bos[i], &sizes);
127*7688df22SAndroid Build Coastguard Worker         if (ret)
128*7688df22SAndroid Build Coastguard Worker             return ret;
129*7688df22SAndroid Build Coastguard Worker     }
130*7688df22SAndroid Build Coastguard Worker 
131*7688df22SAndroid Build Coastguard Worker     if (new_tmp) {
132*7688df22SAndroid Build Coastguard Worker         ret = radeon_cs_setup_bo(new_tmp, &sizes);
133*7688df22SAndroid Build Coastguard Worker         if (ret)
134*7688df22SAndroid Build Coastguard Worker             return ret;
135*7688df22SAndroid Build Coastguard Worker     }
136*7688df22SAndroid Build Coastguard Worker 
137*7688df22SAndroid Build Coastguard Worker     if (sizes.op_read < 0)
138*7688df22SAndroid Build Coastguard Worker         sizes.op_read = 0;
139*7688df22SAndroid Build Coastguard Worker 
140*7688df22SAndroid Build Coastguard Worker     /* check sizes - operation first */
141*7688df22SAndroid Build Coastguard Worker     if ((sizes.op_read + sizes.op_gart_write > csm->gart_limit) ||
142*7688df22SAndroid Build Coastguard Worker         (sizes.op_vram_write > csm->vram_limit)) {
143*7688df22SAndroid Build Coastguard Worker         return RADEON_CS_SPACE_OP_TO_BIG;
144*7688df22SAndroid Build Coastguard Worker     }
145*7688df22SAndroid Build Coastguard Worker 
146*7688df22SAndroid Build Coastguard Worker     if (((csm->vram_write_used + sizes.op_vram_write) > csm->vram_limit) ||
147*7688df22SAndroid Build Coastguard Worker         ((csm->read_used + csm->gart_write_used + sizes.op_gart_write + sizes.op_read) > csm->gart_limit)) {
148*7688df22SAndroid Build Coastguard Worker         return RADEON_CS_SPACE_FLUSH;
149*7688df22SAndroid Build Coastguard Worker     }
150*7688df22SAndroid Build Coastguard Worker 
151*7688df22SAndroid Build Coastguard Worker     csm->gart_write_used += sizes.op_gart_write;
152*7688df22SAndroid Build Coastguard Worker     csm->vram_write_used += sizes.op_vram_write;
153*7688df22SAndroid Build Coastguard Worker     csm->read_used += sizes.op_read;
154*7688df22SAndroid Build Coastguard Worker     /* commit */
155*7688df22SAndroid Build Coastguard Worker     for (i = 0; i < cs->bo_count; i++) {
156*7688df22SAndroid Build Coastguard Worker         bo = cs->bos[i].bo;
157*7688df22SAndroid Build Coastguard Worker         bo->space_accounted = cs->bos[i].new_accounted;
158*7688df22SAndroid Build Coastguard Worker     }
159*7688df22SAndroid Build Coastguard Worker     if (new_tmp)
160*7688df22SAndroid Build Coastguard Worker         new_tmp->bo->space_accounted = new_tmp->new_accounted;
161*7688df22SAndroid Build Coastguard Worker 
162*7688df22SAndroid Build Coastguard Worker     return RADEON_CS_SPACE_OK;
163*7688df22SAndroid Build Coastguard Worker }
164*7688df22SAndroid Build Coastguard Worker 
165*7688df22SAndroid Build Coastguard Worker drm_public void
radeon_cs_space_add_persistent_bo(struct radeon_cs * cs,struct radeon_bo * bo,uint32_t read_domains,uint32_t write_domain)166*7688df22SAndroid Build Coastguard Worker radeon_cs_space_add_persistent_bo(struct radeon_cs *cs, struct radeon_bo *bo,
167*7688df22SAndroid Build Coastguard Worker                                   uint32_t read_domains, uint32_t write_domain)
168*7688df22SAndroid Build Coastguard Worker {
169*7688df22SAndroid Build Coastguard Worker     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
170*7688df22SAndroid Build Coastguard Worker     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
171*7688df22SAndroid Build Coastguard Worker     int i;
172*7688df22SAndroid Build Coastguard Worker     for (i = 0; i < csi->bo_count; i++) {
173*7688df22SAndroid Build Coastguard Worker         if (csi->bos[i].bo == boi &&
174*7688df22SAndroid Build Coastguard Worker             csi->bos[i].read_domains == read_domains &&
175*7688df22SAndroid Build Coastguard Worker             csi->bos[i].write_domain == write_domain)
176*7688df22SAndroid Build Coastguard Worker             return;
177*7688df22SAndroid Build Coastguard Worker     }
178*7688df22SAndroid Build Coastguard Worker     radeon_bo_ref(bo);
179*7688df22SAndroid Build Coastguard Worker     i = csi->bo_count;
180*7688df22SAndroid Build Coastguard Worker     csi->bos[i].bo = boi;
181*7688df22SAndroid Build Coastguard Worker     csi->bos[i].read_domains = read_domains;
182*7688df22SAndroid Build Coastguard Worker     csi->bos[i].write_domain = write_domain;
183*7688df22SAndroid Build Coastguard Worker     csi->bos[i].new_accounted = 0;
184*7688df22SAndroid Build Coastguard Worker     csi->bo_count++;
185*7688df22SAndroid Build Coastguard Worker 
186*7688df22SAndroid Build Coastguard Worker     assert(csi->bo_count < MAX_SPACE_BOS);
187*7688df22SAndroid Build Coastguard Worker }
188*7688df22SAndroid Build Coastguard Worker 
radeon_cs_check_space_internal(struct radeon_cs_int * cs,struct radeon_cs_space_check * tmp_bo)189*7688df22SAndroid Build Coastguard Worker static int radeon_cs_check_space_internal(struct radeon_cs_int *cs,
190*7688df22SAndroid Build Coastguard Worker                       struct radeon_cs_space_check *tmp_bo)
191*7688df22SAndroid Build Coastguard Worker {
192*7688df22SAndroid Build Coastguard Worker     int ret;
193*7688df22SAndroid Build Coastguard Worker     int flushed = 0;
194*7688df22SAndroid Build Coastguard Worker 
195*7688df22SAndroid Build Coastguard Worker again:
196*7688df22SAndroid Build Coastguard Worker     ret = radeon_cs_do_space_check(cs, tmp_bo);
197*7688df22SAndroid Build Coastguard Worker     if (ret == RADEON_CS_SPACE_OP_TO_BIG)
198*7688df22SAndroid Build Coastguard Worker         return -1;
199*7688df22SAndroid Build Coastguard Worker     if (ret == RADEON_CS_SPACE_FLUSH) {
200*7688df22SAndroid Build Coastguard Worker         (*cs->space_flush_fn)(cs->space_flush_data);
201*7688df22SAndroid Build Coastguard Worker         if (flushed)
202*7688df22SAndroid Build Coastguard Worker             return -1;
203*7688df22SAndroid Build Coastguard Worker         flushed = 1;
204*7688df22SAndroid Build Coastguard Worker         goto again;
205*7688df22SAndroid Build Coastguard Worker     }
206*7688df22SAndroid Build Coastguard Worker     return 0;
207*7688df22SAndroid Build Coastguard Worker }
208*7688df22SAndroid Build Coastguard Worker 
209*7688df22SAndroid Build Coastguard Worker drm_public int
radeon_cs_space_check_with_bo(struct radeon_cs * cs,struct radeon_bo * bo,uint32_t read_domains,uint32_t write_domain)210*7688df22SAndroid Build Coastguard Worker radeon_cs_space_check_with_bo(struct radeon_cs *cs, struct radeon_bo *bo,
211*7688df22SAndroid Build Coastguard Worker                               uint32_t read_domains, uint32_t write_domain)
212*7688df22SAndroid Build Coastguard Worker {
213*7688df22SAndroid Build Coastguard Worker     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
214*7688df22SAndroid Build Coastguard Worker     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
215*7688df22SAndroid Build Coastguard Worker     struct radeon_cs_space_check temp_bo;
216*7688df22SAndroid Build Coastguard Worker 
217*7688df22SAndroid Build Coastguard Worker     int ret = 0;
218*7688df22SAndroid Build Coastguard Worker 
219*7688df22SAndroid Build Coastguard Worker     if (bo) {
220*7688df22SAndroid Build Coastguard Worker         temp_bo.bo = boi;
221*7688df22SAndroid Build Coastguard Worker         temp_bo.read_domains = read_domains;
222*7688df22SAndroid Build Coastguard Worker         temp_bo.write_domain = write_domain;
223*7688df22SAndroid Build Coastguard Worker         temp_bo.new_accounted = 0;
224*7688df22SAndroid Build Coastguard Worker     }
225*7688df22SAndroid Build Coastguard Worker 
226*7688df22SAndroid Build Coastguard Worker     ret = radeon_cs_check_space_internal(csi, bo ? &temp_bo : NULL);
227*7688df22SAndroid Build Coastguard Worker     return ret;
228*7688df22SAndroid Build Coastguard Worker }
229*7688df22SAndroid Build Coastguard Worker 
radeon_cs_space_check(struct radeon_cs * cs)230*7688df22SAndroid Build Coastguard Worker drm_public int radeon_cs_space_check(struct radeon_cs *cs)
231*7688df22SAndroid Build Coastguard Worker {
232*7688df22SAndroid Build Coastguard Worker     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
233*7688df22SAndroid Build Coastguard Worker     return radeon_cs_check_space_internal(csi, NULL);
234*7688df22SAndroid Build Coastguard Worker }
235*7688df22SAndroid Build Coastguard Worker 
radeon_cs_space_reset_bos(struct radeon_cs * cs)236*7688df22SAndroid Build Coastguard Worker drm_public void radeon_cs_space_reset_bos(struct radeon_cs *cs)
237*7688df22SAndroid Build Coastguard Worker {
238*7688df22SAndroid Build Coastguard Worker     struct radeon_cs_int *csi = (struct radeon_cs_int *)cs;
239*7688df22SAndroid Build Coastguard Worker     int i;
240*7688df22SAndroid Build Coastguard Worker     for (i = 0; i < csi->bo_count; i++) {
241*7688df22SAndroid Build Coastguard Worker         radeon_bo_unref((struct radeon_bo *)csi->bos[i].bo);
242*7688df22SAndroid Build Coastguard Worker         csi->bos[i].bo = NULL;
243*7688df22SAndroid Build Coastguard Worker         csi->bos[i].read_domains = 0;
244*7688df22SAndroid Build Coastguard Worker         csi->bos[i].write_domain = 0;
245*7688df22SAndroid Build Coastguard Worker         csi->bos[i].new_accounted = 0;
246*7688df22SAndroid Build Coastguard Worker     }
247*7688df22SAndroid Build Coastguard Worker     csi->bo_count = 0;
248*7688df22SAndroid Build Coastguard Worker }
249