summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/amdkfd/kfd_chardev.c')
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c97
1 files changed, 91 insertions, 6 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index 22925df6a791..88621cb7d409 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -164,8 +164,13 @@ static int kfd_release(struct inode *inode, struct file *filep)
{
struct kfd_process *process = filep->private_data;
- if (process)
- kfd_unref_process(process);
+ if (!process)
+ return 0;
+
+ if (process->context_id != KFD_CONTEXT_ID_PRIMARY)
+ kfd_process_notifier_release_internal(process);
+
+ kfd_unref_process(process);
return 0;
}
@@ -216,6 +221,11 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties,
pr_debug("Size lower. clamped to KFD_MIN_QUEUE_RING_SIZE");
}
+ if ((args->metadata_ring_size != 0) && !is_power_of_2(args->metadata_ring_size)) {
+ pr_err("Metadata ring size must be a power of 2 or 0\n");
+ return -EINVAL;
+ }
+
if (!access_ok((const void __user *) args->read_pointer_address,
sizeof(uint32_t))) {
pr_err("Can't access read pointer\n");
@@ -250,6 +260,9 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties,
q_properties->priority = args->queue_priority;
q_properties->queue_address = args->ring_base_address;
q_properties->queue_size = args->ring_size;
+ if (args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE_AQL)
+ q_properties->metadata_queue_size = args->metadata_ring_size;
+
q_properties->read_ptr = (void __user *)args->read_pointer_address;
q_properties->write_ptr = (void __user *)args->write_pointer_address;
q_properties->eop_ring_buffer_address = args->eop_buffer_address;
@@ -1057,6 +1070,12 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep,
if (args->size == 0)
return -EINVAL;
+ if (p->context_id != KFD_CONTEXT_ID_PRIMARY && (flags & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR)) {
+ pr_debug("USERPTR is not supported on non-primary kfd_process\n");
+
+ return -EOPNOTSUPP;
+ }
+
#if IS_ENABLED(CONFIG_HSA_AMD_SVM)
/* Flush pending deferred work to avoid racing with deferred actions
* from previous memory map changes (e.g. munmap).
@@ -1713,6 +1732,12 @@ static int kfd_ioctl_svm(struct file *filep, struct kfd_process *p, void *data)
struct kfd_ioctl_svm_args *args = data;
int r = 0;
+ if (p->context_id != KFD_CONTEXT_ID_PRIMARY) {
+ pr_debug("SVM ioctl not supported on non-primary kfd process\n");
+
+ return -EOPNOTSUPP;
+ }
+
pr_debug("start 0x%llx size 0x%llx op 0x%x nattr 0x%x\n",
args->start_addr, args->size, args->op, args->nattr);
@@ -2914,6 +2939,12 @@ static int kfd_ioctl_set_debug_trap(struct file *filep, struct kfd_process *p, v
struct kfd_process_device *pdd = NULL;
int r = 0;
+ if (p->context_id != KFD_CONTEXT_ID_PRIMARY) {
+ pr_debug("Set debug trap ioctl can not be invoked on non-primary kfd process\n");
+
+ return -EOPNOTSUPP;
+ }
+
if (sched_policy == KFD_SCHED_POLICY_NO_HWS) {
pr_err("Debugging does not support sched_policy %i", sched_policy);
return -EINVAL;
@@ -2958,6 +2989,12 @@ static int kfd_ioctl_set_debug_trap(struct file *filep, struct kfd_process *p, v
goto out;
}
+ if (target->context_id != KFD_CONTEXT_ID_PRIMARY) {
+ pr_debug("Set debug trap ioctl not supported on non-primary kfd process\n");
+ r = -EOPNOTSUPP;
+ goto out;
+ }
+
/* Check if target is still PTRACED. */
rcu_read_lock();
if (target != p && args->op != KFD_IOC_DBG_TRAP_DISABLE
@@ -3121,6 +3158,48 @@ out:
return r;
}
+/* userspace programs need to invoke this ioctl explicitly on a FD to
+ * create a secondary kfd_process which replacing its primary kfd_process
+ */
+static int kfd_ioctl_create_process(struct file *filep, struct kfd_process *p, void *data)
+{
+ struct kfd_process *process;
+ int ret;
+
+ /* Each FD owns only one kfd_process */
+ if (p->context_id != KFD_CONTEXT_ID_PRIMARY)
+ return -EINVAL;
+
+ if (!filep->private_data || !p)
+ return -EINVAL;
+
+ mutex_lock(&kfd_processes_mutex);
+ if (p != filep->private_data) {
+ mutex_unlock(&kfd_processes_mutex);
+ return -EINVAL;
+ }
+
+ process = create_process(current, false);
+ if (IS_ERR(process)) {
+ mutex_unlock(&kfd_processes_mutex);
+ return PTR_ERR(process);
+ }
+
+ filep->private_data = process;
+ mutex_unlock(&kfd_processes_mutex);
+
+ ret = kfd_create_process_sysfs(process);
+ if (ret)
+ pr_warn("Failed to create sysfs entry for the kfd_process");
+
+ /* Each open() increases kref of the primary kfd_process,
+ * so we need to reduce it here when we create a new secondary process replacing it
+ */
+ kfd_unref_process(p);
+
+ return 0;
+}
+
#define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \
[_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, \
.cmd_drv = 0, .name = #ioctl}
@@ -3239,6 +3318,9 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = {
AMDKFD_IOCTL_DEF(AMDKFD_IOC_DBG_TRAP,
kfd_ioctl_set_debug_trap, 0),
+
+ AMDKFD_IOCTL_DEF(AMDKFD_IOC_CREATE_PROCESS,
+ kfd_ioctl_create_process, 0),
};
#define AMDKFD_CORE_IOCTL_COUNT ARRAY_SIZE(amdkfd_ioctls)
@@ -3397,16 +3479,19 @@ static int kfd_mmio_mmap(struct kfd_node *dev, struct kfd_process *process,
}
-static int kfd_mmap(struct file *filp, struct vm_area_struct *vma)
+static int kfd_mmap(struct file *filep, struct vm_area_struct *vma)
{
struct kfd_process *process;
struct kfd_node *dev = NULL;
unsigned long mmap_offset;
unsigned int gpu_id;
- process = kfd_get_process(current);
- if (IS_ERR(process))
- return PTR_ERR(process);
+ process = filep->private_data;
+ if (!process)
+ return -ESRCH;
+
+ if (process->lead_thread != current->group_leader)
+ return -EBADF;
mmap_offset = vma->vm_pgoff << PAGE_SHIFT;
gpu_id = KFD_MMAP_GET_GPU_ID(mmap_offset);