LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/amdgpu - amdgpu_bo_list.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 144 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 9 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015 Advanced Micro Devices, Inc.
       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
       7             :  * "Software"), to deal in the Software without restriction, including
       8             :  * without limitation the rights to use, copy, modify, merge, publish,
       9             :  * distribute, sub license, and/or sell copies of the Software, and to
      10             :  * permit persons to whom the Software is furnished to do so, subject to
      11             :  * the following conditions:
      12             :  *
      13             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      14             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      15             :  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
      16             :  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
      17             :  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
      18             :  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
      19             :  * USE OR OTHER DEALINGS IN THE SOFTWARE.
      20             :  *
      21             :  * The above copyright notice and this permission notice (including the
      22             :  * next paragraph) shall be included in all copies or substantial portions
      23             :  * of the Software.
      24             :  *
      25             :  */
      26             : /*
      27             :  * Authors:
      28             :  *    Christian König <deathsimple@vodafone.de>
      29             :  */
      30             : 
      31             : #include <linux/uaccess.h>
      32             : 
      33             : #include "amdgpu.h"
      34             : #include "amdgpu_trace.h"
      35             : 
      36             : #define AMDGPU_BO_LIST_MAX_PRIORITY     32u
      37             : #define AMDGPU_BO_LIST_NUM_BUCKETS      (AMDGPU_BO_LIST_MAX_PRIORITY + 1)
      38             : 
      39           0 : static void amdgpu_bo_list_free_rcu(struct rcu_head *rcu)
      40             : {
      41           0 :         struct amdgpu_bo_list *list = container_of(rcu, struct amdgpu_bo_list,
      42             :                                                    rhead);
      43           0 :         mutex_destroy(&list->bo_list_mutex);
      44           0 :         kvfree(list);
      45           0 : }
      46             : 
      47           0 : static void amdgpu_bo_list_free(struct kref *ref)
      48             : {
      49           0 :         struct amdgpu_bo_list *list = container_of(ref, struct amdgpu_bo_list,
      50             :                                                    refcount);
      51             :         struct amdgpu_bo_list_entry *e;
      52             : 
      53           0 :         amdgpu_bo_list_for_each_entry(e, list) {
      54           0 :                 struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo);
      55             : 
      56           0 :                 amdgpu_bo_unref(&bo);
      57             :         }
      58             : 
      59           0 :         call_rcu(&list->rhead, amdgpu_bo_list_free_rcu);
      60           0 : }
      61             : 
      62           0 : int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp,
      63             :                           struct drm_amdgpu_bo_list_entry *info,
      64             :                           size_t num_entries, struct amdgpu_bo_list **result)
      65             : {
      66           0 :         unsigned last_entry = 0, first_userptr = num_entries;
      67             :         struct amdgpu_bo_list_entry *array;
      68             :         struct amdgpu_bo_list *list;
      69           0 :         uint64_t total_size = 0;
      70             :         size_t size;
      71             :         unsigned i;
      72             :         int r;
      73             : 
      74           0 :         if (num_entries > (SIZE_MAX - sizeof(struct amdgpu_bo_list))
      75             :                                 / sizeof(struct amdgpu_bo_list_entry))
      76             :                 return -EINVAL;
      77             : 
      78           0 :         size = sizeof(struct amdgpu_bo_list);
      79           0 :         size += num_entries * sizeof(struct amdgpu_bo_list_entry);
      80           0 :         list = kvmalloc(size, GFP_KERNEL);
      81           0 :         if (!list)
      82             :                 return -ENOMEM;
      83             : 
      84           0 :         kref_init(&list->refcount);
      85           0 :         list->gds_obj = NULL;
      86           0 :         list->gws_obj = NULL;
      87           0 :         list->oa_obj = NULL;
      88             : 
      89           0 :         array = amdgpu_bo_list_array_entry(list, 0);
      90           0 :         memset(array, 0, num_entries * sizeof(struct amdgpu_bo_list_entry));
      91             : 
      92           0 :         for (i = 0; i < num_entries; ++i) {
      93             :                 struct amdgpu_bo_list_entry *entry;
      94             :                 struct drm_gem_object *gobj;
      95             :                 struct amdgpu_bo *bo;
      96             :                 struct mm_struct *usermm;
      97             : 
      98           0 :                 gobj = drm_gem_object_lookup(filp, info[i].bo_handle);
      99           0 :                 if (!gobj) {
     100             :                         r = -ENOENT;
     101           0 :                         goto error_free;
     102             :                 }
     103             : 
     104           0 :                 bo = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj));
     105           0 :                 drm_gem_object_put(gobj);
     106             : 
     107           0 :                 usermm = amdgpu_ttm_tt_get_usermm(bo->tbo.ttm);
     108           0 :                 if (usermm) {
     109           0 :                         if (usermm != current->mm) {
     110           0 :                                 amdgpu_bo_unref(&bo);
     111           0 :                                 r = -EPERM;
     112           0 :                                 goto error_free;
     113             :                         }
     114           0 :                         entry = &array[--first_userptr];
     115             :                 } else {
     116           0 :                         entry = &array[last_entry++];
     117             :                 }
     118             : 
     119           0 :                 entry->priority = min(info[i].bo_priority,
     120             :                                       AMDGPU_BO_LIST_MAX_PRIORITY);
     121           0 :                 entry->tv.bo = &bo->tbo;
     122             : 
     123           0 :                 if (bo->preferred_domains == AMDGPU_GEM_DOMAIN_GDS)
     124           0 :                         list->gds_obj = bo;
     125           0 :                 if (bo->preferred_domains == AMDGPU_GEM_DOMAIN_GWS)
     126           0 :                         list->gws_obj = bo;
     127           0 :                 if (bo->preferred_domains == AMDGPU_GEM_DOMAIN_OA)
     128           0 :                         list->oa_obj = bo;
     129             : 
     130           0 :                 total_size += amdgpu_bo_size(bo);
     131           0 :                 trace_amdgpu_bo_list_set(list, bo);
     132             :         }
     133             : 
     134           0 :         list->first_userptr = first_userptr;
     135           0 :         list->num_entries = num_entries;
     136             : 
     137           0 :         trace_amdgpu_cs_bo_status(list->num_entries, total_size);
     138             : 
     139           0 :         mutex_init(&list->bo_list_mutex);
     140           0 :         *result = list;
     141           0 :         return 0;
     142             : 
     143             : error_free:
     144           0 :         for (i = 0; i < last_entry; ++i) {
     145           0 :                 struct amdgpu_bo *bo = ttm_to_amdgpu_bo(array[i].tv.bo);
     146             : 
     147           0 :                 amdgpu_bo_unref(&bo);
     148             :         }
     149           0 :         for (i = first_userptr; i < num_entries; ++i) {
     150           0 :                 struct amdgpu_bo *bo = ttm_to_amdgpu_bo(array[i].tv.bo);
     151             : 
     152           0 :                 amdgpu_bo_unref(&bo);
     153             :         }
     154           0 :         kvfree(list);
     155           0 :         return r;
     156             : 
     157             : }
     158             : 
     159           0 : static void amdgpu_bo_list_destroy(struct amdgpu_fpriv *fpriv, int id)
     160             : {
     161             :         struct amdgpu_bo_list *list;
     162             : 
     163           0 :         mutex_lock(&fpriv->bo_list_lock);
     164           0 :         list = idr_remove(&fpriv->bo_list_handles, id);
     165           0 :         mutex_unlock(&fpriv->bo_list_lock);
     166           0 :         if (list)
     167           0 :                 kref_put(&list->refcount, amdgpu_bo_list_free);
     168           0 : }
     169             : 
     170           0 : int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id,
     171             :                        struct amdgpu_bo_list **result)
     172             : {
     173             :         rcu_read_lock();
     174           0 :         *result = idr_find(&fpriv->bo_list_handles, id);
     175             : 
     176           0 :         if (*result && kref_get_unless_zero(&(*result)->refcount)) {
     177             :                 rcu_read_unlock();
     178           0 :                 return 0;
     179             :         }
     180             : 
     181             :         rcu_read_unlock();
     182           0 :         return -ENOENT;
     183             : }
     184             : 
     185           0 : void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list,
     186             :                              struct list_head *validated)
     187             : {
     188             :         /* This is based on the bucket sort with O(n) time complexity.
     189             :          * An item with priority "i" is added to bucket[i]. The lists are then
     190             :          * concatenated in descending order.
     191             :          */
     192             :         struct list_head bucket[AMDGPU_BO_LIST_NUM_BUCKETS];
     193             :         struct amdgpu_bo_list_entry *e;
     194             :         unsigned i;
     195             : 
     196           0 :         for (i = 0; i < AMDGPU_BO_LIST_NUM_BUCKETS; i++)
     197           0 :                 INIT_LIST_HEAD(&bucket[i]);
     198             : 
     199             :         /* Since buffers which appear sooner in the relocation list are
     200             :          * likely to be used more often than buffers which appear later
     201             :          * in the list, the sort mustn't change the ordering of buffers
     202             :          * with the same priority, i.e. it must be stable.
     203             :          */
     204           0 :         amdgpu_bo_list_for_each_entry(e, list) {
     205           0 :                 struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo);
     206           0 :                 unsigned priority = e->priority;
     207             : 
     208           0 :                 if (!bo->parent)
     209           0 :                         list_add_tail(&e->tv.head, &bucket[priority]);
     210             : 
     211           0 :                 e->user_pages = NULL;
     212             :         }
     213             : 
     214             :         /* Connect the sorted buckets in the output list. */
     215           0 :         for (i = 0; i < AMDGPU_BO_LIST_NUM_BUCKETS; i++)
     216           0 :                 list_splice(&bucket[i], validated);
     217           0 : }
     218             : 
     219           0 : void amdgpu_bo_list_put(struct amdgpu_bo_list *list)
     220             : {
     221           0 :         kref_put(&list->refcount, amdgpu_bo_list_free);
     222           0 : }
     223             : 
     224           0 : int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in,
     225             :                                       struct drm_amdgpu_bo_list_entry **info_param)
     226             : {
     227           0 :         const void __user *uptr = u64_to_user_ptr(in->bo_info_ptr);
     228           0 :         const uint32_t info_size = sizeof(struct drm_amdgpu_bo_list_entry);
     229             :         struct drm_amdgpu_bo_list_entry *info;
     230             :         int r;
     231             : 
     232           0 :         info = kvmalloc_array(in->bo_number, info_size, GFP_KERNEL);
     233           0 :         if (!info)
     234             :                 return -ENOMEM;
     235             : 
     236             :         /* copy the handle array from userspace to a kernel buffer */
     237           0 :         r = -EFAULT;
     238           0 :         if (likely(info_size == in->bo_info_size)) {
     239           0 :                 unsigned long bytes = in->bo_number *
     240             :                         in->bo_info_size;
     241             : 
     242           0 :                 if (copy_from_user(info, uptr, bytes))
     243             :                         goto error_free;
     244             : 
     245             :         } else {
     246           0 :                 unsigned long bytes = min(in->bo_info_size, info_size);
     247             :                 unsigned i;
     248             : 
     249           0 :                 memset(info, 0, in->bo_number * info_size);
     250           0 :                 for (i = 0; i < in->bo_number; ++i) {
     251           0 :                         if (copy_from_user(&info[i], uptr, bytes))
     252             :                                 goto error_free;
     253             : 
     254           0 :                         uptr += in->bo_info_size;
     255             :                 }
     256             :         }
     257             : 
     258           0 :         *info_param = info;
     259           0 :         return 0;
     260             : 
     261             : error_free:
     262           0 :         kvfree(info);
     263           0 :         return r;
     264             : }
     265             : 
     266           0 : int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data,
     267             :                                 struct drm_file *filp)
     268             : {
     269           0 :         struct amdgpu_device *adev = drm_to_adev(dev);
     270           0 :         struct amdgpu_fpriv *fpriv = filp->driver_priv;
     271           0 :         union drm_amdgpu_bo_list *args = data;
     272           0 :         uint32_t handle = args->in.list_handle;
     273           0 :         struct drm_amdgpu_bo_list_entry *info = NULL;
     274             :         struct amdgpu_bo_list *list, *old;
     275             :         int r;
     276             : 
     277           0 :         r = amdgpu_bo_create_list_entry_array(&args->in, &info);
     278           0 :         if (r)
     279             :                 return r;
     280             : 
     281           0 :         switch (args->in.operation) {
     282             :         case AMDGPU_BO_LIST_OP_CREATE:
     283           0 :                 r = amdgpu_bo_list_create(adev, filp, info, args->in.bo_number,
     284             :                                           &list);
     285           0 :                 if (r)
     286             :                         goto error_free;
     287             : 
     288           0 :                 mutex_lock(&fpriv->bo_list_lock);
     289           0 :                 r = idr_alloc(&fpriv->bo_list_handles, list, 1, 0, GFP_KERNEL);
     290           0 :                 mutex_unlock(&fpriv->bo_list_lock);
     291           0 :                 if (r < 0) {
     292             :                         goto error_put_list;
     293             :                 }
     294             : 
     295           0 :                 handle = r;
     296           0 :                 break;
     297             : 
     298             :         case AMDGPU_BO_LIST_OP_DESTROY:
     299           0 :                 amdgpu_bo_list_destroy(fpriv, handle);
     300           0 :                 handle = 0;
     301           0 :                 break;
     302             : 
     303             :         case AMDGPU_BO_LIST_OP_UPDATE:
     304           0 :                 r = amdgpu_bo_list_create(adev, filp, info, args->in.bo_number,
     305             :                                           &list);
     306           0 :                 if (r)
     307             :                         goto error_free;
     308             : 
     309           0 :                 mutex_lock(&fpriv->bo_list_lock);
     310           0 :                 old = idr_replace(&fpriv->bo_list_handles, list, handle);
     311           0 :                 mutex_unlock(&fpriv->bo_list_lock);
     312             : 
     313           0 :                 if (IS_ERR(old)) {
     314           0 :                         r = PTR_ERR(old);
     315           0 :                         goto error_put_list;
     316             :                 }
     317             : 
     318             :                 amdgpu_bo_list_put(old);
     319             :                 break;
     320             : 
     321             :         default:
     322             :                 r = -EINVAL;
     323             :                 goto error_free;
     324             :         }
     325             : 
     326           0 :         memset(args, 0, sizeof(*args));
     327           0 :         args->out.list_handle = handle;
     328           0 :         kvfree(info);
     329             : 
     330           0 :         return 0;
     331             : 
     332             : error_put_list:
     333           0 :         amdgpu_bo_list_put(list);
     334             : 
     335             : error_free:
     336           0 :         kvfree(info);
     337           0 :         return r;
     338             : }

Generated by: LCOV version 1.14