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