drm/ttm: flip over the range manager to self allocated nodes
[linux-2.6-microblaze.git] / drivers / gpu / drm / ttm / ttm_resource.c
1 /*
2  * Copyright 2020 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: Christian König
23  */
24
25 #include <drm/ttm/ttm_resource.h>
26 #include <drm/ttm/ttm_bo_driver.h>
27
28 void ttm_resource_init(struct ttm_buffer_object *bo,
29                        const struct ttm_place *place,
30                        struct ttm_resource *res)
31 {
32         res->mm_node = NULL;
33         res->start = 0;
34         res->num_pages = PFN_UP(bo->base.size);
35         res->mem_type = place->mem_type;
36         res->placement = place->flags;
37         res->bus.addr = NULL;
38         res->bus.offset = 0;
39         res->bus.is_iomem = false;
40         res->bus.caching = ttm_cached;
41 }
42 EXPORT_SYMBOL(ttm_resource_init);
43
44 int ttm_resource_alloc(struct ttm_buffer_object *bo,
45                        const struct ttm_place *place,
46                        struct ttm_resource **res_ptr)
47 {
48         struct ttm_resource_manager *man =
49                 ttm_manager_type(bo->bdev, place->mem_type);
50         struct ttm_resource *res;
51         int r;
52
53         res = kmalloc(sizeof(*res), GFP_KERNEL);
54         if (!res)
55                 return -ENOMEM;
56
57         ttm_resource_init(bo, place, res);
58         r = man->func->alloc(man, bo, place, res);
59         if (r) {
60                 kfree(res);
61                 return r;
62         }
63
64         *res_ptr = res;
65         return 0;
66 }
67
68 void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res)
69 {
70         struct ttm_resource_manager *man;
71
72         if (!*res)
73                 return;
74
75         man = ttm_manager_type(bo->bdev, (*res)->mem_type);
76         man->func->free(man, *res);
77         kfree(*res);
78         *res = NULL;
79 }
80 EXPORT_SYMBOL(ttm_resource_free);
81
82 /**
83  * ttm_resource_manager_init
84  *
85  * @man: memory manager object to init
86  * @p_size: size managed area in pages.
87  *
88  * Initialise core parts of a manager object.
89  */
90 void ttm_resource_manager_init(struct ttm_resource_manager *man,
91                                unsigned long p_size)
92 {
93         unsigned i;
94
95         spin_lock_init(&man->move_lock);
96         man->size = p_size;
97
98         for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
99                 INIT_LIST_HEAD(&man->lru[i]);
100         man->move = NULL;
101 }
102 EXPORT_SYMBOL(ttm_resource_manager_init);
103
104 /*
105  * ttm_resource_manager_evict_all
106  *
107  * @bdev - device to use
108  * @man - manager to use
109  *
110  * Evict all the objects out of a memory manager until it is empty.
111  * Part of memory manager cleanup sequence.
112  */
113 int ttm_resource_manager_evict_all(struct ttm_device *bdev,
114                                    struct ttm_resource_manager *man)
115 {
116         struct ttm_operation_ctx ctx = {
117                 .interruptible = false,
118                 .no_wait_gpu = false,
119                 .force_alloc = true
120         };
121         struct dma_fence *fence;
122         int ret;
123         unsigned i;
124
125         /*
126          * Can't use standard list traversal since we're unlocking.
127          */
128
129         spin_lock(&bdev->lru_lock);
130         for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
131                 while (!list_empty(&man->lru[i])) {
132                         spin_unlock(&bdev->lru_lock);
133                         ret = ttm_mem_evict_first(bdev, man, NULL, &ctx,
134                                                   NULL);
135                         if (ret)
136                                 return ret;
137                         spin_lock(&bdev->lru_lock);
138                 }
139         }
140         spin_unlock(&bdev->lru_lock);
141
142         spin_lock(&man->move_lock);
143         fence = dma_fence_get(man->move);
144         spin_unlock(&man->move_lock);
145
146         if (fence) {
147                 ret = dma_fence_wait(fence, false);
148                 dma_fence_put(fence);
149                 if (ret)
150                         return ret;
151         }
152
153         return 0;
154 }
155 EXPORT_SYMBOL(ttm_resource_manager_evict_all);
156
157 /**
158  * ttm_resource_manager_debug
159  *
160  * @man: manager type to dump.
161  * @p: printer to use for debug.
162  */
163 void ttm_resource_manager_debug(struct ttm_resource_manager *man,
164                                 struct drm_printer *p)
165 {
166         drm_printf(p, "  use_type: %d\n", man->use_type);
167         drm_printf(p, "  use_tt: %d\n", man->use_tt);
168         drm_printf(p, "  size: %llu\n", man->size);
169         if (man->func->debug)
170                 man->func->debug(man, p);
171 }
172 EXPORT_SYMBOL(ttm_resource_manager_debug);