drm/amdgpu: Allow to create BO lists in CS ioctl v3
This change is to support MESA performace optimization. Modify CS IOCTL to allow its input as command buffer and an array of buffer handles to create a temporay bo list and then destroy it when IOCTL completes. This saves on calling for BO_LIST create and destry IOCTLs in MESA and by this improves performance. v2: Avoid inserting the temp list into idr struct. v3: Remove idr alloation from amdgpu_bo_list_create. Remove useless argument from amdgpu_cs_parser_fini Minor cosmetic stuff. v4: Revert amdgpu_bo_list_destroy back to static Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
8415afbd86
commit
964d0fbf63
@ -732,6 +732,14 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list,
|
||||
struct list_head *validated);
|
||||
void amdgpu_bo_list_put(struct amdgpu_bo_list *list);
|
||||
void amdgpu_bo_list_free(struct amdgpu_bo_list *list);
|
||||
int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in,
|
||||
struct drm_amdgpu_bo_list_entry **info_param);
|
||||
|
||||
int amdgpu_bo_list_create(struct amdgpu_device *adev,
|
||||
struct drm_file *filp,
|
||||
struct drm_amdgpu_bo_list_entry *info,
|
||||
unsigned num_entries,
|
||||
struct amdgpu_bo_list **list);
|
||||
|
||||
/*
|
||||
* GFX stuff
|
||||
|
@ -55,15 +55,15 @@ static void amdgpu_bo_list_release_rcu(struct kref *ref)
|
||||
kfree_rcu(list, rhead);
|
||||
}
|
||||
|
||||
static int amdgpu_bo_list_create(struct amdgpu_device *adev,
|
||||
int amdgpu_bo_list_create(struct amdgpu_device *adev,
|
||||
struct drm_file *filp,
|
||||
struct drm_amdgpu_bo_list_entry *info,
|
||||
unsigned num_entries,
|
||||
int *id)
|
||||
struct amdgpu_bo_list **list_out)
|
||||
{
|
||||
int r;
|
||||
struct amdgpu_fpriv *fpriv = filp->driver_priv;
|
||||
struct amdgpu_bo_list *list;
|
||||
int r;
|
||||
|
||||
|
||||
list = kzalloc(sizeof(struct amdgpu_bo_list), GFP_KERNEL);
|
||||
if (!list)
|
||||
@ -78,16 +78,7 @@ static int amdgpu_bo_list_create(struct amdgpu_device *adev,
|
||||
return r;
|
||||
}
|
||||
|
||||
/* idr alloc should be called only after initialization of bo list. */
|
||||
mutex_lock(&fpriv->bo_list_lock);
|
||||
r = idr_alloc(&fpriv->bo_list_handles, list, 1, 0, GFP_KERNEL);
|
||||
mutex_unlock(&fpriv->bo_list_lock);
|
||||
if (r < 0) {
|
||||
amdgpu_bo_list_free(list);
|
||||
return r;
|
||||
}
|
||||
*id = r;
|
||||
|
||||
*list_out = list;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -263,55 +254,79 @@ void amdgpu_bo_list_free(struct amdgpu_bo_list *list)
|
||||
kfree(list);
|
||||
}
|
||||
|
||||
int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *filp)
|
||||
int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in,
|
||||
struct drm_amdgpu_bo_list_entry **info_param)
|
||||
{
|
||||
const void __user *uptr = u64_to_user_ptr(in->bo_info_ptr);
|
||||
const uint32_t info_size = sizeof(struct drm_amdgpu_bo_list_entry);
|
||||
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
struct amdgpu_fpriv *fpriv = filp->driver_priv;
|
||||
union drm_amdgpu_bo_list *args = data;
|
||||
uint32_t handle = args->in.list_handle;
|
||||
const void __user *uptr = u64_to_user_ptr(args->in.bo_info_ptr);
|
||||
|
||||
struct drm_amdgpu_bo_list_entry *info;
|
||||
struct amdgpu_bo_list *list;
|
||||
|
||||
int r;
|
||||
|
||||
info = kvmalloc_array(args->in.bo_number,
|
||||
sizeof(struct drm_amdgpu_bo_list_entry), GFP_KERNEL);
|
||||
info = kvmalloc_array(in->bo_number, info_size, GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
/* copy the handle array from userspace to a kernel buffer */
|
||||
r = -EFAULT;
|
||||
if (likely(info_size == args->in.bo_info_size)) {
|
||||
unsigned long bytes = args->in.bo_number *
|
||||
args->in.bo_info_size;
|
||||
if (likely(info_size == in->bo_info_size)) {
|
||||
unsigned long bytes = in->bo_number *
|
||||
in->bo_info_size;
|
||||
|
||||
if (copy_from_user(info, uptr, bytes))
|
||||
goto error_free;
|
||||
|
||||
} else {
|
||||
unsigned long bytes = min(args->in.bo_info_size, info_size);
|
||||
unsigned long bytes = min(in->bo_info_size, info_size);
|
||||
unsigned i;
|
||||
|
||||
memset(info, 0, args->in.bo_number * info_size);
|
||||
for (i = 0; i < args->in.bo_number; ++i) {
|
||||
memset(info, 0, in->bo_number * info_size);
|
||||
for (i = 0; i < in->bo_number; ++i) {
|
||||
if (copy_from_user(&info[i], uptr, bytes))
|
||||
goto error_free;
|
||||
|
||||
uptr += args->in.bo_info_size;
|
||||
uptr += in->bo_info_size;
|
||||
}
|
||||
}
|
||||
|
||||
*info_param = info;
|
||||
return 0;
|
||||
|
||||
error_free:
|
||||
kvfree(info);
|
||||
return r;
|
||||
}
|
||||
|
||||
int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *filp)
|
||||
{
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
struct amdgpu_fpriv *fpriv = filp->driver_priv;
|
||||
union drm_amdgpu_bo_list *args = data;
|
||||
uint32_t handle = args->in.list_handle;
|
||||
struct drm_amdgpu_bo_list_entry *info = NULL;
|
||||
struct amdgpu_bo_list *list;
|
||||
int r;
|
||||
|
||||
r = amdgpu_bo_create_list_entry_array(&args->in, &info);
|
||||
if (r)
|
||||
goto error_free;
|
||||
|
||||
switch (args->in.operation) {
|
||||
case AMDGPU_BO_LIST_OP_CREATE:
|
||||
r = amdgpu_bo_list_create(adev, filp, info, args->in.bo_number,
|
||||
&handle);
|
||||
&list);
|
||||
if (r)
|
||||
goto error_free;
|
||||
|
||||
mutex_lock(&fpriv->bo_list_lock);
|
||||
r = idr_alloc(&fpriv->bo_list_handles, list, 1, 0, GFP_KERNEL);
|
||||
mutex_unlock(&fpriv->bo_list_lock);
|
||||
if (r < 0) {
|
||||
amdgpu_bo_list_free(list);
|
||||
return r;
|
||||
}
|
||||
|
||||
handle = r;
|
||||
break;
|
||||
|
||||
case AMDGPU_BO_LIST_OP_DESTROY:
|
||||
@ -345,6 +360,7 @@ int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data,
|
||||
return 0;
|
||||
|
||||
error_free:
|
||||
kvfree(info);
|
||||
if (info)
|
||||
kvfree(info);
|
||||
return r;
|
||||
}
|
||||
|
@ -66,11 +66,35 @@ static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
|
||||
static int amdgpu_cs_bo_handles_chunk(struct amdgpu_cs_parser *p,
|
||||
struct drm_amdgpu_bo_list_in *data)
|
||||
{
|
||||
int r;
|
||||
struct drm_amdgpu_bo_list_entry *info = NULL;
|
||||
|
||||
r = amdgpu_bo_create_list_entry_array(data, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_bo_list_create(p->adev, p->filp, info, data->bo_number,
|
||||
&p->bo_list);
|
||||
if (r)
|
||||
goto error_free;
|
||||
|
||||
kvfree(info);
|
||||
return 0;
|
||||
|
||||
error_free:
|
||||
if (info)
|
||||
kvfree(info);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, union drm_amdgpu_cs *cs)
|
||||
{
|
||||
struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
|
||||
struct amdgpu_vm *vm = &fpriv->vm;
|
||||
union drm_amdgpu_cs *cs = data;
|
||||
uint64_t *chunk_array_user;
|
||||
uint64_t *chunk_array;
|
||||
unsigned size, num_ibs = 0;
|
||||
@ -164,6 +188,19 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
|
||||
|
||||
break;
|
||||
|
||||
case AMDGPU_CHUNK_ID_BO_HANDLES:
|
||||
size = sizeof(struct drm_amdgpu_bo_list_in);
|
||||
if (p->chunks[i].length_dw * sizeof(uint32_t) < size) {
|
||||
ret = -EINVAL;
|
||||
goto free_partial_kdata;
|
||||
}
|
||||
|
||||
ret = amdgpu_cs_bo_handles_chunk(p, p->chunks[i].kdata);
|
||||
if (ret)
|
||||
goto free_partial_kdata;
|
||||
|
||||
break;
|
||||
|
||||
case AMDGPU_CHUNK_ID_DEPENDENCIES:
|
||||
case AMDGPU_CHUNK_ID_SYNCOBJ_IN:
|
||||
case AMDGPU_CHUNK_ID_SYNCOBJ_OUT:
|
||||
@ -534,7 +571,12 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
|
||||
|
||||
INIT_LIST_HEAD(&p->validated);
|
||||
|
||||
p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle);
|
||||
/* p->bo_list could already be assigned if AMDGPU_CHUNK_ID_BO_HANDLES is present */
|
||||
if (!p->bo_list)
|
||||
p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle);
|
||||
else
|
||||
mutex_lock(&p->bo_list->lock);
|
||||
|
||||
if (p->bo_list) {
|
||||
amdgpu_bo_list_get_list(p->bo_list, &p->validated);
|
||||
if (p->bo_list->first_userptr != p->bo_list->num_entries)
|
||||
|
@ -69,9 +69,10 @@
|
||||
* - 3.24.0 - Add high priority compute support for gfx9
|
||||
* - 3.25.0 - Add support for sensor query info (stable pstate sclk/mclk).
|
||||
* - 3.26.0 - GFX9: Process AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE.
|
||||
* - 3.27.0 - Add new chunk to to AMDGPU_CS to enable BO_LIST creation.
|
||||
*/
|
||||
#define KMS_DRIVER_MAJOR 3
|
||||
#define KMS_DRIVER_MINOR 26
|
||||
#define KMS_DRIVER_MINOR 27
|
||||
#define KMS_DRIVER_PATCHLEVEL 0
|
||||
|
||||
int amdgpu_vram_limit = 0;
|
||||
|
@ -516,6 +516,7 @@ struct drm_amdgpu_gem_va {
|
||||
#define AMDGPU_CHUNK_ID_DEPENDENCIES 0x03
|
||||
#define AMDGPU_CHUNK_ID_SYNCOBJ_IN 0x04
|
||||
#define AMDGPU_CHUNK_ID_SYNCOBJ_OUT 0x05
|
||||
#define AMDGPU_CHUNK_ID_BO_HANDLES 0x06
|
||||
|
||||
struct drm_amdgpu_cs_chunk {
|
||||
__u32 chunk_id;
|
||||
|
Loading…
Reference in New Issue
Block a user