Home | History | Annotate | Download | only in radeon
      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