radeon_cs_space.c revision e88f27b3
122944501Smrg/* 222944501Smrg * Copyright © 2009 Red Hat Inc. 322944501Smrg * All Rights Reserved. 422944501Smrg * 522944501Smrg * Permission is hereby granted, free of charge, to any person obtaining 622944501Smrg * a copy of this software and associated documentation files (the 722944501Smrg * "Software"), to deal in the Software without restriction, including 822944501Smrg * without limitation the rights to use, copy, modify, merge, publish, 922944501Smrg * distribute, sub license, and/or sell copies of the Software, and to 1022944501Smrg * permit persons to whom the Software is furnished to do so, subject to 1122944501Smrg * the following conditions: 1222944501Smrg * 1322944501Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1422944501Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 1522944501Smrg * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1622944501Smrg * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS 1722944501Smrg * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1822944501Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1922944501Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2022944501Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. 2122944501Smrg * 2222944501Smrg * The above copyright notice and this permission notice (including the 2322944501Smrg * next paragraph) shall be included in all copies or substantial portions 2422944501Smrg * of the Software. 2522944501Smrg */ 2622944501Smrg/* 2722944501Smrg */ 2822944501Smrg#include <assert.h> 2922944501Smrg#include <errno.h> 3022944501Smrg#include <stdlib.h> 3122944501Smrg#include "radeon_cs.h" 3222944501Smrg#include "radeon_bo_int.h" 3322944501Smrg#include "radeon_cs_int.h" 3422944501Smrg 3522944501Smrgstruct rad_sizes { 3622944501Smrg int32_t op_read; 3722944501Smrg int32_t op_gart_write; 3822944501Smrg int32_t op_vram_write; 3922944501Smrg}; 4022944501Smrg 4122944501Smrgstatic inline int radeon_cs_setup_bo(struct radeon_cs_space_check *sc, struct rad_sizes *sizes) 4222944501Smrg{ 4322944501Smrg uint32_t read_domains, write_domain; 4422944501Smrg struct radeon_bo_int *bo; 4522944501Smrg 4622944501Smrg bo = sc->bo; 4722944501Smrg sc->new_accounted = 0; 4822944501Smrg read_domains = sc->read_domains; 4922944501Smrg write_domain = sc->write_domain; 5022944501Smrg 5122944501Smrg /* legacy needs a static check */ 5222944501Smrg if (radeon_bo_is_static((struct radeon_bo *)sc->bo)) { 5322944501Smrg bo->space_accounted = sc->new_accounted = (read_domains << 16) | write_domain; 5422944501Smrg return 0; 5522944501Smrg } 5622944501Smrg 5722944501Smrg /* already accounted this bo */ 5822944501Smrg if (write_domain && (write_domain == bo->space_accounted)) { 5922944501Smrg sc->new_accounted = bo->space_accounted; 6022944501Smrg return 0; 6122944501Smrg } 6222944501Smrg if (read_domains && ((read_domains << 16) == bo->space_accounted)) { 6322944501Smrg sc->new_accounted = bo->space_accounted; 6422944501Smrg return 0; 6522944501Smrg } 6622944501Smrg 6722944501Smrg if (bo->space_accounted == 0) { 68e88f27b3Smrg if (write_domain) { 69e88f27b3Smrg if (write_domain == RADEON_GEM_DOMAIN_VRAM) 70e88f27b3Smrg sizes->op_vram_write += bo->size; 71e88f27b3Smrg else if (write_domain == RADEON_GEM_DOMAIN_GTT) 72e88f27b3Smrg sizes->op_gart_write += bo->size; 73e88f27b3Smrg sc->new_accounted = write_domain; 74e88f27b3Smrg } else { 7522944501Smrg sizes->op_read += bo->size; 76e88f27b3Smrg sc->new_accounted = read_domains << 16; 77e88f27b3Smrg } 7822944501Smrg } else { 7922944501Smrg uint16_t old_read, old_write; 8022944501Smrg 8122944501Smrg old_read = bo->space_accounted >> 16; 8222944501Smrg old_write = bo->space_accounted & 0xffff; 8322944501Smrg 8422944501Smrg if (write_domain && (old_read & write_domain)) { 8522944501Smrg sc->new_accounted = write_domain; 8622944501Smrg /* moving from read to a write domain */ 8722944501Smrg if (write_domain == RADEON_GEM_DOMAIN_VRAM) { 8822944501Smrg sizes->op_read -= bo->size; 8922944501Smrg sizes->op_vram_write += bo->size; 9022944501Smrg } else if (write_domain == RADEON_GEM_DOMAIN_GTT) { 9122944501Smrg sizes->op_read -= bo->size; 9222944501Smrg sizes->op_gart_write += bo->size; 9322944501Smrg } 9422944501Smrg } else if (read_domains & old_write) { 9522944501Smrg sc->new_accounted = bo->space_accounted & 0xffff; 9622944501Smrg } else { 9722944501Smrg /* rewrite the domains */ 9822944501Smrg if (write_domain != old_write) 9922944501Smrg fprintf(stderr,"WRITE DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, write_domain, old_write); 10022944501Smrg if (read_domains != old_read) 10122944501Smrg fprintf(stderr,"READ DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, read_domains, old_read); 10222944501Smrg return RADEON_CS_SPACE_FLUSH; 10322944501Smrg } 10422944501Smrg } 10522944501Smrg return 0; 10622944501Smrg} 10722944501Smrg 10822944501Smrgstatic int radeon_cs_do_space_check(struct radeon_cs_int *cs, struct radeon_cs_space_check *new_tmp) 10922944501Smrg{ 11022944501Smrg struct radeon_cs_manager *csm = cs->csm; 11122944501Smrg int i; 11222944501Smrg struct radeon_bo_int *bo; 11322944501Smrg struct rad_sizes sizes; 11422944501Smrg int ret; 11522944501Smrg 11622944501Smrg /* check the totals for this operation */ 11722944501Smrg 11822944501Smrg if (cs->bo_count == 0 && !new_tmp) 11922944501Smrg return 0; 12022944501Smrg 12122944501Smrg memset(&sizes, 0, sizeof(struct rad_sizes)); 12222944501Smrg 12322944501Smrg /* prepare */ 12422944501Smrg for (i = 0; i < cs->bo_count; i++) { 12522944501Smrg ret = radeon_cs_setup_bo(&cs->bos[i], &sizes); 12622944501Smrg if (ret) 12722944501Smrg return ret; 12822944501Smrg } 12922944501Smrg 13022944501Smrg if (new_tmp) { 13122944501Smrg ret = radeon_cs_setup_bo(new_tmp, &sizes); 13222944501Smrg if (ret) 13322944501Smrg return ret; 13422944501Smrg } 13522944501Smrg 13622944501Smrg if (sizes.op_read < 0) 13722944501Smrg sizes.op_read = 0; 13822944501Smrg 13922944501Smrg /* check sizes - operation first */ 14022944501Smrg if ((sizes.op_read + sizes.op_gart_write > csm->gart_limit) || 14122944501Smrg (sizes.op_vram_write > csm->vram_limit)) { 14222944501Smrg return RADEON_CS_SPACE_OP_TO_BIG; 14322944501Smrg } 14422944501Smrg 14522944501Smrg if (((csm->vram_write_used + sizes.op_vram_write) > csm->vram_limit) || 14622944501Smrg ((csm->read_used + csm->gart_write_used + sizes.op_gart_write + sizes.op_read) > csm->gart_limit)) { 14722944501Smrg return RADEON_CS_SPACE_FLUSH; 14822944501Smrg } 14922944501Smrg 15022944501Smrg csm->gart_write_used += sizes.op_gart_write; 15122944501Smrg csm->vram_write_used += sizes.op_vram_write; 15222944501Smrg csm->read_used += sizes.op_read; 15322944501Smrg /* commit */ 15422944501Smrg for (i = 0; i < cs->bo_count; i++) { 15522944501Smrg bo = cs->bos[i].bo; 15622944501Smrg bo->space_accounted = cs->bos[i].new_accounted; 15722944501Smrg } 15822944501Smrg if (new_tmp) 15922944501Smrg new_tmp->bo->space_accounted = new_tmp->new_accounted; 16022944501Smrg 16122944501Smrg return RADEON_CS_SPACE_OK; 16222944501Smrg} 16322944501Smrg 16422944501Smrgvoid radeon_cs_space_add_persistent_bo(struct radeon_cs *cs, struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain) 16522944501Smrg{ 16622944501Smrg struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; 16722944501Smrg struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; 16822944501Smrg int i; 16922944501Smrg for (i = 0; i < csi->bo_count; i++) { 17022944501Smrg if (csi->bos[i].bo == boi && 17122944501Smrg csi->bos[i].read_domains == read_domains && 17222944501Smrg csi->bos[i].write_domain == write_domain) 17322944501Smrg return; 17422944501Smrg } 17522944501Smrg radeon_bo_ref(bo); 17622944501Smrg i = csi->bo_count; 17722944501Smrg csi->bos[i].bo = boi; 17822944501Smrg csi->bos[i].read_domains = read_domains; 17922944501Smrg csi->bos[i].write_domain = write_domain; 18022944501Smrg csi->bos[i].new_accounted = 0; 18122944501Smrg csi->bo_count++; 18222944501Smrg 18322944501Smrg assert(csi->bo_count < MAX_SPACE_BOS); 18422944501Smrg} 18522944501Smrg 18622944501Smrgstatic int radeon_cs_check_space_internal(struct radeon_cs_int *cs, 18722944501Smrg struct radeon_cs_space_check *tmp_bo) 18822944501Smrg{ 18922944501Smrg int ret; 19022944501Smrg int flushed = 0; 19122944501Smrg 19222944501Smrgagain: 19322944501Smrg ret = radeon_cs_do_space_check(cs, tmp_bo); 19422944501Smrg if (ret == RADEON_CS_SPACE_OP_TO_BIG) 19522944501Smrg return -1; 19622944501Smrg if (ret == RADEON_CS_SPACE_FLUSH) { 19722944501Smrg (*cs->space_flush_fn)(cs->space_flush_data); 19822944501Smrg if (flushed) 19922944501Smrg return -1; 20022944501Smrg flushed = 1; 20122944501Smrg goto again; 20222944501Smrg } 20322944501Smrg return 0; 20422944501Smrg} 20522944501Smrg 20622944501Smrgint radeon_cs_space_check_with_bo(struct radeon_cs *cs, 20722944501Smrg struct radeon_bo *bo, 20822944501Smrg uint32_t read_domains, uint32_t write_domain) 20922944501Smrg{ 21022944501Smrg struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; 21122944501Smrg struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; 21222944501Smrg struct radeon_cs_space_check temp_bo; 21322944501Smrg 21422944501Smrg int ret = 0; 21522944501Smrg 21622944501Smrg if (bo) { 21722944501Smrg temp_bo.bo = boi; 21822944501Smrg temp_bo.read_domains = read_domains; 21922944501Smrg temp_bo.write_domain = write_domain; 22022944501Smrg temp_bo.new_accounted = 0; 22122944501Smrg } 22222944501Smrg 22322944501Smrg ret = radeon_cs_check_space_internal(csi, bo ? &temp_bo : NULL); 22422944501Smrg return ret; 22522944501Smrg} 22622944501Smrg 22722944501Smrgint radeon_cs_space_check(struct radeon_cs *cs) 22822944501Smrg{ 22922944501Smrg struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; 23022944501Smrg return radeon_cs_check_space_internal(csi, NULL); 23122944501Smrg} 23222944501Smrg 23322944501Smrgvoid radeon_cs_space_reset_bos(struct radeon_cs *cs) 23422944501Smrg{ 23522944501Smrg struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; 23622944501Smrg int i; 23722944501Smrg for (i = 0; i < csi->bo_count; i++) { 23822944501Smrg radeon_bo_unref((struct radeon_bo *)csi->bos[i].bo); 23922944501Smrg csi->bos[i].bo = NULL; 24022944501Smrg csi->bos[i].read_domains = 0; 24122944501Smrg csi->bos[i].write_domain = 0; 24222944501Smrg csi->bos[i].new_accounted = 0; 24322944501Smrg } 24422944501Smrg csi->bo_count = 0; 24522944501Smrg} 246