blob: 6d8df76b5a5d54b5cecebcaa46bb34c4337ee712 [file] [log] [blame]
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001/*
2 * Copyright 2008 Jerome Glisse.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Jerome Glisse <glisse@freedesktop.org>
26 */
Stephen Rothwell568d7c72016-03-17 15:30:49 +110027#include <linux/pagemap.h>
Marek Olšák7ca24cf2017-09-12 22:42:14 +020028#include <linux/sync_file.h>
Alex Deucherd38ceaf2015-04-20 16:55:21 -040029#include <drm/drmP.h>
30#include <drm/amdgpu_drm.h>
Dave Airlie660e8552017-03-13 22:18:15 +000031#include <drm/drm_syncobj.h>
Alex Deucherd38ceaf2015-04-20 16:55:21 -040032#include "amdgpu.h"
33#include "amdgpu_trace.h"
Andrey Grodzovskyc8c5e562018-06-12 14:28:20 -040034#include "amdgpu_gmc.h"
Alex Deucherd38ceaf2015-04-20 16:55:21 -040035
Christian König91acbeb2015-12-14 16:42:31 +010036static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
Christian König758ac172016-05-06 22:14:00 +020037 struct drm_amdgpu_cs_chunk_fence *data,
38 uint32_t *offset)
Christian König91acbeb2015-12-14 16:42:31 +010039{
40 struct drm_gem_object *gobj;
Christian Königaa290402016-09-09 11:21:43 +020041 unsigned long size;
Christian König91acbeb2015-12-14 16:42:31 +010042
Chris Wilsona8ad0bd2016-05-09 11:04:54 +010043 gobj = drm_gem_object_lookup(p->filp, data->handle);
Christian König91acbeb2015-12-14 16:42:31 +010044 if (gobj == NULL)
45 return -EINVAL;
46
Christian König758ac172016-05-06 22:14:00 +020047 p->uf_entry.robj = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj));
Christian König91acbeb2015-12-14 16:42:31 +010048 p->uf_entry.priority = 0;
49 p->uf_entry.tv.bo = &p->uf_entry.robj->tbo;
50 p->uf_entry.tv.shared = true;
Christian König2f568db2016-02-23 12:36:59 +010051 p->uf_entry.user_pages = NULL;
Christian Königaa290402016-09-09 11:21:43 +020052
53 size = amdgpu_bo_size(p->uf_entry.robj);
54 if (size != PAGE_SIZE || (data->offset + 8) > size)
55 return -EINVAL;
56
Christian König758ac172016-05-06 22:14:00 +020057 *offset = data->offset;
Christian König91acbeb2015-12-14 16:42:31 +010058
Cihangir Akturkf62facc2017-08-03 14:58:16 +030059 drm_gem_object_put_unlocked(gobj);
Christian König758ac172016-05-06 22:14:00 +020060
61 if (amdgpu_ttm_tt_get_usermm(p->uf_entry.robj->tbo.ttm)) {
62 amdgpu_bo_unref(&p->uf_entry.robj);
63 return -EINVAL;
64 }
65
Christian König91acbeb2015-12-14 16:42:31 +010066 return 0;
67}
68
Andrey Grodzovsky964d0fb2018-07-06 14:16:54 -040069static int amdgpu_cs_bo_handles_chunk(struct amdgpu_cs_parser *p,
70 struct drm_amdgpu_bo_list_in *data)
71{
72 int r;
73 struct drm_amdgpu_bo_list_entry *info = NULL;
74
75 r = amdgpu_bo_create_list_entry_array(data, &info);
76 if (r)
77 return r;
78
79 r = amdgpu_bo_list_create(p->adev, p->filp, info, data->bo_number,
80 &p->bo_list);
81 if (r)
82 goto error_free;
83
84 kvfree(info);
85 return 0;
86
87error_free:
88 if (info)
89 kvfree(info);
90
91 return r;
92}
93
94static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, union drm_amdgpu_cs *cs)
Alex Deucherd38ceaf2015-04-20 16:55:21 -040095{
Christian König4c0b2422016-02-01 11:20:37 +010096 struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
Monk Liuc5637832016-04-19 20:11:32 +080097 struct amdgpu_vm *vm = &fpriv->vm;
Alex Deucherd38ceaf2015-04-20 16:55:21 -040098 uint64_t *chunk_array_user;
Dan Carpenter1d263472015-09-23 13:59:28 +030099 uint64_t *chunk_array;
Christian König50838c82016-02-03 13:44:52 +0100100 unsigned size, num_ibs = 0;
Christian König758ac172016-05-06 22:14:00 +0200101 uint32_t uf_offset = 0;
Dan Carpenter54313502015-09-25 14:36:55 +0300102 int i;
Dan Carpenter1d263472015-09-23 13:59:28 +0300103 int ret;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400104
Dan Carpenter1d263472015-09-23 13:59:28 +0300105 if (cs->in.num_chunks == 0)
106 return 0;
107
108 chunk_array = kmalloc_array(cs->in.num_chunks, sizeof(uint64_t), GFP_KERNEL);
109 if (!chunk_array)
110 return -ENOMEM;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400111
Christian König3cb485f2015-05-11 15:34:59 +0200112 p->ctx = amdgpu_ctx_get(fpriv, cs->in.ctx_id);
113 if (!p->ctx) {
Dan Carpenter1d263472015-09-23 13:59:28 +0300114 ret = -EINVAL;
115 goto free_chunk;
Christian König3cb485f2015-05-11 15:34:59 +0200116 }
Dan Carpenter1d263472015-09-23 13:59:28 +0300117
Monk Liu7716ea52017-10-17 12:08:02 +0800118 /* skip guilty context job */
119 if (atomic_read(&p->ctx->guilty) == 1) {
120 ret = -ECANCELED;
121 goto free_chunk;
122 }
123
Andrey Grodzovsky0ae94442017-10-10 16:50:17 -0400124 mutex_lock(&p->ctx->lock);
125
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400126 /* get chunks */
Christian König7ecc2452017-07-26 17:02:52 +0200127 chunk_array_user = u64_to_user_ptr(cs->in.chunks);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400128 if (copy_from_user(chunk_array, chunk_array_user,
129 sizeof(uint64_t)*cs->in.num_chunks)) {
Dan Carpenter1d263472015-09-23 13:59:28 +0300130 ret = -EFAULT;
Andrey Grodzovsky26eedf62017-10-11 17:02:02 -0400131 goto free_chunk;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400132 }
133
134 p->nchunks = cs->in.num_chunks;
monk.liue60b3442015-07-17 18:39:25 +0800135 p->chunks = kmalloc_array(p->nchunks, sizeof(struct amdgpu_cs_chunk),
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400136 GFP_KERNEL);
Dan Carpenter1d263472015-09-23 13:59:28 +0300137 if (!p->chunks) {
138 ret = -ENOMEM;
Andrey Grodzovsky26eedf62017-10-11 17:02:02 -0400139 goto free_chunk;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400140 }
141
142 for (i = 0; i < p->nchunks; i++) {
143 struct drm_amdgpu_cs_chunk __user **chunk_ptr = NULL;
144 struct drm_amdgpu_cs_chunk user_chunk;
145 uint32_t __user *cdata;
146
Christian König7ecc2452017-07-26 17:02:52 +0200147 chunk_ptr = u64_to_user_ptr(chunk_array[i]);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400148 if (copy_from_user(&user_chunk, chunk_ptr,
149 sizeof(struct drm_amdgpu_cs_chunk))) {
Dan Carpenter1d263472015-09-23 13:59:28 +0300150 ret = -EFAULT;
151 i--;
152 goto free_partial_kdata;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400153 }
154 p->chunks[i].chunk_id = user_chunk.chunk_id;
155 p->chunks[i].length_dw = user_chunk.length_dw;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400156
157 size = p->chunks[i].length_dw;
Christian König7ecc2452017-07-26 17:02:52 +0200158 cdata = u64_to_user_ptr(user_chunk.chunk_data);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400159
Michal Hocko20981052017-05-17 14:23:12 +0200160 p->chunks[i].kdata = kvmalloc_array(size, sizeof(uint32_t), GFP_KERNEL);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400161 if (p->chunks[i].kdata == NULL) {
Dan Carpenter1d263472015-09-23 13:59:28 +0300162 ret = -ENOMEM;
163 i--;
164 goto free_partial_kdata;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400165 }
166 size *= sizeof(uint32_t);
167 if (copy_from_user(p->chunks[i].kdata, cdata, size)) {
Dan Carpenter1d263472015-09-23 13:59:28 +0300168 ret = -EFAULT;
169 goto free_partial_kdata;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400170 }
171
Christian König9a5e8fb2015-06-23 17:07:03 +0200172 switch (p->chunks[i].chunk_id) {
173 case AMDGPU_CHUNK_ID_IB:
Christian König50838c82016-02-03 13:44:52 +0100174 ++num_ibs;
Christian König9a5e8fb2015-06-23 17:07:03 +0200175 break;
176
177 case AMDGPU_CHUNK_ID_FENCE:
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400178 size = sizeof(struct drm_amdgpu_cs_chunk_fence);
Christian König91acbeb2015-12-14 16:42:31 +0100179 if (p->chunks[i].length_dw * sizeof(uint32_t) < size) {
Dan Carpenter1d263472015-09-23 13:59:28 +0300180 ret = -EINVAL;
181 goto free_partial_kdata;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400182 }
Christian König91acbeb2015-12-14 16:42:31 +0100183
Christian König758ac172016-05-06 22:14:00 +0200184 ret = amdgpu_cs_user_fence_chunk(p, p->chunks[i].kdata,
185 &uf_offset);
Christian König91acbeb2015-12-14 16:42:31 +0100186 if (ret)
187 goto free_partial_kdata;
188
Christian König9a5e8fb2015-06-23 17:07:03 +0200189 break;
190
Andrey Grodzovsky964d0fb2018-07-06 14:16:54 -0400191 case AMDGPU_CHUNK_ID_BO_HANDLES:
192 size = sizeof(struct drm_amdgpu_bo_list_in);
193 if (p->chunks[i].length_dw * sizeof(uint32_t) < size) {
194 ret = -EINVAL;
195 goto free_partial_kdata;
196 }
197
198 ret = amdgpu_cs_bo_handles_chunk(p, p->chunks[i].kdata);
199 if (ret)
200 goto free_partial_kdata;
201
202 break;
203
Christian König2b48d322015-06-19 17:31:29 +0200204 case AMDGPU_CHUNK_ID_DEPENDENCIES:
Dave Airlie660e8552017-03-13 22:18:15 +0000205 case AMDGPU_CHUNK_ID_SYNCOBJ_IN:
206 case AMDGPU_CHUNK_ID_SYNCOBJ_OUT:
Christian König2b48d322015-06-19 17:31:29 +0200207 break;
208
Christian König9a5e8fb2015-06-23 17:07:03 +0200209 default:
Dan Carpenter1d263472015-09-23 13:59:28 +0300210 ret = -EINVAL;
211 goto free_partial_kdata;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400212 }
213 }
214
Monk Liuc5637832016-04-19 20:11:32 +0800215 ret = amdgpu_job_alloc(p->adev, num_ibs, &p->job, vm);
Christian König50838c82016-02-03 13:44:52 +0100216 if (ret)
Christian König4acabfe2016-01-31 11:32:04 +0100217 goto free_all_kdata;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400218
Christian Könige55f2b62017-10-09 15:18:43 +0200219 if (p->ctx->vram_lost_counter != p->job->vram_lost_counter) {
220 ret = -ECANCELED;
221 goto free_all_kdata;
222 }
Christian König14e47f92017-10-09 15:04:41 +0200223
Christian Königb5f5acb2016-06-29 13:26:41 +0200224 if (p->uf_entry.robj)
225 p->job->uf_addr = uf_offset;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400226 kfree(chunk_array);
Andrey Grodzovskyefaa9642018-06-28 22:55:27 -0400227
228 /* Use this opportunity to fill in task info for the vm */
229 amdgpu_vm_set_task_info(vm);
230
Dan Carpenter1d263472015-09-23 13:59:28 +0300231 return 0;
232
233free_all_kdata:
234 i = p->nchunks - 1;
235free_partial_kdata:
236 for (; i >= 0; i--)
Michal Hocko20981052017-05-17 14:23:12 +0200237 kvfree(p->chunks[i].kdata);
Dan Carpenter1d263472015-09-23 13:59:28 +0300238 kfree(p->chunks);
Dave Airlie607523d2017-03-10 12:13:04 +1000239 p->chunks = NULL;
240 p->nchunks = 0;
Dan Carpenter1d263472015-09-23 13:59:28 +0300241free_chunk:
242 kfree(chunk_array);
243
244 return ret;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400245}
246
Marek Olšák95844d22016-08-17 23:49:27 +0200247/* Convert microseconds to bytes. */
248static u64 us_to_bytes(struct amdgpu_device *adev, s64 us)
249{
250 if (us <= 0 || !adev->mm_stats.log2_max_MBps)
251 return 0;
252
253 /* Since accum_us is incremented by a million per second, just
254 * multiply it by the number of MB/s to get the number of bytes.
255 */
256 return us << adev->mm_stats.log2_max_MBps;
257}
258
259static s64 bytes_to_us(struct amdgpu_device *adev, u64 bytes)
260{
261 if (!adev->mm_stats.log2_max_MBps)
262 return 0;
263
264 return bytes >> adev->mm_stats.log2_max_MBps;
265}
266
267/* Returns how many bytes TTM can move right now. If no bytes can be moved,
268 * it returns 0. If it returns non-zero, it's OK to move at least one buffer,
269 * which means it can go over the threshold once. If that happens, the driver
270 * will be in debt and no other buffer migrations can be done until that debt
271 * is repaid.
272 *
273 * This approach allows moving a buffer of any size (it's important to allow
274 * that).
275 *
276 * The currency is simply time in microseconds and it increases as the clock
277 * ticks. The accumulated microseconds (us) are converted to bytes and
278 * returned.
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400279 */
John Brooks00f06b22017-06-27 22:33:18 -0400280static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev,
281 u64 *max_bytes,
282 u64 *max_vis_bytes)
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400283{
Marek Olšák95844d22016-08-17 23:49:27 +0200284 s64 time_us, increment_us;
Marek Olšák95844d22016-08-17 23:49:27 +0200285 u64 free_vram, total_vram, used_vram;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400286
Marek Olšák95844d22016-08-17 23:49:27 +0200287 /* Allow a maximum of 200 accumulated ms. This is basically per-IB
288 * throttling.
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400289 *
Marek Olšák95844d22016-08-17 23:49:27 +0200290 * It means that in order to get full max MBps, at least 5 IBs per
291 * second must be submitted and not more than 200ms apart from each
292 * other.
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400293 */
Marek Olšák95844d22016-08-17 23:49:27 +0200294 const s64 us_upper_bound = 200000;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400295
John Brooks00f06b22017-06-27 22:33:18 -0400296 if (!adev->mm_stats.log2_max_MBps) {
297 *max_bytes = 0;
298 *max_vis_bytes = 0;
299 return;
300 }
Marek Olšák95844d22016-08-17 23:49:27 +0200301
Michel Dänzera5ccfe5c22018-07-11 12:00:40 +0200302 total_vram = adev->gmc.real_vram_size - atomic64_read(&adev->vram_pin_size);
Christian König3c848bb2017-08-07 17:46:49 +0200303 used_vram = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
Marek Olšák95844d22016-08-17 23:49:27 +0200304 free_vram = used_vram >= total_vram ? 0 : total_vram - used_vram;
305
306 spin_lock(&adev->mm_stats.lock);
307
308 /* Increase the amount of accumulated us. */
309 time_us = ktime_to_us(ktime_get());
310 increment_us = time_us - adev->mm_stats.last_update_us;
311 adev->mm_stats.last_update_us = time_us;
312 adev->mm_stats.accum_us = min(adev->mm_stats.accum_us + increment_us,
313 us_upper_bound);
314
315 /* This prevents the short period of low performance when the VRAM
316 * usage is low and the driver is in debt or doesn't have enough
317 * accumulated us to fill VRAM quickly.
318 *
319 * The situation can occur in these cases:
320 * - a lot of VRAM is freed by userspace
321 * - the presence of a big buffer causes a lot of evictions
322 * (solution: split buffers into smaller ones)
323 *
324 * If 128 MB or 1/8th of VRAM is free, start filling it now by setting
325 * accum_us to a positive number.
326 */
327 if (free_vram >= 128 * 1024 * 1024 || free_vram >= total_vram / 8) {
328 s64 min_us;
329
330 /* Be more aggresive on dGPUs. Try to fill a portion of free
331 * VRAM now.
332 */
333 if (!(adev->flags & AMD_IS_APU))
334 min_us = bytes_to_us(adev, free_vram / 4);
335 else
336 min_us = 0; /* Reset accum_us on APUs. */
337
338 adev->mm_stats.accum_us = max(min_us, adev->mm_stats.accum_us);
339 }
340
John Brooks00f06b22017-06-27 22:33:18 -0400341 /* This is set to 0 if the driver is in debt to disallow (optional)
Marek Olšák95844d22016-08-17 23:49:27 +0200342 * buffer moves.
343 */
John Brooks00f06b22017-06-27 22:33:18 -0400344 *max_bytes = us_to_bytes(adev, adev->mm_stats.accum_us);
345
346 /* Do the same for visible VRAM if half of it is free */
Andrey Grodzovskyc8c5e562018-06-12 14:28:20 -0400347 if (!amdgpu_gmc_vram_full_visible(&adev->gmc)) {
Christian König770d13b2018-01-12 14:52:22 +0100348 u64 total_vis_vram = adev->gmc.visible_vram_size;
Christian König3c848bb2017-08-07 17:46:49 +0200349 u64 used_vis_vram =
350 amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]);
John Brooks00f06b22017-06-27 22:33:18 -0400351
352 if (used_vis_vram < total_vis_vram) {
353 u64 free_vis_vram = total_vis_vram - used_vis_vram;
354 adev->mm_stats.accum_us_vis = min(adev->mm_stats.accum_us_vis +
355 increment_us, us_upper_bound);
356
357 if (free_vis_vram >= total_vis_vram / 2)
358 adev->mm_stats.accum_us_vis =
359 max(bytes_to_us(adev, free_vis_vram / 2),
360 adev->mm_stats.accum_us_vis);
361 }
362
363 *max_vis_bytes = us_to_bytes(adev, adev->mm_stats.accum_us_vis);
364 } else {
365 *max_vis_bytes = 0;
366 }
Marek Olšák95844d22016-08-17 23:49:27 +0200367
368 spin_unlock(&adev->mm_stats.lock);
Marek Olšák95844d22016-08-17 23:49:27 +0200369}
370
371/* Report how many bytes have really been moved for the last command
372 * submission. This can result in a debt that can stop buffer migrations
373 * temporarily.
374 */
John Brooks00f06b22017-06-27 22:33:18 -0400375void amdgpu_cs_report_moved_bytes(struct amdgpu_device *adev, u64 num_bytes,
376 u64 num_vis_bytes)
Marek Olšák95844d22016-08-17 23:49:27 +0200377{
378 spin_lock(&adev->mm_stats.lock);
379 adev->mm_stats.accum_us -= bytes_to_us(adev, num_bytes);
John Brooks00f06b22017-06-27 22:33:18 -0400380 adev->mm_stats.accum_us_vis -= bytes_to_us(adev, num_vis_bytes);
Marek Olšák95844d22016-08-17 23:49:27 +0200381 spin_unlock(&adev->mm_stats.lock);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400382}
383
Chunming Zhou14fd8332016-08-04 13:05:46 +0800384static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p,
385 struct amdgpu_bo *bo)
386{
Christian Königa7d64de2016-09-15 14:58:48 +0200387 struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
Roger He92518592017-12-08 13:31:52 +0800388 struct ttm_operation_ctx ctx = {
389 .interruptible = true,
390 .no_wait_gpu = false,
Roger Hed330fca2018-02-06 11:22:57 +0800391 .resv = bo->tbo.resv,
392 .flags = 0
Roger He92518592017-12-08 13:31:52 +0800393 };
Chunming Zhou14fd8332016-08-04 13:05:46 +0800394 uint32_t domain;
395 int r;
396
397 if (bo->pin_count)
398 return 0;
399
Marek Olšák95844d22016-08-17 23:49:27 +0200400 /* Don't move this buffer if we have depleted our allowance
401 * to move it. Don't move anything if the threshold is zero.
Chunming Zhou14fd8332016-08-04 13:05:46 +0800402 */
John Brooks00f06b22017-06-27 22:33:18 -0400403 if (p->bytes_moved < p->bytes_moved_threshold) {
Andrey Grodzovskyc8c5e562018-06-12 14:28:20 -0400404 if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
John Brooks00f06b22017-06-27 22:33:18 -0400405 (bo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)) {
406 /* And don't move a CPU_ACCESS_REQUIRED BO to limited
407 * visible VRAM if we've depleted our allowance to do
408 * that.
409 */
410 if (p->bytes_moved_vis < p->bytes_moved_vis_threshold)
Kent Russell6d7d9c52017-08-08 07:58:01 -0400411 domain = bo->preferred_domains;
John Brooks00f06b22017-06-27 22:33:18 -0400412 else
413 domain = bo->allowed_domains;
414 } else {
Kent Russell6d7d9c52017-08-08 07:58:01 -0400415 domain = bo->preferred_domains;
John Brooks00f06b22017-06-27 22:33:18 -0400416 }
417 } else {
Chunming Zhou14fd8332016-08-04 13:05:46 +0800418 domain = bo->allowed_domains;
John Brooks00f06b22017-06-27 22:33:18 -0400419 }
Chunming Zhou14fd8332016-08-04 13:05:46 +0800420
421retry:
422 amdgpu_ttm_placement_from_domain(bo, domain);
Christian König19be5572017-04-12 14:24:39 +0200423 r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
Christian König6af046d2017-04-27 18:20:47 +0200424
425 p->bytes_moved += ctx.bytes_moved;
Andrey Grodzovskyc8c5e562018-06-12 14:28:20 -0400426 if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
Christian König5422a282018-04-05 16:42:03 +0200427 amdgpu_bo_in_cpu_visible_vram(bo))
Christian König6af046d2017-04-27 18:20:47 +0200428 p->bytes_moved_vis += ctx.bytes_moved;
Chunming Zhou14fd8332016-08-04 13:05:46 +0800429
Christian König1abdc3d2016-08-31 17:28:11 +0200430 if (unlikely(r == -ENOMEM) && domain != bo->allowed_domains) {
431 domain = bo->allowed_domains;
432 goto retry;
Chunming Zhou14fd8332016-08-04 13:05:46 +0800433 }
434
435 return r;
436}
437
Christian König662bfa62016-09-01 12:13:18 +0200438/* Last resort, try to evict something from the current working set */
439static bool amdgpu_cs_try_evict(struct amdgpu_cs_parser *p,
Christian Königf7da30d2016-09-28 12:03:04 +0200440 struct amdgpu_bo *validated)
Christian König662bfa62016-09-01 12:13:18 +0200441{
Christian Königf7da30d2016-09-28 12:03:04 +0200442 uint32_t domain = validated->allowed_domains;
Christian König19be5572017-04-12 14:24:39 +0200443 struct ttm_operation_ctx ctx = { true, false };
Christian König662bfa62016-09-01 12:13:18 +0200444 int r;
445
446 if (!p->evictable)
447 return false;
448
449 for (;&p->evictable->tv.head != &p->validated;
450 p->evictable = list_prev_entry(p->evictable, tv.head)) {
451
452 struct amdgpu_bo_list_entry *candidate = p->evictable;
453 struct amdgpu_bo *bo = candidate->robj;
Christian Königa7d64de2016-09-15 14:58:48 +0200454 struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
John Brooks00f06b22017-06-27 22:33:18 -0400455 bool update_bytes_moved_vis;
Christian König662bfa62016-09-01 12:13:18 +0200456 uint32_t other;
457
458 /* If we reached our current BO we can forget it */
Christian Königf7da30d2016-09-28 12:03:04 +0200459 if (candidate->robj == validated)
Christian König662bfa62016-09-01 12:13:18 +0200460 break;
461
Christian König6edc6912017-11-24 11:39:30 +0100462 /* We can't move pinned BOs here */
463 if (bo->pin_count)
464 continue;
465
Christian König662bfa62016-09-01 12:13:18 +0200466 other = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type);
467
468 /* Check if this BO is in one of the domains we need space for */
469 if (!(other & domain))
470 continue;
471
472 /* Check if we can move this BO somewhere else */
473 other = bo->allowed_domains & ~domain;
474 if (!other)
475 continue;
476
477 /* Good we can try to move this BO somewhere else */
John Brooks00f06b22017-06-27 22:33:18 -0400478 update_bytes_moved_vis =
Andrey Grodzovskyc8c5e562018-06-12 14:28:20 -0400479 !amdgpu_gmc_vram_full_visible(&adev->gmc) &&
480 amdgpu_bo_in_cpu_visible_vram(bo);
Christian Königf1018f52018-04-05 14:46:41 +0200481 amdgpu_ttm_placement_from_domain(bo, other);
Christian König19be5572017-04-12 14:24:39 +0200482 r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
Christian Königf1018f52018-04-05 14:46:41 +0200483 p->bytes_moved += ctx.bytes_moved;
John Brooks00f06b22017-06-27 22:33:18 -0400484 if (update_bytes_moved_vis)
Christian Königf1018f52018-04-05 14:46:41 +0200485 p->bytes_moved_vis += ctx.bytes_moved;
Christian König662bfa62016-09-01 12:13:18 +0200486
487 if (unlikely(r))
488 break;
489
490 p->evictable = list_prev_entry(p->evictable, tv.head);
491 list_move(&candidate->tv.head, &p->validated);
492
493 return true;
494 }
495
496 return false;
497}
498
Christian Königf7da30d2016-09-28 12:03:04 +0200499static int amdgpu_cs_validate(void *param, struct amdgpu_bo *bo)
500{
501 struct amdgpu_cs_parser *p = param;
502 int r;
503
504 do {
505 r = amdgpu_cs_bo_validate(p, bo);
506 } while (r == -ENOMEM && amdgpu_cs_try_evict(p, bo));
507 if (r)
508 return r;
509
510 if (bo->shadow)
Alex Xie1cd99a82016-11-30 17:19:40 -0500511 r = amdgpu_cs_bo_validate(p, bo->shadow);
Christian Königf7da30d2016-09-28 12:03:04 +0200512
513 return r;
514}
515
Baoyou Xie761c2e82016-09-03 13:57:14 +0800516static int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p,
Christian Königa5b75052015-09-03 16:40:39 +0200517 struct list_head *validated)
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400518{
Christian König19be5572017-04-12 14:24:39 +0200519 struct ttm_operation_ctx ctx = { true, false };
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400520 struct amdgpu_bo_list_entry *lobj;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400521 int r;
522
Christian Königa5b75052015-09-03 16:40:39 +0200523 list_for_each_entry(lobj, validated, tv.head) {
Christian König36409d122015-12-21 20:31:35 +0100524 struct amdgpu_bo *bo = lobj->robj;
Christian König2f568db2016-02-23 12:36:59 +0100525 bool binding_userptr = false;
Christian Königcc325d12016-02-08 11:08:35 +0100526 struct mm_struct *usermm;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400527
Christian Königcc325d12016-02-08 11:08:35 +0100528 usermm = amdgpu_ttm_tt_get_usermm(bo->tbo.ttm);
529 if (usermm && usermm != current->mm)
530 return -EPERM;
531
Christian König2f568db2016-02-23 12:36:59 +0100532 /* Check if we have user pages and nobody bound the BO already */
Christian Königca666a32017-09-05 14:30:05 +0200533 if (amdgpu_ttm_tt_userptr_needs_pages(bo->tbo.ttm) &&
534 lobj->user_pages) {
Christian König1b0c0f92017-09-05 14:36:44 +0200535 amdgpu_ttm_placement_from_domain(bo,
536 AMDGPU_GEM_DOMAIN_CPU);
Christian König19be5572017-04-12 14:24:39 +0200537 r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
Christian König1b0c0f92017-09-05 14:36:44 +0200538 if (r)
539 return r;
Christian Königa216ab02017-09-02 13:21:31 +0200540 amdgpu_ttm_tt_set_user_pages(bo->tbo.ttm,
541 lobj->user_pages);
Christian König2f568db2016-02-23 12:36:59 +0100542 binding_userptr = true;
543 }
544
Christian König662bfa62016-09-01 12:13:18 +0200545 if (p->evictable == lobj)
546 p->evictable = NULL;
547
Christian Königf7da30d2016-09-28 12:03:04 +0200548 r = amdgpu_cs_validate(p, bo);
Chunming Zhou14fd8332016-08-04 13:05:46 +0800549 if (r)
Christian König36409d122015-12-21 20:31:35 +0100550 return r;
Christian König662bfa62016-09-01 12:13:18 +0200551
Christian König2f568db2016-02-23 12:36:59 +0100552 if (binding_userptr) {
Michal Hocko20981052017-05-17 14:23:12 +0200553 kvfree(lobj->user_pages);
Christian König2f568db2016-02-23 12:36:59 +0100554 lobj->user_pages = NULL;
555 }
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400556 }
557 return 0;
558}
559
Christian König2a7d9bd2015-12-18 20:33:52 +0100560static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
561 union drm_amdgpu_cs *cs)
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400562{
563 struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
Christian König2f568db2016-02-23 12:36:59 +0100564 struct amdgpu_bo_list_entry *e;
Christian Königa5b75052015-09-03 16:40:39 +0200565 struct list_head duplicates;
Christian König2f568db2016-02-23 12:36:59 +0100566 unsigned i, tries = 10;
Emily Deng01d98502018-05-30 10:04:25 +0800567 struct amdgpu_bo *gds;
568 struct amdgpu_bo *gws;
569 struct amdgpu_bo *oa;
Christian König636ce252015-12-18 21:26:47 +0100570 int r;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400571
Christian König2a7d9bd2015-12-18 20:33:52 +0100572 INIT_LIST_HEAD(&p->validated);
573
Andrey Grodzovsky964d0fb2018-07-06 14:16:54 -0400574 /* p->bo_list could already be assigned if AMDGPU_CHUNK_ID_BO_HANDLES is present */
575 if (!p->bo_list)
576 p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle);
577 else
578 mutex_lock(&p->bo_list->lock);
579
monk.liu840d5142015-04-27 15:19:20 +0800580 if (p->bo_list) {
Christian König636ce252015-12-18 21:26:47 +0100581 amdgpu_bo_list_get_list(p->bo_list, &p->validated);
Christian König3fe89772017-09-12 14:25:14 -0400582 if (p->bo_list->first_userptr != p->bo_list->num_entries)
Felix Kuehlinge52482d2018-03-23 15:32:28 -0400583 p->mn = amdgpu_mn_get(p->adev, AMDGPU_MN_TYPE_GFX);
monk.liu840d5142015-04-27 15:19:20 +0800584 }
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400585
Christian König3c0eea62015-12-11 14:39:05 +0100586 INIT_LIST_HEAD(&duplicates);
Christian König56467eb2015-12-11 15:16:32 +0100587 amdgpu_vm_get_pd_bo(&fpriv->vm, &p->validated, &p->vm_pd);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400588
Bas Nieuwenhuizena20ee0b2018-01-31 13:58:55 +0100589 if (p->uf_entry.robj && !p->uf_entry.robj->parent)
Christian König91acbeb2015-12-14 16:42:31 +0100590 list_add(&p->uf_entry.tv.head, &p->validated);
591
Christian König2f568db2016-02-23 12:36:59 +0100592 while (1) {
593 struct list_head need_pages;
594 unsigned i;
595
596 r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true,
597 &duplicates);
Marek Olšákf1037952016-07-30 00:48:39 +0200598 if (unlikely(r != 0)) {
jimqu57d7f9b2016-10-20 14:58:04 +0800599 if (r != -ERESTARTSYS)
600 DRM_ERROR("ttm_eu_reserve_buffers failed.\n");
Christian König2f568db2016-02-23 12:36:59 +0100601 goto error_free_pages;
Marek Olšákf1037952016-07-30 00:48:39 +0200602 }
Christian König2f568db2016-02-23 12:36:59 +0100603
604 /* Without a BO list we don't have userptr BOs */
605 if (!p->bo_list)
606 break;
607
608 INIT_LIST_HEAD(&need_pages);
609 for (i = p->bo_list->first_userptr;
610 i < p->bo_list->num_entries; ++i) {
Christian Königca666a32017-09-05 14:30:05 +0200611 struct amdgpu_bo *bo;
Christian König2f568db2016-02-23 12:36:59 +0100612
613 e = &p->bo_list->array[i];
Christian Königca666a32017-09-05 14:30:05 +0200614 bo = e->robj;
Christian König2f568db2016-02-23 12:36:59 +0100615
Christian Königca666a32017-09-05 14:30:05 +0200616 if (amdgpu_ttm_tt_userptr_invalidated(bo->tbo.ttm,
Christian König2f568db2016-02-23 12:36:59 +0100617 &e->user_invalidated) && e->user_pages) {
618
619 /* We acquired a page array, but somebody
Alex Xie9f69c0f2017-06-20 16:33:02 -0400620 * invalidated it. Free it and try again
Christian König2f568db2016-02-23 12:36:59 +0100621 */
622 release_pages(e->user_pages,
Linus Torvaldse60e1ee2017-11-15 20:42:10 -0800623 bo->tbo.ttm->num_pages);
Michal Hocko20981052017-05-17 14:23:12 +0200624 kvfree(e->user_pages);
Christian König2f568db2016-02-23 12:36:59 +0100625 e->user_pages = NULL;
626 }
627
Christian Königca666a32017-09-05 14:30:05 +0200628 if (amdgpu_ttm_tt_userptr_needs_pages(bo->tbo.ttm) &&
Christian König2f568db2016-02-23 12:36:59 +0100629 !e->user_pages) {
630 list_del(&e->tv.head);
631 list_add(&e->tv.head, &need_pages);
632
633 amdgpu_bo_unreserve(e->robj);
634 }
635 }
636
637 if (list_empty(&need_pages))
638 break;
639
640 /* Unreserve everything again. */
641 ttm_eu_backoff_reservation(&p->ticket, &p->validated);
642
Marek Olšákf1037952016-07-30 00:48:39 +0200643 /* We tried too many times, just abort */
Christian König2f568db2016-02-23 12:36:59 +0100644 if (!--tries) {
645 r = -EDEADLK;
Marek Olšákf1037952016-07-30 00:48:39 +0200646 DRM_ERROR("deadlock in %s\n", __func__);
Christian König2f568db2016-02-23 12:36:59 +0100647 goto error_free_pages;
648 }
649
Alex Xieeb0f0372017-06-08 14:53:26 -0400650 /* Fill the page arrays for all userptrs. */
Christian König2f568db2016-02-23 12:36:59 +0100651 list_for_each_entry(e, &need_pages, tv.head) {
652 struct ttm_tt *ttm = e->robj->tbo.ttm;
653
Michal Hocko20981052017-05-17 14:23:12 +0200654 e->user_pages = kvmalloc_array(ttm->num_pages,
655 sizeof(struct page*),
656 GFP_KERNEL | __GFP_ZERO);
Christian König2f568db2016-02-23 12:36:59 +0100657 if (!e->user_pages) {
658 r = -ENOMEM;
Marek Olšákf1037952016-07-30 00:48:39 +0200659 DRM_ERROR("calloc failure in %s\n", __func__);
Christian König2f568db2016-02-23 12:36:59 +0100660 goto error_free_pages;
661 }
662
663 r = amdgpu_ttm_tt_get_user_pages(ttm, e->user_pages);
664 if (r) {
Marek Olšákf1037952016-07-30 00:48:39 +0200665 DRM_ERROR("amdgpu_ttm_tt_get_user_pages failed.\n");
Michal Hocko20981052017-05-17 14:23:12 +0200666 kvfree(e->user_pages);
Christian König2f568db2016-02-23 12:36:59 +0100667 e->user_pages = NULL;
668 goto error_free_pages;
669 }
670 }
671
672 /* And try again. */
673 list_splice(&need_pages, &p->validated);
674 }
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400675
John Brooks00f06b22017-06-27 22:33:18 -0400676 amdgpu_cs_get_threshold_for_moves(p->adev, &p->bytes_moved_threshold,
677 &p->bytes_moved_vis_threshold);
Christian Königf69f90a12015-12-21 19:47:42 +0100678 p->bytes_moved = 0;
John Brooks00f06b22017-06-27 22:33:18 -0400679 p->bytes_moved_vis = 0;
Christian König662bfa62016-09-01 12:13:18 +0200680 p->evictable = list_last_entry(&p->validated,
681 struct amdgpu_bo_list_entry,
682 tv.head);
Christian Königf69f90a12015-12-21 19:47:42 +0100683
Christian Königf7da30d2016-09-28 12:03:04 +0200684 r = amdgpu_vm_validate_pt_bos(p->adev, &fpriv->vm,
685 amdgpu_cs_validate, p);
686 if (r) {
687 DRM_ERROR("amdgpu_vm_validate_pt_bos() failed.\n");
688 goto error_validate;
689 }
690
Christian Königf69f90a12015-12-21 19:47:42 +0100691 r = amdgpu_cs_list_validate(p, &duplicates);
Marek Olšákf1037952016-07-30 00:48:39 +0200692 if (r) {
693 DRM_ERROR("amdgpu_cs_list_validate(duplicates) failed.\n");
Christian Königa5b75052015-09-03 16:40:39 +0200694 goto error_validate;
Marek Olšákf1037952016-07-30 00:48:39 +0200695 }
Christian Königa5b75052015-09-03 16:40:39 +0200696
Christian Königf69f90a12015-12-21 19:47:42 +0100697 r = amdgpu_cs_list_validate(p, &p->validated);
Marek Olšákf1037952016-07-30 00:48:39 +0200698 if (r) {
699 DRM_ERROR("amdgpu_cs_list_validate(validated) failed.\n");
Christian Königa8480302016-01-05 16:03:39 +0100700 goto error_validate;
Marek Olšákf1037952016-07-30 00:48:39 +0200701 }
Christian Königa8480302016-01-05 16:03:39 +0100702
John Brooks00f06b22017-06-27 22:33:18 -0400703 amdgpu_cs_report_moved_bytes(p->adev, p->bytes_moved,
704 p->bytes_moved_vis);
Emily Deng01d98502018-05-30 10:04:25 +0800705
Christian Königa8480302016-01-05 16:03:39 +0100706 if (p->bo_list) {
707 struct amdgpu_vm *vm = &fpriv->vm;
708 unsigned i;
709
Emily Deng01d98502018-05-30 10:04:25 +0800710 gds = p->bo_list->gds_obj;
711 gws = p->bo_list->gws_obj;
712 oa = p->bo_list->oa_obj;
Christian Königa8480302016-01-05 16:03:39 +0100713 for (i = 0; i < p->bo_list->num_entries; i++) {
714 struct amdgpu_bo *bo = p->bo_list->array[i].robj;
715
716 p->bo_list->array[i].bo_va = amdgpu_vm_bo_find(vm, bo);
717 }
Emily Deng01d98502018-05-30 10:04:25 +0800718 } else {
719 gds = p->adev->gds.gds_gfx_bo;
720 gws = p->adev->gds.gws_gfx_bo;
721 oa = p->adev->gds.oa_gfx_bo;
722 }
Christian Königd88bf582016-05-06 17:50:03 +0200723
Emily Deng01d98502018-05-30 10:04:25 +0800724 if (gds) {
725 p->job->gds_base = amdgpu_bo_gpu_offset(gds);
726 p->job->gds_size = amdgpu_bo_size(gds);
727 }
728 if (gws) {
729 p->job->gws_base = amdgpu_bo_gpu_offset(gws);
730 p->job->gws_size = amdgpu_bo_size(gws);
731 }
732 if (oa) {
733 p->job->oa_base = amdgpu_bo_gpu_offset(oa);
734 p->job->oa_size = amdgpu_bo_size(oa);
Christian Königa8480302016-01-05 16:03:39 +0100735 }
Christian Königa5b75052015-09-03 16:40:39 +0200736
Christian Königc855e252016-09-05 17:00:57 +0200737 if (!r && p->uf_entry.robj) {
738 struct amdgpu_bo *uf = p->uf_entry.robj;
739
Christian Königc5835bb2017-10-27 15:43:14 +0200740 r = amdgpu_ttm_alloc_gart(&uf->tbo);
Christian Königc855e252016-09-05 17:00:57 +0200741 p->job->uf_addr += amdgpu_bo_gpu_offset(uf);
742 }
Christian Königb5f5acb2016-06-29 13:26:41 +0200743
Christian Königa5b75052015-09-03 16:40:39 +0200744error_validate:
Christian Königb6369222017-08-03 11:44:01 -0400745 if (r)
Christian Königa5b75052015-09-03 16:40:39 +0200746 ttm_eu_backoff_reservation(&p->ticket, &p->validated);
747
Christian König2f568db2016-02-23 12:36:59 +0100748error_free_pages:
749
Christian König2f568db2016-02-23 12:36:59 +0100750 if (p->bo_list) {
751 for (i = p->bo_list->first_userptr;
752 i < p->bo_list->num_entries; ++i) {
753 e = &p->bo_list->array[i];
754
755 if (!e->user_pages)
756 continue;
757
758 release_pages(e->user_pages,
Mel Gormanc6f92f92017-11-15 17:37:55 -0800759 e->robj->tbo.ttm->num_pages);
Michal Hocko20981052017-05-17 14:23:12 +0200760 kvfree(e->user_pages);
Christian König2f568db2016-02-23 12:36:59 +0100761 }
762 }
763
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400764 return r;
765}
766
767static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)
768{
769 struct amdgpu_bo_list_entry *e;
770 int r;
771
772 list_for_each_entry(e, &p->validated, tv.head) {
773 struct reservation_object *resv = e->robj->tbo.resv;
Andres Rodriguez177ae092017-09-15 20:44:06 -0400774 r = amdgpu_sync_resv(p->adev, &p->job->sync, resv, p->filp,
775 amdgpu_bo_explicit_sync(e->robj));
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400776
777 if (r)
778 return r;
779 }
780 return 0;
781}
782
Christian König984810f2015-11-14 21:05:35 +0100783/**
784 * cs_parser_fini() - clean parser states
785 * @parser: parser structure holding parsing context.
786 * @error: error number
787 *
788 * If error is set than unvalidate buffer, otherwise just free memory
789 * used by parsing context.
790 **/
Christian Königb6369222017-08-03 11:44:01 -0400791static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error,
792 bool backoff)
Chunming Zhou049fc522015-07-21 14:36:51 +0800793{
Christian König984810f2015-11-14 21:05:35 +0100794 unsigned i;
795
Christian König3fe89772017-09-12 14:25:14 -0400796 if (error && backoff)
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400797 ttm_eu_backoff_reservation(&parser->ticket,
798 &parser->validated);
Dave Airlie660e8552017-03-13 22:18:15 +0000799
800 for (i = 0; i < parser->num_post_dep_syncobjs; i++)
801 drm_syncobj_put(parser->post_dep_syncobjs[i]);
802 kfree(parser->post_dep_syncobjs);
803
Chris Wilsonf54d1862016-10-25 13:00:45 +0100804 dma_fence_put(parser->fence);
Christian König7e52a812015-11-04 15:44:39 +0100805
Andrey Grodzovsky0ae94442017-10-10 16:50:17 -0400806 if (parser->ctx) {
807 mutex_unlock(&parser->ctx->lock);
Christian König3cb485f2015-05-11 15:34:59 +0200808 amdgpu_ctx_put(parser->ctx);
Andrey Grodzovsky0ae94442017-10-10 16:50:17 -0400809 }
Chunming Zhoua3348bb2015-08-18 16:25:46 +0800810 if (parser->bo_list)
811 amdgpu_bo_list_put(parser->bo_list);
812
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400813 for (i = 0; i < parser->nchunks; i++)
Michal Hocko20981052017-05-17 14:23:12 +0200814 kvfree(parser->chunks[i].kdata);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400815 kfree(parser->chunks);
Christian König50838c82016-02-03 13:44:52 +0100816 if (parser->job)
817 amdgpu_job_free(parser->job);
Christian König91acbeb2015-12-14 16:42:31 +0100818 amdgpu_bo_unref(&parser->uf_entry.robj);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400819}
820
Junwei Zhangb85891b2017-01-16 13:59:01 +0800821static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p)
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400822{
823 struct amdgpu_device *adev = p->adev;
Junwei Zhangb85891b2017-01-16 13:59:01 +0800824 struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
825 struct amdgpu_vm *vm = &fpriv->vm;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400826 struct amdgpu_bo_va *bo_va;
827 struct amdgpu_bo *bo;
828 int i, r;
829
Nicolai Hähnlef3467812017-03-23 19:36:31 +0100830 r = amdgpu_vm_clear_freed(adev, vm, NULL);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400831 if (r)
832 return r;
833
Junwei Zhangb85891b2017-01-16 13:59:01 +0800834 r = amdgpu_vm_bo_update(adev, fpriv->prt_va, false);
835 if (r)
836 return r;
837
838 r = amdgpu_sync_fence(adev, &p->job->sync,
Andrey Grodzovskycebb52b2017-11-13 14:47:52 -0500839 fpriv->prt_va->last_pt_update, false);
Junwei Zhangb85891b2017-01-16 13:59:01 +0800840 if (r)
841 return r;
842
Monk Liu24936642017-01-09 15:54:32 +0800843 if (amdgpu_sriov_vf(adev)) {
844 struct dma_fence *f;
Christian König0f4b3c62017-07-31 15:32:40 +0200845
846 bo_va = fpriv->csa_va;
Monk Liu24936642017-01-09 15:54:32 +0800847 BUG_ON(!bo_va);
848 r = amdgpu_vm_bo_update(adev, bo_va, false);
849 if (r)
850 return r;
851
852 f = bo_va->last_pt_update;
Andrey Grodzovskycebb52b2017-11-13 14:47:52 -0500853 r = amdgpu_sync_fence(adev, &p->job->sync, f, false);
Monk Liu24936642017-01-09 15:54:32 +0800854 if (r)
855 return r;
856 }
857
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400858 if (p->bo_list) {
859 for (i = 0; i < p->bo_list->num_entries; i++) {
Chris Wilsonf54d1862016-10-25 13:00:45 +0100860 struct dma_fence *f;
Christian König91e1a522015-07-06 22:06:40 +0200861
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400862 /* ignore duplicates */
863 bo = p->bo_list->array[i].robj;
864 if (!bo)
865 continue;
866
867 bo_va = p->bo_list->array[i].bo_va;
868 if (bo_va == NULL)
869 continue;
870
Christian König99e124f2016-08-16 14:43:17 +0200871 r = amdgpu_vm_bo_update(adev, bo_va, false);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400872 if (r)
873 return r;
874
Chunming Zhoubb1e38a42015-08-03 18:19:38 +0800875 f = bo_va->last_pt_update;
Andrey Grodzovskycebb52b2017-11-13 14:47:52 -0500876 r = amdgpu_sync_fence(adev, &p->job->sync, f, false);
Christian König91e1a522015-07-06 22:06:40 +0200877 if (r)
878 return r;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400879 }
Christian Königb495bd32015-09-10 14:00:35 +0200880
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400881 }
882
Christian König4e55eb32017-09-11 16:54:59 +0200883 r = amdgpu_vm_handle_moved(adev, vm);
Christian Königd5884512017-09-08 14:09:41 +0200884 if (r)
885 return r;
886
Christian König0abc6872017-09-01 20:37:57 +0200887 r = amdgpu_vm_update_directories(adev, vm);
888 if (r)
889 return r;
890
Andrey Grodzovskycebb52b2017-11-13 14:47:52 -0500891 r = amdgpu_sync_fence(adev, &p->job->sync, vm->last_update, false);
Christian Königd5884512017-09-08 14:09:41 +0200892 if (r)
893 return r;
Christian Königb495bd32015-09-10 14:00:35 +0200894
895 if (amdgpu_vm_debug && p->bo_list) {
896 /* Invalidate all BOs to test for userspace bugs */
897 for (i = 0; i < p->bo_list->num_entries; i++) {
898 /* ignore duplicates */
899 bo = p->bo_list->array[i].robj;
900 if (!bo)
901 continue;
902
Christian König3f3333f2017-08-03 14:02:13 +0200903 amdgpu_vm_bo_invalidate(adev, bo, false);
Christian Königb495bd32015-09-10 14:00:35 +0200904 }
905 }
906
907 return r;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400908}
909
910static int amdgpu_cs_ib_vm_chunk(struct amdgpu_device *adev,
Christian Königb07c60c2016-01-31 12:29:04 +0100911 struct amdgpu_cs_parser *p)
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400912{
Christian Königb07c60c2016-01-31 12:29:04 +0100913 struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400914 struct amdgpu_vm *vm = &fpriv->vm;
Christian Königb07c60c2016-01-31 12:29:04 +0100915 struct amdgpu_ring *ring = p->job->ring;
Christian Königc5795c552017-10-12 12:16:33 +0200916 int r;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400917
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400918 /* Only for UVD/VCE VM emulation */
Christian Königc5795c552017-10-12 12:16:33 +0200919 if (p->job->ring->funcs->parse_cs) {
920 unsigned i, j;
Andrey Grodzovskyad864d22017-10-10 16:50:16 -0400921
Christian Königc5795c552017-10-12 12:16:33 +0200922 for (i = 0, j = 0; i < p->nchunks && j < p->job->num_ibs; i++) {
923 struct drm_amdgpu_cs_chunk_ib *chunk_ib;
Andrey Grodzovskyad864d22017-10-10 16:50:16 -0400924 struct amdgpu_bo_va_mapping *m;
925 struct amdgpu_bo *aobj = NULL;
Christian Königc5795c552017-10-12 12:16:33 +0200926 struct amdgpu_cs_chunk *chunk;
Christian Königbb7939b2017-11-06 15:37:01 +0100927 uint64_t offset, va_start;
Christian Königc5795c552017-10-12 12:16:33 +0200928 struct amdgpu_ib *ib;
Andrey Grodzovskyad864d22017-10-10 16:50:16 -0400929 uint8_t *kptr;
930
Christian Königc5795c552017-10-12 12:16:33 +0200931 chunk = &p->chunks[i];
932 ib = &p->job->ibs[j];
933 chunk_ib = chunk->kdata;
934
935 if (chunk->chunk_id != AMDGPU_CHUNK_ID_IB)
936 continue;
937
Christian Königbb7939b2017-11-06 15:37:01 +0100938 va_start = chunk_ib->va_start & AMDGPU_VA_HOLE_MASK;
939 r = amdgpu_cs_find_mapping(p, va_start, &aobj, &m);
Andrey Grodzovskyad864d22017-10-10 16:50:16 -0400940 if (r) {
941 DRM_ERROR("IB va_start is invalid\n");
942 return r;
943 }
944
Christian Königbb7939b2017-11-06 15:37:01 +0100945 if ((va_start + chunk_ib->ib_bytes) >
Christian Königc5795c552017-10-12 12:16:33 +0200946 (m->last + 1) * AMDGPU_GPU_PAGE_SIZE) {
Andrey Grodzovskyad864d22017-10-10 16:50:16 -0400947 DRM_ERROR("IB va_start+ib_bytes is invalid\n");
948 return -EINVAL;
949 }
950
951 /* the IB should be reserved at this point */
952 r = amdgpu_bo_kmap(aobj, (void **)&kptr);
953 if (r) {
954 return r;
955 }
956
957 offset = m->start * AMDGPU_GPU_PAGE_SIZE;
Christian Königbb7939b2017-11-06 15:37:01 +0100958 kptr += va_start - offset;
Andrey Grodzovskyad864d22017-10-10 16:50:16 -0400959
960 memcpy(ib->ptr, kptr, chunk_ib->ib_bytes);
961 amdgpu_bo_kunmap(aobj);
962
Andrey Grodzovskyad864d22017-10-10 16:50:16 -0400963 r = amdgpu_ring_parse_cs(ring, p, j);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400964 if (r)
965 return r;
Christian Königc5795c552017-10-12 12:16:33 +0200966
967 j++;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400968 }
Christian König45088ef2016-10-05 16:49:19 +0200969 }
970
971 if (p->job->vm) {
Christian König3f3333f2017-08-03 14:02:13 +0200972 p->job->vm_pd_addr = amdgpu_bo_gpu_offset(vm->root.base.bo);
Christian König9a795882016-06-22 14:25:55 +0200973
Junwei Zhangb85891b2017-01-16 13:59:01 +0800974 r = amdgpu_bo_vm_update_pte(p);
Christian König9a795882016-06-22 14:25:55 +0200975 if (r)
976 return r;
Michel Dänzer02374bb2018-06-25 11:07:17 +0200977
978 r = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv);
979 if (r)
980 return r;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400981 }
982
Christian König9a795882016-06-22 14:25:55 +0200983 return amdgpu_cs_sync_rings(p);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400984}
985
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400986static int amdgpu_cs_ib_fill(struct amdgpu_device *adev,
987 struct amdgpu_cs_parser *parser)
988{
989 struct amdgpu_fpriv *fpriv = parser->filp->driver_priv;
990 struct amdgpu_vm *vm = &fpriv->vm;
991 int i, j;
Monk Liu9a1b3af2017-03-08 15:51:13 +0800992 int r, ce_preempt = 0, de_preempt = 0;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400993
Christian König50838c82016-02-03 13:44:52 +0100994 for (i = 0, j = 0; i < parser->nchunks && j < parser->job->num_ibs; i++) {
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400995 struct amdgpu_cs_chunk *chunk;
996 struct amdgpu_ib *ib;
997 struct drm_amdgpu_cs_chunk_ib *chunk_ib;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400998 struct amdgpu_ring *ring;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400999
1000 chunk = &parser->chunks[i];
Christian König50838c82016-02-03 13:44:52 +01001001 ib = &parser->job->ibs[j];
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001002 chunk_ib = (struct drm_amdgpu_cs_chunk_ib *)chunk->kdata;
1003
1004 if (chunk->chunk_id != AMDGPU_CHUNK_ID_IB)
1005 continue;
1006
Monk Liu65333e42017-03-27 15:14:53 +08001007 if (chunk_ib->ip_type == AMDGPU_HW_IP_GFX && amdgpu_sriov_vf(adev)) {
Harry Wentlande51a3222017-03-28 11:29:53 -04001008 if (chunk_ib->flags & AMDGPU_IB_FLAG_PREEMPT) {
Monk Liu65333e42017-03-27 15:14:53 +08001009 if (chunk_ib->flags & AMDGPU_IB_FLAG_CE)
1010 ce_preempt++;
1011 else
1012 de_preempt++;
Harry Wentlande51a3222017-03-28 11:29:53 -04001013 }
Monk Liu9a1b3af2017-03-08 15:51:13 +08001014
Monk Liu65333e42017-03-27 15:14:53 +08001015 /* each GFX command submit allows 0 or 1 IB preemptible for CE & DE */
1016 if (ce_preempt > 1 || de_preempt > 1)
Monk Liue9d672b2017-03-15 12:18:57 +08001017 return -EINVAL;
Monk Liu65333e42017-03-27 15:14:53 +08001018 }
Monk Liu9a1b3af2017-03-08 15:51:13 +08001019
Andres Rodriguezeffd9242017-02-16 00:47:32 -05001020 r = amdgpu_queue_mgr_map(adev, &parser->ctx->queue_mgr, chunk_ib->ip_type,
1021 chunk_ib->ip_instance, chunk_ib->ring, &ring);
Marek Olšák3ccec532015-06-02 17:44:49 +02001022 if (r)
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001023 return r;
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001024
Monk Liu2a9ceb82017-03-28 11:00:03 +08001025 if (chunk_ib->flags & AMDGPU_IB_FLAG_PREAMBLE) {
Monk Liu753ad492016-08-26 13:28:28 +08001026 parser->job->preamble_status |= AMDGPU_PREAMBLE_IB_PRESENT;
1027 if (!parser->ctx->preamble_presented) {
1028 parser->job->preamble_status |= AMDGPU_PREAMBLE_IB_PRESENT_FIRST;
1029 parser->ctx->preamble_presented = true;
1030 }
1031 }
1032
Christian Königb07c60c2016-01-31 12:29:04 +01001033 if (parser->job->ring && parser->job->ring != ring)
1034 return -EINVAL;
1035
1036 parser->job->ring = ring;
1037
Andrey Grodzovskyad864d22017-10-10 16:50:16 -04001038 r = amdgpu_ib_get(adev, vm,
1039 ring->funcs->parse_cs ? chunk_ib->ib_bytes : 0,
1040 ib);
1041 if (r) {
1042 DRM_ERROR("Failed to get ib !\n");
1043 return r;
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001044 }
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001045
Christian König45088ef2016-10-05 16:49:19 +02001046 ib->gpu_addr = chunk_ib->va_start;
Marek Olšák3ccec532015-06-02 17:44:49 +02001047 ib->length_dw = chunk_ib->ib_bytes / 4;
Jammy Zhoude807f82015-05-11 23:41:41 +08001048 ib->flags = chunk_ib->flags;
Andrey Grodzovskyad864d22017-10-10 16:50:16 -04001049
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001050 j++;
1051 }
1052
Christian König758ac172016-05-06 22:14:00 +02001053 /* UVD & VCE fw doesn't support user fences */
Christian Königb5f5acb2016-06-29 13:26:41 +02001054 if (parser->job->uf_addr && (
Christian König21cd9422016-10-05 15:36:39 +02001055 parser->job->ring->funcs->type == AMDGPU_RING_TYPE_UVD ||
1056 parser->job->ring->funcs->type == AMDGPU_RING_TYPE_VCE))
Christian König758ac172016-05-06 22:14:00 +02001057 return -EINVAL;
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001058
Andrey Grodzovsky0ae94442017-10-10 16:50:17 -04001059 return amdgpu_ctx_wait_prev_fence(parser->ctx, parser->job->ring->idx);
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001060}
1061
Dave Airlie6f0308e2017-03-09 03:45:52 +00001062static int amdgpu_cs_process_fence_dep(struct amdgpu_cs_parser *p,
1063 struct amdgpu_cs_chunk *chunk)
1064{
1065 struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
1066 unsigned num_deps;
1067 int i, r;
1068 struct drm_amdgpu_cs_chunk_dep *deps;
1069
1070 deps = (struct drm_amdgpu_cs_chunk_dep *)chunk->kdata;
1071 num_deps = chunk->length_dw * 4 /
1072 sizeof(struct drm_amdgpu_cs_chunk_dep);
1073
1074 for (i = 0; i < num_deps; ++i) {
1075 struct amdgpu_ring *ring;
1076 struct amdgpu_ctx *ctx;
1077 struct dma_fence *fence;
1078
1079 ctx = amdgpu_ctx_get(fpriv, deps[i].ctx_id);
1080 if (ctx == NULL)
1081 return -EINVAL;
1082
1083 r = amdgpu_queue_mgr_map(p->adev, &ctx->queue_mgr,
1084 deps[i].ip_type,
1085 deps[i].ip_instance,
1086 deps[i].ring, &ring);
1087 if (r) {
1088 amdgpu_ctx_put(ctx);
1089 return r;
1090 }
1091
1092 fence = amdgpu_ctx_get_fence(ctx, ring,
1093 deps[i].handle);
1094 if (IS_ERR(fence)) {
1095 r = PTR_ERR(fence);
1096 amdgpu_ctx_put(ctx);
1097 return r;
1098 } else if (fence) {
Andrey Grodzovskycebb52b2017-11-13 14:47:52 -05001099 r = amdgpu_sync_fence(p->adev, &p->job->sync, fence,
1100 true);
Dave Airlie6f0308e2017-03-09 03:45:52 +00001101 dma_fence_put(fence);
1102 amdgpu_ctx_put(ctx);
1103 if (r)
1104 return r;
1105 }
1106 }
1107 return 0;
1108}
1109
Dave Airlie660e8552017-03-13 22:18:15 +00001110static int amdgpu_syncobj_lookup_and_add_to_sync(struct amdgpu_cs_parser *p,
1111 uint32_t handle)
1112{
1113 int r;
1114 struct dma_fence *fence;
Jason Ekstrandafaf5922017-08-25 10:52:19 -07001115 r = drm_syncobj_find_fence(p->filp, handle, &fence);
Dave Airlie660e8552017-03-13 22:18:15 +00001116 if (r)
1117 return r;
1118
Andrey Grodzovskycebb52b2017-11-13 14:47:52 -05001119 r = amdgpu_sync_fence(p->adev, &p->job->sync, fence, true);
Dave Airlie660e8552017-03-13 22:18:15 +00001120 dma_fence_put(fence);
1121
1122 return r;
1123}
1124
1125static int amdgpu_cs_process_syncobj_in_dep(struct amdgpu_cs_parser *p,
1126 struct amdgpu_cs_chunk *chunk)
1127{
1128 unsigned num_deps;
1129 int i, r;
1130 struct drm_amdgpu_cs_chunk_sem *deps;
1131
1132 deps = (struct drm_amdgpu_cs_chunk_sem *)chunk->kdata;
1133 num_deps = chunk->length_dw * 4 /
1134 sizeof(struct drm_amdgpu_cs_chunk_sem);
1135
1136 for (i = 0; i < num_deps; ++i) {
1137 r = amdgpu_syncobj_lookup_and_add_to_sync(p, deps[i].handle);
1138 if (r)
1139 return r;
1140 }
1141 return 0;
1142}
1143
1144static int amdgpu_cs_process_syncobj_out_dep(struct amdgpu_cs_parser *p,
1145 struct amdgpu_cs_chunk *chunk)
1146{
1147 unsigned num_deps;
1148 int i;
1149 struct drm_amdgpu_cs_chunk_sem *deps;
1150 deps = (struct drm_amdgpu_cs_chunk_sem *)chunk->kdata;
1151 num_deps = chunk->length_dw * 4 /
1152 sizeof(struct drm_amdgpu_cs_chunk_sem);
1153
1154 p->post_dep_syncobjs = kmalloc_array(num_deps,
1155 sizeof(struct drm_syncobj *),
1156 GFP_KERNEL);
1157 p->num_post_dep_syncobjs = 0;
1158
Christophe JAILLETa1d6b192017-08-23 07:52:36 +02001159 if (!p->post_dep_syncobjs)
1160 return -ENOMEM;
1161
Dave Airlie660e8552017-03-13 22:18:15 +00001162 for (i = 0; i < num_deps; ++i) {
1163 p->post_dep_syncobjs[i] = drm_syncobj_find(p->filp, deps[i].handle);
1164 if (!p->post_dep_syncobjs[i])
1165 return -EINVAL;
1166 p->num_post_dep_syncobjs++;
1167 }
1168 return 0;
1169}
1170
Christian König2b48d322015-06-19 17:31:29 +02001171static int amdgpu_cs_dependencies(struct amdgpu_device *adev,
1172 struct amdgpu_cs_parser *p)
1173{
Dave Airlie6f0308e2017-03-09 03:45:52 +00001174 int i, r;
Christian König2b48d322015-06-19 17:31:29 +02001175
Christian König2b48d322015-06-19 17:31:29 +02001176 for (i = 0; i < p->nchunks; ++i) {
Christian König2b48d322015-06-19 17:31:29 +02001177 struct amdgpu_cs_chunk *chunk;
Christian König2b48d322015-06-19 17:31:29 +02001178
1179 chunk = &p->chunks[i];
1180
Dave Airlie6f0308e2017-03-09 03:45:52 +00001181 if (chunk->chunk_id == AMDGPU_CHUNK_ID_DEPENDENCIES) {
1182 r = amdgpu_cs_process_fence_dep(p, chunk);
1183 if (r)
Andres Rodriguezeffd9242017-02-16 00:47:32 -05001184 return r;
Dave Airlie660e8552017-03-13 22:18:15 +00001185 } else if (chunk->chunk_id == AMDGPU_CHUNK_ID_SYNCOBJ_IN) {
1186 r = amdgpu_cs_process_syncobj_in_dep(p, chunk);
1187 if (r)
1188 return r;
1189 } else if (chunk->chunk_id == AMDGPU_CHUNK_ID_SYNCOBJ_OUT) {
1190 r = amdgpu_cs_process_syncobj_out_dep(p, chunk);
1191 if (r)
1192 return r;
Christian König2b48d322015-06-19 17:31:29 +02001193 }
1194 }
1195
1196 return 0;
1197}
1198
Dave Airlie660e8552017-03-13 22:18:15 +00001199static void amdgpu_cs_post_dependencies(struct amdgpu_cs_parser *p)
1200{
1201 int i;
1202
Chris Wilson00fc2c22017-07-05 21:12:44 +01001203 for (i = 0; i < p->num_post_dep_syncobjs; ++i)
1204 drm_syncobj_replace_fence(p->post_dep_syncobjs[i], p->fence);
Dave Airlie660e8552017-03-13 22:18:15 +00001205}
1206
Christian Königcd75dc62016-01-31 11:30:55 +01001207static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
1208 union drm_amdgpu_cs *cs)
1209{
Christian Königb07c60c2016-01-31 12:29:04 +01001210 struct amdgpu_ring *ring = p->job->ring;
Lucas Stach1b1f42d2017-12-06 17:49:39 +01001211 struct drm_sched_entity *entity = &p->ctx->rings[ring->idx].entity;
Christian Königcd75dc62016-01-31 11:30:55 +01001212 struct amdgpu_job *job;
Christian König3fe89772017-09-12 14:25:14 -04001213 unsigned i;
Monk Liueb01abc2017-09-15 13:40:31 +08001214 uint64_t seq;
1215
Monk Liue6869412016-03-07 12:49:55 +08001216 int r;
Christian Königcd75dc62016-01-31 11:30:55 +01001217
Christian König3fe89772017-09-12 14:25:14 -04001218 amdgpu_mn_lock(p->mn);
1219 if (p->bo_list) {
1220 for (i = p->bo_list->first_userptr;
1221 i < p->bo_list->num_entries; ++i) {
1222 struct amdgpu_bo *bo = p->bo_list->array[i].robj;
1223
1224 if (amdgpu_ttm_tt_userptr_needs_pages(bo->tbo.ttm)) {
1225 amdgpu_mn_unlock(p->mn);
1226 return -ERESTARTSYS;
1227 }
1228 }
1229 }
1230
Christian König50838c82016-02-03 13:44:52 +01001231 job = p->job;
1232 p->job = NULL;
Christian Königcd75dc62016-01-31 11:30:55 +01001233
Lucas Stach1b1f42d2017-12-06 17:49:39 +01001234 r = drm_sched_job_init(&job->base, &ring->sched, entity, p->filp);
Monk Liue6869412016-03-07 12:49:55 +08001235 if (r) {
Christian Königd71518b2016-02-01 12:20:25 +01001236 amdgpu_job_free(job);
Christian König3fe89772017-09-12 14:25:14 -04001237 amdgpu_mn_unlock(p->mn);
Monk Liue6869412016-03-07 12:49:55 +08001238 return r;
Christian Königcd75dc62016-01-31 11:30:55 +01001239 }
1240
Monk Liue6869412016-03-07 12:49:55 +08001241 job->owner = p->filp;
Monk Liu3aecd242016-08-25 15:40:48 +08001242 job->fence_ctx = entity->fence_context;
Chris Wilsonf54d1862016-10-25 13:00:45 +01001243 p->fence = dma_fence_get(&job->base.s_fence->finished);
Dave Airlie660e8552017-03-13 22:18:15 +00001244
Monk Liueb01abc2017-09-15 13:40:31 +08001245 r = amdgpu_ctx_add_fence(p->ctx, ring, p->fence, &seq);
1246 if (r) {
1247 dma_fence_put(p->fence);
1248 dma_fence_put(&job->base.s_fence->finished);
1249 amdgpu_job_free(job);
1250 amdgpu_mn_unlock(p->mn);
1251 return r;
1252 }
1253
Dave Airlie660e8552017-03-13 22:18:15 +00001254 amdgpu_cs_post_dependencies(p);
1255
Monk Liueb01abc2017-09-15 13:40:31 +08001256 cs->out.handle = seq;
1257 job->uf_sequence = seq;
1258
Christian Königa5fb4ec2016-06-29 15:10:31 +02001259 amdgpu_job_free_resources(job);
Andrey Grodzovskyd1f6dc12017-10-19 14:29:46 -04001260 amdgpu_ring_priority_get(job->ring, job->base.s_priority);
Christian Königcd75dc62016-01-31 11:30:55 +01001261
1262 trace_amdgpu_cs_ioctl(job);
Lucas Stach1b1f42d2017-12-06 17:49:39 +01001263 drm_sched_entity_push_job(&job->base, entity);
Christian König3fe89772017-09-12 14:25:14 -04001264
1265 ttm_eu_fence_buffer_objects(&p->ticket, &p->validated, p->fence);
1266 amdgpu_mn_unlock(p->mn);
1267
Christian Königcd75dc62016-01-31 11:30:55 +01001268 return 0;
1269}
1270
Chunming Zhou049fc522015-07-21 14:36:51 +08001271int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
1272{
1273 struct amdgpu_device *adev = dev->dev_private;
1274 union drm_amdgpu_cs *cs = data;
Christian König7e52a812015-11-04 15:44:39 +01001275 struct amdgpu_cs_parser parser = {};
Christian König26a69802015-08-18 21:09:33 +02001276 bool reserved_buffers = false;
1277 int i, r;
Chunming Zhou049fc522015-07-21 14:36:51 +08001278
Christian König0c418f12015-09-01 15:13:53 +02001279 if (!adev->accel_working)
Chunming Zhou049fc522015-07-21 14:36:51 +08001280 return -EBUSY;
Chunming Zhou049fc522015-07-21 14:36:51 +08001281
Christian König7e52a812015-11-04 15:44:39 +01001282 parser.adev = adev;
1283 parser.filp = filp;
1284
1285 r = amdgpu_cs_parser_init(&parser, data);
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001286 if (r) {
Chunming Zhou049fc522015-07-21 14:36:51 +08001287 DRM_ERROR("Failed to initialize parser !\n");
Huang Ruia414cd72016-10-30 23:05:47 +08001288 goto out;
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001289 }
Huang Ruia414cd72016-10-30 23:05:47 +08001290
Andrey Grodzovskyad864d22017-10-10 16:50:16 -04001291 r = amdgpu_cs_ib_fill(adev, &parser);
1292 if (r)
1293 goto out;
1294
Christian König2a7d9bd2015-12-18 20:33:52 +01001295 r = amdgpu_cs_parser_bos(&parser, data);
Huang Ruia414cd72016-10-30 23:05:47 +08001296 if (r) {
1297 if (r == -ENOMEM)
1298 DRM_ERROR("Not enough memory for command submission!\n");
1299 else if (r != -ERESTARTSYS)
1300 DRM_ERROR("Failed to process the buffer list %d!\n", r);
1301 goto out;
Christian König26a69802015-08-18 21:09:33 +02001302 }
1303
Huang Ruia414cd72016-10-30 23:05:47 +08001304 reserved_buffers = true;
Christian König26a69802015-08-18 21:09:33 +02001305
Huang Ruia414cd72016-10-30 23:05:47 +08001306 r = amdgpu_cs_dependencies(adev, &parser);
1307 if (r) {
1308 DRM_ERROR("Failed in the dependencies handling %d!\n", r);
1309 goto out;
1310 }
1311
Christian König50838c82016-02-03 13:44:52 +01001312 for (i = 0; i < parser.job->num_ibs; i++)
Christian König7e52a812015-11-04 15:44:39 +01001313 trace_amdgpu_cs(&parser, i);
Christian König26a69802015-08-18 21:09:33 +02001314
Christian König7e52a812015-11-04 15:44:39 +01001315 r = amdgpu_cs_ib_vm_chunk(adev, &parser);
Chunming Zhou4fe63112015-08-18 16:12:15 +08001316 if (r)
1317 goto out;
1318
Christian König4acabfe2016-01-31 11:32:04 +01001319 r = amdgpu_cs_submit(&parser, cs);
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001320
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001321out:
Christian König7e52a812015-11-04 15:44:39 +01001322 amdgpu_cs_parser_fini(&parser, r, reserved_buffers);
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001323 return r;
1324}
1325
1326/**
1327 * amdgpu_cs_wait_ioctl - wait for a command submission to finish
1328 *
1329 * @dev: drm device
1330 * @data: data from userspace
1331 * @filp: file private
1332 *
1333 * Wait for the command submission identified by handle to finish.
1334 */
1335int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data,
1336 struct drm_file *filp)
1337{
1338 union drm_amdgpu_wait_cs *wait = data;
1339 struct amdgpu_device *adev = dev->dev_private;
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001340 unsigned long timeout = amdgpu_gem_timeout(wait->in.timeout);
Christian König03507c42015-06-19 17:00:19 +02001341 struct amdgpu_ring *ring = NULL;
Jammy Zhou66b3cf22015-05-08 17:29:40 +08001342 struct amdgpu_ctx *ctx;
Chris Wilsonf54d1862016-10-25 13:00:45 +01001343 struct dma_fence *fence;
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001344 long r;
1345
Jammy Zhou66b3cf22015-05-08 17:29:40 +08001346 ctx = amdgpu_ctx_get(filp->driver_priv, wait->in.ctx_id);
1347 if (ctx == NULL)
1348 return -EINVAL;
Chunming Zhou4b559c92015-07-21 15:53:04 +08001349
Andres Rodriguezeffd9242017-02-16 00:47:32 -05001350 r = amdgpu_queue_mgr_map(adev, &ctx->queue_mgr,
1351 wait->in.ip_type, wait->in.ip_instance,
1352 wait->in.ring, &ring);
1353 if (r) {
1354 amdgpu_ctx_put(ctx);
1355 return r;
1356 }
1357
Chunming Zhou4b559c92015-07-21 15:53:04 +08001358 fence = amdgpu_ctx_get_fence(ctx, ring, wait->in.handle);
1359 if (IS_ERR(fence))
1360 r = PTR_ERR(fence);
1361 else if (fence) {
Chris Wilsonf54d1862016-10-25 13:00:45 +01001362 r = dma_fence_wait_timeout(fence, true, timeout);
Christian König7a0a48d2017-10-09 15:51:10 +02001363 if (r > 0 && fence->error)
1364 r = fence->error;
Chris Wilsonf54d1862016-10-25 13:00:45 +01001365 dma_fence_put(fence);
Chunming Zhou4b559c92015-07-21 15:53:04 +08001366 } else
Christian König21c16bf2015-07-07 17:24:49 +02001367 r = 1;
1368
Jammy Zhou66b3cf22015-05-08 17:29:40 +08001369 amdgpu_ctx_put(ctx);
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001370 if (r < 0)
1371 return r;
1372
1373 memset(wait, 0, sizeof(*wait));
1374 wait->out.status = (r == 0);
1375
1376 return 0;
1377}
1378
1379/**
Junwei Zhangeef18a82016-11-04 16:16:10 -04001380 * amdgpu_cs_get_fence - helper to get fence from drm_amdgpu_fence
1381 *
1382 * @adev: amdgpu device
1383 * @filp: file private
1384 * @user: drm_amdgpu_fence copied from user space
1385 */
1386static struct dma_fence *amdgpu_cs_get_fence(struct amdgpu_device *adev,
1387 struct drm_file *filp,
1388 struct drm_amdgpu_fence *user)
1389{
1390 struct amdgpu_ring *ring;
1391 struct amdgpu_ctx *ctx;
1392 struct dma_fence *fence;
1393 int r;
1394
Junwei Zhangeef18a82016-11-04 16:16:10 -04001395 ctx = amdgpu_ctx_get(filp->driver_priv, user->ctx_id);
1396 if (ctx == NULL)
1397 return ERR_PTR(-EINVAL);
1398
Andres Rodriguezeffd9242017-02-16 00:47:32 -05001399 r = amdgpu_queue_mgr_map(adev, &ctx->queue_mgr, user->ip_type,
1400 user->ip_instance, user->ring, &ring);
1401 if (r) {
1402 amdgpu_ctx_put(ctx);
1403 return ERR_PTR(r);
1404 }
1405
Junwei Zhangeef18a82016-11-04 16:16:10 -04001406 fence = amdgpu_ctx_get_fence(ctx, ring, user->seq_no);
1407 amdgpu_ctx_put(ctx);
1408
1409 return fence;
1410}
1411
Marek Olšák7ca24cf2017-09-12 22:42:14 +02001412int amdgpu_cs_fence_to_handle_ioctl(struct drm_device *dev, void *data,
1413 struct drm_file *filp)
1414{
1415 struct amdgpu_device *adev = dev->dev_private;
Marek Olšák7ca24cf2017-09-12 22:42:14 +02001416 union drm_amdgpu_fence_to_handle *info = data;
1417 struct dma_fence *fence;
1418 struct drm_syncobj *syncobj;
1419 struct sync_file *sync_file;
1420 int fd, r;
1421
Marek Olšák7ca24cf2017-09-12 22:42:14 +02001422 fence = amdgpu_cs_get_fence(adev, filp, &info->in.fence);
1423 if (IS_ERR(fence))
1424 return PTR_ERR(fence);
1425
1426 switch (info->in.what) {
1427 case AMDGPU_FENCE_TO_HANDLE_GET_SYNCOBJ:
1428 r = drm_syncobj_create(&syncobj, 0, fence);
1429 dma_fence_put(fence);
1430 if (r)
1431 return r;
1432 r = drm_syncobj_get_handle(filp, syncobj, &info->out.handle);
1433 drm_syncobj_put(syncobj);
1434 return r;
1435
1436 case AMDGPU_FENCE_TO_HANDLE_GET_SYNCOBJ_FD:
1437 r = drm_syncobj_create(&syncobj, 0, fence);
1438 dma_fence_put(fence);
1439 if (r)
1440 return r;
1441 r = drm_syncobj_get_fd(syncobj, (int*)&info->out.handle);
1442 drm_syncobj_put(syncobj);
1443 return r;
1444
1445 case AMDGPU_FENCE_TO_HANDLE_GET_SYNC_FILE_FD:
1446 fd = get_unused_fd_flags(O_CLOEXEC);
1447 if (fd < 0) {
1448 dma_fence_put(fence);
1449 return fd;
1450 }
1451
1452 sync_file = sync_file_create(fence);
1453 dma_fence_put(fence);
1454 if (!sync_file) {
1455 put_unused_fd(fd);
1456 return -ENOMEM;
1457 }
1458
1459 fd_install(fd, sync_file->file);
1460 info->out.handle = fd;
1461 return 0;
1462
1463 default:
1464 return -EINVAL;
1465 }
1466}
1467
Junwei Zhangeef18a82016-11-04 16:16:10 -04001468/**
1469 * amdgpu_cs_wait_all_fence - wait on all fences to signal
1470 *
1471 * @adev: amdgpu device
1472 * @filp: file private
1473 * @wait: wait parameters
1474 * @fences: array of drm_amdgpu_fence
1475 */
1476static int amdgpu_cs_wait_all_fences(struct amdgpu_device *adev,
1477 struct drm_file *filp,
1478 union drm_amdgpu_wait_fences *wait,
1479 struct drm_amdgpu_fence *fences)
1480{
1481 uint32_t fence_count = wait->in.fence_count;
1482 unsigned int i;
1483 long r = 1;
1484
1485 for (i = 0; i < fence_count; i++) {
1486 struct dma_fence *fence;
1487 unsigned long timeout = amdgpu_gem_timeout(wait->in.timeout_ns);
1488
1489 fence = amdgpu_cs_get_fence(adev, filp, &fences[i]);
1490 if (IS_ERR(fence))
1491 return PTR_ERR(fence);
1492 else if (!fence)
1493 continue;
1494
1495 r = dma_fence_wait_timeout(fence, true, timeout);
Chunming Zhou32df87d2017-04-07 17:05:45 +08001496 dma_fence_put(fence);
Junwei Zhangeef18a82016-11-04 16:16:10 -04001497 if (r < 0)
1498 return r;
1499
1500 if (r == 0)
1501 break;
Christian König7a0a48d2017-10-09 15:51:10 +02001502
1503 if (fence->error)
1504 return fence->error;
Junwei Zhangeef18a82016-11-04 16:16:10 -04001505 }
1506
1507 memset(wait, 0, sizeof(*wait));
1508 wait->out.status = (r > 0);
1509
1510 return 0;
1511}
1512
1513/**
1514 * amdgpu_cs_wait_any_fence - wait on any fence to signal
1515 *
1516 * @adev: amdgpu device
1517 * @filp: file private
1518 * @wait: wait parameters
1519 * @fences: array of drm_amdgpu_fence
1520 */
1521static int amdgpu_cs_wait_any_fence(struct amdgpu_device *adev,
1522 struct drm_file *filp,
1523 union drm_amdgpu_wait_fences *wait,
1524 struct drm_amdgpu_fence *fences)
1525{
1526 unsigned long timeout = amdgpu_gem_timeout(wait->in.timeout_ns);
1527 uint32_t fence_count = wait->in.fence_count;
1528 uint32_t first = ~0;
1529 struct dma_fence **array;
1530 unsigned int i;
1531 long r;
1532
1533 /* Prepare the fence array */
1534 array = kcalloc(fence_count, sizeof(struct dma_fence *), GFP_KERNEL);
1535
1536 if (array == NULL)
1537 return -ENOMEM;
1538
1539 for (i = 0; i < fence_count; i++) {
1540 struct dma_fence *fence;
1541
1542 fence = amdgpu_cs_get_fence(adev, filp, &fences[i]);
1543 if (IS_ERR(fence)) {
1544 r = PTR_ERR(fence);
1545 goto err_free_fence_array;
1546 } else if (fence) {
1547 array[i] = fence;
1548 } else { /* NULL, the fence has been already signaled */
1549 r = 1;
Monk Liua2138ea2017-08-11 17:49:48 +08001550 first = i;
Junwei Zhangeef18a82016-11-04 16:16:10 -04001551 goto out;
1552 }
1553 }
1554
1555 r = dma_fence_wait_any_timeout(array, fence_count, true, timeout,
1556 &first);
1557 if (r < 0)
1558 goto err_free_fence_array;
1559
1560out:
1561 memset(wait, 0, sizeof(*wait));
1562 wait->out.status = (r > 0);
1563 wait->out.first_signaled = first;
Emily Dengcdadab82017-11-09 17:18:18 +08001564
Roger Heeb174c72017-11-17 12:45:18 +08001565 if (first < fence_count && array[first])
Emily Dengcdadab82017-11-09 17:18:18 +08001566 r = array[first]->error;
1567 else
1568 r = 0;
Junwei Zhangeef18a82016-11-04 16:16:10 -04001569
1570err_free_fence_array:
1571 for (i = 0; i < fence_count; i++)
1572 dma_fence_put(array[i]);
1573 kfree(array);
1574
1575 return r;
1576}
1577
1578/**
1579 * amdgpu_cs_wait_fences_ioctl - wait for multiple command submissions to finish
1580 *
1581 * @dev: drm device
1582 * @data: data from userspace
1583 * @filp: file private
1584 */
1585int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data,
1586 struct drm_file *filp)
1587{
1588 struct amdgpu_device *adev = dev->dev_private;
1589 union drm_amdgpu_wait_fences *wait = data;
1590 uint32_t fence_count = wait->in.fence_count;
1591 struct drm_amdgpu_fence *fences_user;
1592 struct drm_amdgpu_fence *fences;
1593 int r;
1594
1595 /* Get the fences from userspace */
1596 fences = kmalloc_array(fence_count, sizeof(struct drm_amdgpu_fence),
1597 GFP_KERNEL);
1598 if (fences == NULL)
1599 return -ENOMEM;
1600
Christian König7ecc2452017-07-26 17:02:52 +02001601 fences_user = u64_to_user_ptr(wait->in.fences);
Junwei Zhangeef18a82016-11-04 16:16:10 -04001602 if (copy_from_user(fences, fences_user,
1603 sizeof(struct drm_amdgpu_fence) * fence_count)) {
1604 r = -EFAULT;
1605 goto err_free_fences;
1606 }
1607
1608 if (wait->in.wait_all)
1609 r = amdgpu_cs_wait_all_fences(adev, filp, wait, fences);
1610 else
1611 r = amdgpu_cs_wait_any_fence(adev, filp, wait, fences);
1612
1613err_free_fences:
1614 kfree(fences);
1615
1616 return r;
1617}
1618
1619/**
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001620 * amdgpu_cs_find_bo_va - find bo_va for VM address
1621 *
1622 * @parser: command submission parser context
1623 * @addr: VM address
1624 * @bo: resulting BO of the mapping found
1625 *
1626 * Search the buffer objects in the command submission context for a certain
1627 * virtual memory address. Returns allocation structure when found, NULL
1628 * otherwise.
1629 */
Christian König9cca0b82017-09-06 16:15:28 +02001630int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
1631 uint64_t addr, struct amdgpu_bo **bo,
1632 struct amdgpu_bo_va_mapping **map)
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001633{
Christian Königaebc5e62017-09-06 16:55:16 +02001634 struct amdgpu_fpriv *fpriv = parser->filp->driver_priv;
Christian König19be5572017-04-12 14:24:39 +02001635 struct ttm_operation_ctx ctx = { false, false };
Christian Königaebc5e62017-09-06 16:55:16 +02001636 struct amdgpu_vm *vm = &fpriv->vm;
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001637 struct amdgpu_bo_va_mapping *mapping;
Christian König9cca0b82017-09-06 16:15:28 +02001638 int r;
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001639
1640 addr /= AMDGPU_GPU_PAGE_SIZE;
1641
Christian Königaebc5e62017-09-06 16:55:16 +02001642 mapping = amdgpu_vm_bo_lookup_mapping(vm, addr);
1643 if (!mapping || !mapping->bo_va || !mapping->bo_va->base.bo)
1644 return -EINVAL;
Christian König15486fd22015-12-22 16:06:12 +01001645
Christian Königaebc5e62017-09-06 16:55:16 +02001646 *bo = mapping->bo_va->base.bo;
1647 *map = mapping;
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001648
Christian Königaebc5e62017-09-06 16:55:16 +02001649 /* Double check that the BO is reserved by this CS */
1650 if (READ_ONCE((*bo)->tbo.resv->lock.ctx) != &parser->ticket)
1651 return -EINVAL;
Christian König7fc11952015-07-30 11:53:42 +02001652
Christian König4b6b6912017-10-16 10:32:04 +02001653 if (!((*bo)->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)) {
1654 (*bo)->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
1655 amdgpu_ttm_placement_from_domain(*bo, (*bo)->allowed_domains);
Christian König19be5572017-04-12 14:24:39 +02001656 r = ttm_bo_validate(&(*bo)->tbo, &(*bo)->placement, &ctx);
Christian König4b6b6912017-10-16 10:32:04 +02001657 if (r)
Christian König03f48dd2016-08-15 17:00:22 +02001658 return r;
Christian Königc855e252016-09-05 17:00:57 +02001659 }
1660
Christian Königc5835bb2017-10-27 15:43:14 +02001661 return amdgpu_ttm_alloc_gart(&(*bo)->tbo);
Christian Königc855e252016-09-05 17:00:57 +02001662}