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> 31e6188e58Smrg#include "libdrm_macros.h" 3222944501Smrg#include "radeon_cs.h" 3322944501Smrg#include "radeon_bo_int.h" 3422944501Smrg#include "radeon_cs_int.h" 3522944501Smrg 3622944501Smrgstruct rad_sizes { 3722944501Smrg int32_t op_read; 3822944501Smrg int32_t op_gart_write; 3922944501Smrg int32_t op_vram_write; 4022944501Smrg}; 4122944501Smrg 4222944501Smrgstatic inline int radeon_cs_setup_bo(struct radeon_cs_space_check *sc, struct rad_sizes *sizes) 4322944501Smrg{ 4422944501Smrg uint32_t read_domains, write_domain; 4522944501Smrg struct radeon_bo_int *bo; 4622944501Smrg 4722944501Smrg bo = sc->bo; 4822944501Smrg sc->new_accounted = 0; 4922944501Smrg read_domains = sc->read_domains; 5022944501Smrg write_domain = sc->write_domain; 5122944501Smrg 5222944501Smrg /* legacy needs a static check */ 5322944501Smrg if (radeon_bo_is_static((struct radeon_bo *)sc->bo)) { 5422944501Smrg bo->space_accounted = sc->new_accounted = (read_domains << 16) | write_domain; 5522944501Smrg return 0; 5622944501Smrg } 5722944501Smrg 5822944501Smrg /* already accounted this bo */ 5922944501Smrg if (write_domain && (write_domain == bo->space_accounted)) { 6022944501Smrg sc->new_accounted = bo->space_accounted; 6122944501Smrg return 0; 6222944501Smrg } 6322944501Smrg if (read_domains && ((read_domains << 16) == bo->space_accounted)) { 6422944501Smrg sc->new_accounted = bo->space_accounted; 6522944501Smrg return 0; 6622944501Smrg } 6722944501Smrg 6822944501Smrg if (bo->space_accounted == 0) { 69e88f27b3Smrg if (write_domain) { 70e88f27b3Smrg if (write_domain == RADEON_GEM_DOMAIN_VRAM) 71e88f27b3Smrg sizes->op_vram_write += bo->size; 72e88f27b3Smrg else if (write_domain == RADEON_GEM_DOMAIN_GTT) 73e88f27b3Smrg sizes->op_gart_write += bo->size; 74e88f27b3Smrg sc->new_accounted = write_domain; 75e88f27b3Smrg } else { 7622944501Smrg sizes->op_read += bo->size; 77e88f27b3Smrg sc->new_accounted = read_domains << 16; 78e88f27b3Smrg } 7922944501Smrg } else { 8022944501Smrg uint16_t old_read, old_write; 8122944501Smrg 8222944501Smrg old_read = bo->space_accounted >> 16; 8322944501Smrg old_write = bo->space_accounted & 0xffff; 8422944501Smrg 8522944501Smrg if (write_domain && (old_read & write_domain)) { 8622944501Smrg sc->new_accounted = write_domain; 8722944501Smrg /* moving from read to a write domain */ 8822944501Smrg if (write_domain == RADEON_GEM_DOMAIN_VRAM) { 8922944501Smrg sizes->op_read -= bo->size; 9022944501Smrg sizes->op_vram_write += bo->size; 9122944501Smrg } else if (write_domain == RADEON_GEM_DOMAIN_GTT) { 9222944501Smrg sizes->op_read -= bo->size; 9322944501Smrg sizes->op_gart_write += bo->size; 9422944501Smrg } 9522944501Smrg } else if (read_domains & old_write) { 9622944501Smrg sc->new_accounted = bo->space_accounted & 0xffff; 9722944501Smrg } else { 9822944501Smrg /* rewrite the domains */ 9922944501Smrg if (write_domain != old_write) 10022944501Smrg fprintf(stderr,"WRITE DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, write_domain, old_write); 10122944501Smrg if (read_domains != old_read) 10222944501Smrg fprintf(stderr,"READ DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, read_domains, old_read); 10322944501Smrg return RADEON_CS_SPACE_FLUSH; 10422944501Smrg } 10522944501Smrg } 10622944501Smrg return 0; 10722944501Smrg} 10822944501Smrg 10922944501Smrgstatic int radeon_cs_do_space_check(struct radeon_cs_int *cs, struct radeon_cs_space_check *new_tmp) 11022944501Smrg{ 11122944501Smrg struct radeon_cs_manager *csm = cs->csm; 11222944501Smrg int i; 11322944501Smrg struct radeon_bo_int *bo; 11422944501Smrg struct rad_sizes sizes; 11522944501Smrg int ret; 11622944501Smrg 11722944501Smrg /* check the totals for this operation */ 11822944501Smrg 11922944501Smrg if (cs->bo_count == 0 && !new_tmp) 12022944501Smrg return 0; 12122944501Smrg 12222944501Smrg memset(&sizes, 0, sizeof(struct rad_sizes)); 12322944501Smrg 12422944501Smrg /* prepare */ 12522944501Smrg for (i = 0; i < cs->bo_count; i++) { 12622944501Smrg ret = radeon_cs_setup_bo(&cs->bos[i], &sizes); 12722944501Smrg if (ret) 12822944501Smrg return ret; 12922944501Smrg } 13022944501Smrg 13122944501Smrg if (new_tmp) { 13222944501Smrg ret = radeon_cs_setup_bo(new_tmp, &sizes); 13322944501Smrg if (ret) 13422944501Smrg return ret; 13522944501Smrg } 13622944501Smrg 13722944501Smrg if (sizes.op_read < 0) 13822944501Smrg sizes.op_read = 0; 13922944501Smrg 14022944501Smrg /* check sizes - operation first */ 14122944501Smrg if ((sizes.op_read + sizes.op_gart_write > csm->gart_limit) || 14222944501Smrg (sizes.op_vram_write > csm->vram_limit)) { 14322944501Smrg return RADEON_CS_SPACE_OP_TO_BIG; 14422944501Smrg } 14522944501Smrg 14622944501Smrg if (((csm->vram_write_used + sizes.op_vram_write) > csm->vram_limit) || 14722944501Smrg ((csm->read_used + csm->gart_write_used + sizes.op_gart_write + sizes.op_read) > csm->gart_limit)) { 14822944501Smrg return RADEON_CS_SPACE_FLUSH; 14922944501Smrg } 15022944501Smrg 15122944501Smrg csm->gart_write_used += sizes.op_gart_write; 15222944501Smrg csm->vram_write_used += sizes.op_vram_write; 15322944501Smrg csm->read_used += sizes.op_read; 15422944501Smrg /* commit */ 15522944501Smrg for (i = 0; i < cs->bo_count; i++) { 15622944501Smrg bo = cs->bos[i].bo; 15722944501Smrg bo->space_accounted = cs->bos[i].new_accounted; 15822944501Smrg } 15922944501Smrg if (new_tmp) 16022944501Smrg new_tmp->bo->space_accounted = new_tmp->new_accounted; 16122944501Smrg 16222944501Smrg return RADEON_CS_SPACE_OK; 16322944501Smrg} 16422944501Smrg 1657cdc0497Smrgdrm_public void 166baaff307Smrgradeon_cs_space_add_persistent_bo(struct radeon_cs *cs, struct radeon_bo *bo, 167baaff307Smrg uint32_t read_domains, uint32_t write_domain) 16822944501Smrg{ 16922944501Smrg struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; 17022944501Smrg struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; 17122944501Smrg int i; 17222944501Smrg for (i = 0; i < csi->bo_count; i++) { 17322944501Smrg if (csi->bos[i].bo == boi && 17422944501Smrg csi->bos[i].read_domains == read_domains && 17522944501Smrg csi->bos[i].write_domain == write_domain) 17622944501Smrg return; 17722944501Smrg } 17822944501Smrg radeon_bo_ref(bo); 17922944501Smrg i = csi->bo_count; 18022944501Smrg csi->bos[i].bo = boi; 18122944501Smrg csi->bos[i].read_domains = read_domains; 18222944501Smrg csi->bos[i].write_domain = write_domain; 18322944501Smrg csi->bos[i].new_accounted = 0; 18422944501Smrg csi->bo_count++; 18522944501Smrg 18622944501Smrg assert(csi->bo_count < MAX_SPACE_BOS); 18722944501Smrg} 18822944501Smrg 18922944501Smrgstatic int radeon_cs_check_space_internal(struct radeon_cs_int *cs, 19022944501Smrg struct radeon_cs_space_check *tmp_bo) 19122944501Smrg{ 19222944501Smrg int ret; 19322944501Smrg int flushed = 0; 19422944501Smrg 19522944501Smrgagain: 19622944501Smrg ret = radeon_cs_do_space_check(cs, tmp_bo); 19722944501Smrg if (ret == RADEON_CS_SPACE_OP_TO_BIG) 19822944501Smrg return -1; 19922944501Smrg if (ret == RADEON_CS_SPACE_FLUSH) { 20022944501Smrg (*cs->space_flush_fn)(cs->space_flush_data); 20122944501Smrg if (flushed) 20222944501Smrg return -1; 20322944501Smrg flushed = 1; 20422944501Smrg goto again; 20522944501Smrg } 20622944501Smrg return 0; 20722944501Smrg} 20822944501Smrg 2097cdc0497Smrgdrm_public int 210baaff307Smrgradeon_cs_space_check_with_bo(struct radeon_cs *cs, struct radeon_bo *bo, 211baaff307Smrg uint32_t read_domains, uint32_t write_domain) 21222944501Smrg{ 21322944501Smrg struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; 21422944501Smrg struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; 21522944501Smrg struct radeon_cs_space_check temp_bo; 21622944501Smrg 21722944501Smrg int ret = 0; 21822944501Smrg 21922944501Smrg if (bo) { 22022944501Smrg temp_bo.bo = boi; 22122944501Smrg temp_bo.read_domains = read_domains; 22222944501Smrg temp_bo.write_domain = write_domain; 22322944501Smrg temp_bo.new_accounted = 0; 22422944501Smrg } 22522944501Smrg 22622944501Smrg ret = radeon_cs_check_space_internal(csi, bo ? &temp_bo : NULL); 22722944501Smrg return ret; 22822944501Smrg} 22922944501Smrg 2307cdc0497Smrgdrm_public int radeon_cs_space_check(struct radeon_cs *cs) 23122944501Smrg{ 23222944501Smrg struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; 23322944501Smrg return radeon_cs_check_space_internal(csi, NULL); 23422944501Smrg} 23522944501Smrg 2367cdc0497Smrgdrm_public void radeon_cs_space_reset_bos(struct radeon_cs *cs) 23722944501Smrg{ 23822944501Smrg struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; 23922944501Smrg int i; 24022944501Smrg for (i = 0; i < csi->bo_count; i++) { 24122944501Smrg radeon_bo_unref((struct radeon_bo *)csi->bos[i].bo); 24222944501Smrg csi->bos[i].bo = NULL; 24322944501Smrg csi->bos[i].read_domains = 0; 24422944501Smrg csi->bos[i].write_domain = 0; 24522944501Smrg csi->bos[i].new_accounted = 0; 24622944501Smrg } 24722944501Smrg csi->bo_count = 0; 24822944501Smrg} 249