diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 137 |
1 files changed, 80 insertions, 57 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 3b355aeb62fd..749420f1ea6f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | |||
@@ -154,42 +154,41 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) | |||
154 | { | 154 | { |
155 | union drm_amdgpu_cs *cs = data; | 155 | union drm_amdgpu_cs *cs = data; |
156 | uint64_t *chunk_array_user; | 156 | uint64_t *chunk_array_user; |
157 | uint64_t *chunk_array = NULL; | 157 | uint64_t *chunk_array; |
158 | struct amdgpu_fpriv *fpriv = p->filp->driver_priv; | 158 | struct amdgpu_fpriv *fpriv = p->filp->driver_priv; |
159 | unsigned size, i; | 159 | unsigned size, i; |
160 | int r = 0; | 160 | int ret; |
161 | 161 | ||
162 | if (!cs->in.num_chunks) | 162 | if (cs->in.num_chunks == 0) |
163 | goto out; | 163 | return 0; |
164 | |||
165 | chunk_array = kmalloc_array(cs->in.num_chunks, sizeof(uint64_t), GFP_KERNEL); | ||
166 | if (!chunk_array) | ||
167 | return -ENOMEM; | ||
164 | 168 | ||
165 | p->ctx = amdgpu_ctx_get(fpriv, cs->in.ctx_id); | 169 | p->ctx = amdgpu_ctx_get(fpriv, cs->in.ctx_id); |
166 | if (!p->ctx) { | 170 | if (!p->ctx) { |
167 | r = -EINVAL; | 171 | ret = -EINVAL; |
168 | goto out; | 172 | goto free_chunk; |
169 | } | 173 | } |
174 | |||
170 | p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle); | 175 | p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle); |
171 | 176 | ||
172 | /* get chunks */ | 177 | /* get chunks */ |
173 | INIT_LIST_HEAD(&p->validated); | 178 | INIT_LIST_HEAD(&p->validated); |
174 | chunk_array = kmalloc_array(cs->in.num_chunks, sizeof(uint64_t), GFP_KERNEL); | ||
175 | if (chunk_array == NULL) { | ||
176 | r = -ENOMEM; | ||
177 | goto out; | ||
178 | } | ||
179 | |||
180 | chunk_array_user = (uint64_t __user *)(cs->in.chunks); | 179 | chunk_array_user = (uint64_t __user *)(cs->in.chunks); |
181 | if (copy_from_user(chunk_array, chunk_array_user, | 180 | if (copy_from_user(chunk_array, chunk_array_user, |
182 | sizeof(uint64_t)*cs->in.num_chunks)) { | 181 | sizeof(uint64_t)*cs->in.num_chunks)) { |
183 | r = -EFAULT; | 182 | ret = -EFAULT; |
184 | goto out; | 183 | goto put_bo_list; |
185 | } | 184 | } |
186 | 185 | ||
187 | p->nchunks = cs->in.num_chunks; | 186 | p->nchunks = cs->in.num_chunks; |
188 | p->chunks = kmalloc_array(p->nchunks, sizeof(struct amdgpu_cs_chunk), | 187 | p->chunks = kmalloc_array(p->nchunks, sizeof(struct amdgpu_cs_chunk), |
189 | GFP_KERNEL); | 188 | GFP_KERNEL); |
190 | if (p->chunks == NULL) { | 189 | if (!p->chunks) { |
191 | r = -ENOMEM; | 190 | ret = -ENOMEM; |
192 | goto out; | 191 | goto put_bo_list; |
193 | } | 192 | } |
194 | 193 | ||
195 | for (i = 0; i < p->nchunks; i++) { | 194 | for (i = 0; i < p->nchunks; i++) { |
@@ -200,8 +199,9 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) | |||
200 | chunk_ptr = (void __user *)chunk_array[i]; | 199 | chunk_ptr = (void __user *)chunk_array[i]; |
201 | if (copy_from_user(&user_chunk, chunk_ptr, | 200 | if (copy_from_user(&user_chunk, chunk_ptr, |
202 | sizeof(struct drm_amdgpu_cs_chunk))) { | 201 | sizeof(struct drm_amdgpu_cs_chunk))) { |
203 | r = -EFAULT; | 202 | ret = -EFAULT; |
204 | goto out; | 203 | i--; |
204 | goto free_partial_kdata; | ||
205 | } | 205 | } |
206 | p->chunks[i].chunk_id = user_chunk.chunk_id; | 206 | p->chunks[i].chunk_id = user_chunk.chunk_id; |
207 | p->chunks[i].length_dw = user_chunk.length_dw; | 207 | p->chunks[i].length_dw = user_chunk.length_dw; |
@@ -212,13 +212,14 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) | |||
212 | 212 | ||
213 | p->chunks[i].kdata = drm_malloc_ab(size, sizeof(uint32_t)); | 213 | p->chunks[i].kdata = drm_malloc_ab(size, sizeof(uint32_t)); |
214 | if (p->chunks[i].kdata == NULL) { | 214 | if (p->chunks[i].kdata == NULL) { |
215 | r = -ENOMEM; | 215 | ret = -ENOMEM; |
216 | goto out; | 216 | i--; |
217 | goto free_partial_kdata; | ||
217 | } | 218 | } |
218 | size *= sizeof(uint32_t); | 219 | size *= sizeof(uint32_t); |
219 | if (copy_from_user(p->chunks[i].kdata, cdata, size)) { | 220 | if (copy_from_user(p->chunks[i].kdata, cdata, size)) { |
220 | r = -EFAULT; | 221 | ret = -EFAULT; |
221 | goto out; | 222 | goto free_partial_kdata; |
222 | } | 223 | } |
223 | 224 | ||
224 | switch (p->chunks[i].chunk_id) { | 225 | switch (p->chunks[i].chunk_id) { |
@@ -238,15 +239,15 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) | |||
238 | gobj = drm_gem_object_lookup(p->adev->ddev, | 239 | gobj = drm_gem_object_lookup(p->adev->ddev, |
239 | p->filp, handle); | 240 | p->filp, handle); |
240 | if (gobj == NULL) { | 241 | if (gobj == NULL) { |
241 | r = -EINVAL; | 242 | ret = -EINVAL; |
242 | goto out; | 243 | goto free_partial_kdata; |
243 | } | 244 | } |
244 | 245 | ||
245 | p->uf.bo = gem_to_amdgpu_bo(gobj); | 246 | p->uf.bo = gem_to_amdgpu_bo(gobj); |
246 | p->uf.offset = fence_data->offset; | 247 | p->uf.offset = fence_data->offset; |
247 | } else { | 248 | } else { |
248 | r = -EINVAL; | 249 | ret = -EINVAL; |
249 | goto out; | 250 | goto free_partial_kdata; |
250 | } | 251 | } |
251 | break; | 252 | break; |
252 | 253 | ||
@@ -254,19 +255,35 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) | |||
254 | break; | 255 | break; |
255 | 256 | ||
256 | default: | 257 | default: |
257 | r = -EINVAL; | 258 | ret = -EINVAL; |
258 | goto out; | 259 | goto free_partial_kdata; |
259 | } | 260 | } |
260 | } | 261 | } |
261 | 262 | ||
262 | 263 | ||
263 | p->ibs = kcalloc(p->num_ibs, sizeof(struct amdgpu_ib), GFP_KERNEL); | 264 | p->ibs = kcalloc(p->num_ibs, sizeof(struct amdgpu_ib), GFP_KERNEL); |
264 | if (!p->ibs) | 265 | if (!p->ibs) { |
265 | r = -ENOMEM; | 266 | ret = -ENOMEM; |
267 | goto free_all_kdata; | ||
268 | } | ||
266 | 269 | ||
267 | out: | ||
268 | kfree(chunk_array); | 270 | kfree(chunk_array); |
269 | return r; | 271 | return 0; |
272 | |||
273 | free_all_kdata: | ||
274 | i = p->nchunks - 1; | ||
275 | free_partial_kdata: | ||
276 | for (; i >= 0; i--) | ||
277 | drm_free_large(p->chunks[i].kdata); | ||
278 | kfree(p->chunks); | ||
279 | put_bo_list: | ||
280 | if (p->bo_list) | ||
281 | amdgpu_bo_list_put(p->bo_list); | ||
282 | amdgpu_ctx_put(p->ctx); | ||
283 | free_chunk: | ||
284 | kfree(chunk_array); | ||
285 | |||
286 | return ret; | ||
270 | } | 287 | } |
271 | 288 | ||
272 | /* Returns how many bytes TTM can move per IB. | 289 | /* Returns how many bytes TTM can move per IB. |
@@ -321,25 +338,17 @@ static u64 amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev) | |||
321 | return max(bytes_moved_threshold, 1024*1024ull); | 338 | return max(bytes_moved_threshold, 1024*1024ull); |
322 | } | 339 | } |
323 | 340 | ||
324 | int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p) | 341 | int amdgpu_cs_list_validate(struct amdgpu_device *adev, |
342 | struct amdgpu_vm *vm, | ||
343 | struct list_head *validated) | ||
325 | { | 344 | { |
326 | struct amdgpu_fpriv *fpriv = p->filp->driver_priv; | ||
327 | struct amdgpu_vm *vm = &fpriv->vm; | ||
328 | struct amdgpu_device *adev = p->adev; | ||
329 | struct amdgpu_bo_list_entry *lobj; | 345 | struct amdgpu_bo_list_entry *lobj; |
330 | struct list_head duplicates; | ||
331 | struct amdgpu_bo *bo; | 346 | struct amdgpu_bo *bo; |
332 | u64 bytes_moved = 0, initial_bytes_moved; | 347 | u64 bytes_moved = 0, initial_bytes_moved; |
333 | u64 bytes_moved_threshold = amdgpu_cs_get_threshold_for_moves(adev); | 348 | u64 bytes_moved_threshold = amdgpu_cs_get_threshold_for_moves(adev); |
334 | int r; | 349 | int r; |
335 | 350 | ||
336 | INIT_LIST_HEAD(&duplicates); | 351 | list_for_each_entry(lobj, validated, tv.head) { |
337 | r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true, &duplicates); | ||
338 | if (unlikely(r != 0)) { | ||
339 | return r; | ||
340 | } | ||
341 | |||
342 | list_for_each_entry(lobj, &p->validated, tv.head) { | ||
343 | bo = lobj->robj; | 352 | bo = lobj->robj; |
344 | if (!bo->pin_count) { | 353 | if (!bo->pin_count) { |
345 | u32 domain = lobj->prefered_domains; | 354 | u32 domain = lobj->prefered_domains; |
@@ -373,7 +382,6 @@ int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p) | |||
373 | domain = lobj->allowed_domains; | 382 | domain = lobj->allowed_domains; |
374 | goto retry; | 383 | goto retry; |
375 | } | 384 | } |
376 | ttm_eu_backoff_reservation(&p->ticket, &p->validated); | ||
377 | return r; | 385 | return r; |
378 | } | 386 | } |
379 | } | 387 | } |
@@ -386,6 +394,7 @@ static int amdgpu_cs_parser_relocs(struct amdgpu_cs_parser *p) | |||
386 | { | 394 | { |
387 | struct amdgpu_fpriv *fpriv = p->filp->driver_priv; | 395 | struct amdgpu_fpriv *fpriv = p->filp->driver_priv; |
388 | struct amdgpu_cs_buckets buckets; | 396 | struct amdgpu_cs_buckets buckets; |
397 | struct list_head duplicates; | ||
389 | bool need_mmap_lock = false; | 398 | bool need_mmap_lock = false; |
390 | int i, r; | 399 | int i, r; |
391 | 400 | ||
@@ -405,8 +414,22 @@ static int amdgpu_cs_parser_relocs(struct amdgpu_cs_parser *p) | |||
405 | if (need_mmap_lock) | 414 | if (need_mmap_lock) |
406 | down_read(¤t->mm->mmap_sem); | 415 | down_read(¤t->mm->mmap_sem); |
407 | 416 | ||
408 | r = amdgpu_cs_list_validate(p); | 417 | INIT_LIST_HEAD(&duplicates); |
418 | r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true, &duplicates); | ||
419 | if (unlikely(r != 0)) | ||
420 | goto error_reserve; | ||
421 | |||
422 | r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &p->validated); | ||
423 | if (r) | ||
424 | goto error_validate; | ||
425 | |||
426 | r = amdgpu_cs_list_validate(p->adev, &fpriv->vm, &duplicates); | ||
427 | |||
428 | error_validate: | ||
429 | if (r) | ||
430 | ttm_eu_backoff_reservation(&p->ticket, &p->validated); | ||
409 | 431 | ||
432 | error_reserve: | ||
410 | if (need_mmap_lock) | 433 | if (need_mmap_lock) |
411 | up_read(¤t->mm->mmap_sem); | 434 | up_read(¤t->mm->mmap_sem); |
412 | 435 | ||
@@ -772,15 +795,15 @@ static int amdgpu_cs_dependencies(struct amdgpu_device *adev, | |||
772 | return 0; | 795 | return 0; |
773 | } | 796 | } |
774 | 797 | ||
775 | static int amdgpu_cs_free_job(struct amdgpu_job *sched_job) | 798 | static int amdgpu_cs_free_job(struct amdgpu_job *job) |
776 | { | 799 | { |
777 | int i; | 800 | int i; |
778 | if (sched_job->ibs) | 801 | if (job->ibs) |
779 | for (i = 0; i < sched_job->num_ibs; i++) | 802 | for (i = 0; i < job->num_ibs; i++) |
780 | amdgpu_ib_free(sched_job->adev, &sched_job->ibs[i]); | 803 | amdgpu_ib_free(job->adev, &job->ibs[i]); |
781 | kfree(sched_job->ibs); | 804 | kfree(job->ibs); |
782 | if (sched_job->uf.bo) | 805 | if (job->uf.bo) |
783 | drm_gem_object_unreference_unlocked(&sched_job->uf.bo->gem_base); | 806 | drm_gem_object_unreference_unlocked(&job->uf.bo->gem_base); |
784 | return 0; | 807 | return 0; |
785 | } | 808 | } |
786 | 809 | ||
@@ -804,7 +827,7 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) | |||
804 | r = amdgpu_cs_parser_init(parser, data); | 827 | r = amdgpu_cs_parser_init(parser, data); |
805 | if (r) { | 828 | if (r) { |
806 | DRM_ERROR("Failed to initialize parser !\n"); | 829 | DRM_ERROR("Failed to initialize parser !\n"); |
807 | amdgpu_cs_parser_fini(parser, r, false); | 830 | kfree(parser); |
808 | up_read(&adev->exclusive_lock); | 831 | up_read(&adev->exclusive_lock); |
809 | r = amdgpu_cs_handle_lockup(adev, r); | 832 | r = amdgpu_cs_handle_lockup(adev, r); |
810 | return r; | 833 | return r; |
@@ -842,7 +865,7 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) | |||
842 | job = kzalloc(sizeof(struct amdgpu_job), GFP_KERNEL); | 865 | job = kzalloc(sizeof(struct amdgpu_job), GFP_KERNEL); |
843 | if (!job) | 866 | if (!job) |
844 | return -ENOMEM; | 867 | return -ENOMEM; |
845 | job->base.sched = ring->scheduler; | 868 | job->base.sched = &ring->sched; |
846 | job->base.s_entity = &parser->ctx->rings[ring->idx].entity; | 869 | job->base.s_entity = &parser->ctx->rings[ring->idx].entity; |
847 | job->adev = parser->adev; | 870 | job->adev = parser->adev; |
848 | job->ibs = parser->ibs; | 871 | job->ibs = parser->ibs; |
@@ -857,7 +880,7 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) | |||
857 | 880 | ||
858 | job->free_job = amdgpu_cs_free_job; | 881 | job->free_job = amdgpu_cs_free_job; |
859 | mutex_lock(&job->job_lock); | 882 | mutex_lock(&job->job_lock); |
860 | r = amd_sched_entity_push_job((struct amd_sched_job *)job); | 883 | r = amd_sched_entity_push_job(&job->base); |
861 | if (r) { | 884 | if (r) { |
862 | mutex_unlock(&job->job_lock); | 885 | mutex_unlock(&job->job_lock); |
863 | amdgpu_cs_free_job(job); | 886 | amdgpu_cs_free_job(job); |