1b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse/* 2b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * Copyright 2011 Red Hat Inc. 3b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * All Rights Reserved. 4b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * 5b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * Permission is hereby granted, free of charge, to any person obtaining a 6b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * copy of this software and associated documentation files (the 7b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * "Software"), to deal in the Software without restriction, including 8b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * without limitation the rights to use, copy, modify, merge, publish, 9b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * distribute, sub license, and/or sell copies of the Software, and to 10b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * permit persons to whom the Software is furnished to do so, subject to 11b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * the following conditions: 12b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * 13b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 16b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 17b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 19b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * USE OR OTHER DEALINGS IN THE SOFTWARE. 20b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * 21b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * The above copyright notice and this permission notice (including the 22b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * next paragraph) shall be included in all copies or substantial portions 23b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * of the Software. 24b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * 25b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse */ 26b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse/* 27b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * Authors: 28b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * Jerome Glisse <glisse@freedesktop.org> 29b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse */ 30b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse#include "drmP.h" 31b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse#include "drm.h" 32b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse#include "radeon.h" 33b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 34b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisseint radeon_sa_bo_manager_init(struct radeon_device *rdev, 35b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse struct radeon_sa_manager *sa_manager, 36b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse unsigned size, u32 domain) 37b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse{ 38b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse int r; 39b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 40b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse sa_manager->bo = NULL; 41b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse sa_manager->size = size; 42b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse sa_manager->domain = domain; 43b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse INIT_LIST_HEAD(&sa_manager->sa_bo); 44b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 45b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse r = radeon_bo_create(rdev, size, RADEON_GPU_PAGE_SIZE, true, 46b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse RADEON_GEM_DOMAIN_CPU, &sa_manager->bo); 47b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse if (r) { 48b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse dev_err(rdev->dev, "(%d) failed to allocate bo for manager\n", r); 49b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse return r; 50b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 51b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 52b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse return r; 53b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse} 54b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 55b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glissevoid radeon_sa_bo_manager_fini(struct radeon_device *rdev, 56b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse struct radeon_sa_manager *sa_manager) 57b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse{ 58b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse struct radeon_sa_bo *sa_bo, *tmp; 59b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 60b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse if (!list_empty(&sa_manager->sa_bo)) { 61b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse dev_err(rdev->dev, "sa_manager is not empty, clearing anyway\n"); 62b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 63b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse list_for_each_entry_safe(sa_bo, tmp, &sa_manager->sa_bo, list) { 64b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse list_del_init(&sa_bo->list); 65b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 66b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse radeon_bo_unref(&sa_manager->bo); 67b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse sa_manager->size = 0; 68b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse} 69b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 70b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisseint radeon_sa_bo_manager_start(struct radeon_device *rdev, 71b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse struct radeon_sa_manager *sa_manager) 72b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse{ 73b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse int r; 74b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 75b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse if (sa_manager->bo == NULL) { 76b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse dev_err(rdev->dev, "no bo for sa manager\n"); 77b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse return -EINVAL; 78b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 79b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 80b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse /* map the buffer */ 81b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse r = radeon_bo_reserve(sa_manager->bo, false); 82b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse if (r) { 83b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse dev_err(rdev->dev, "(%d) failed to reserve manager bo\n", r); 84b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse return r; 85b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 86b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse r = radeon_bo_pin(sa_manager->bo, sa_manager->domain, &sa_manager->gpu_addr); 87b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse if (r) { 88b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse radeon_bo_unreserve(sa_manager->bo); 89b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse dev_err(rdev->dev, "(%d) failed to pin manager bo\n", r); 90b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse return r; 91b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 92b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse r = radeon_bo_kmap(sa_manager->bo, &sa_manager->cpu_ptr); 93b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse radeon_bo_unreserve(sa_manager->bo); 94b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse return r; 95b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse} 96b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 97b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisseint radeon_sa_bo_manager_suspend(struct radeon_device *rdev, 98b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse struct radeon_sa_manager *sa_manager) 99b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse{ 100b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse int r; 101b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 102b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse if (sa_manager->bo == NULL) { 103b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse dev_err(rdev->dev, "no bo for sa manager\n"); 104b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse return -EINVAL; 105b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 106b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 107b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse r = radeon_bo_reserve(sa_manager->bo, false); 108b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse if (!r) { 109b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse radeon_bo_kunmap(sa_manager->bo); 110b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse radeon_bo_unpin(sa_manager->bo); 111b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse radeon_bo_unreserve(sa_manager->bo); 112b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 113b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse return r; 114b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse} 115b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 116b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse/* 117b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * Principe is simple, we keep a list of sub allocation in offset 118b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * order (first entry has offset == 0, last entry has the highest 119b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * offset). 120b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * 121b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * When allocating new object we first check if there is room at 122b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * the end total_size - (last_object_offset + last_object_size) >= 123b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * alloc_size. If so we allocate new object there. 124b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * 125b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * When there is not enough room at the end, we start waiting for 126b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * each sub object until we reach object_offset+object_size >= 127b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * alloc_size, this object then become the sub object we return. 128b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * 129b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse * Alignment can't be bigger than page size 130b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse */ 131b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisseint radeon_sa_bo_new(struct radeon_device *rdev, 132b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse struct radeon_sa_manager *sa_manager, 133b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse struct radeon_sa_bo *sa_bo, 134b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse unsigned size, unsigned align) 135b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse{ 136b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse struct radeon_sa_bo *tmp; 137b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse struct list_head *head; 138b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse unsigned offset = 0, wasted = 0; 139b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 140b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse BUG_ON(align > RADEON_GPU_PAGE_SIZE); 141b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse BUG_ON(size > sa_manager->size); 142b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 143b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse /* no one ? */ 144b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse head = sa_manager->sa_bo.prev; 145b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse if (list_empty(&sa_manager->sa_bo)) { 146b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse goto out; 147b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 148b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 149b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse /* look for a hole big enough */ 150b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse offset = 0; 151b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse list_for_each_entry(tmp, &sa_manager->sa_bo, list) { 152b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse /* room before this object ? */ 153b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse if ((tmp->offset - offset) >= size) { 154b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse head = tmp->list.prev; 155b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse goto out; 156b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 157b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse offset = tmp->offset + tmp->size; 158b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse wasted = offset % align; 159b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse if (wasted) { 160b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse wasted = align - wasted; 161b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 162b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse offset += wasted; 163b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 164b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse /* room at the end ? */ 165b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse head = sa_manager->sa_bo.prev; 166b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse tmp = list_entry(head, struct radeon_sa_bo, list); 167b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse offset = tmp->offset + tmp->size; 168b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse wasted = offset % align; 169b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse if (wasted) { 170b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse wasted = align - wasted; 171b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 172b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse offset += wasted; 173b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse if ((sa_manager->size - offset) < size) { 174b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse /* failed to find somethings big enough */ 175b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse return -ENOMEM; 176b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse } 177b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 178b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisseout: 179b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse sa_bo->manager = sa_manager; 180b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse sa_bo->offset = offset; 181b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse sa_bo->size = size; 182b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse list_add(&sa_bo->list, head); 183b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse return 0; 184b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse} 185b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse 186b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glissevoid radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo *sa_bo) 187b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse{ 188b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse list_del_init(&sa_bo->list); 189b15ba51207e54245409d6f46e20dab36f906eed1Jerome Glisse} 190