drm/amdkfd: Add support for user-mode trap handlers
authorFelix Kuehling <Felix.Kuehling@amd.com>
Tue, 14 Nov 2017 21:41:20 +0000 (16:41 -0500)
committerOded Gabbay <oded.gabbay@gmail.com>
Tue, 14 Nov 2017 21:41:20 +0000 (16:41 -0500)
A second-level user mode trap handler can be installed. The CWSR trap
handler jumps to the secondary trap handler conditionally for any
conditions not handled by it. This can be used e.g. for debugging or
catching math exceptions.

When CWSR is disabled, the user mode trap handler is installed as
first level trap handler.

Signed-off-by: Shaoyun.liu <shaoyun.liu@amd.com>
Signed-off-by: Jay Cornwall <Jay.Cornwall@amd.com>
Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
include/uapi/linux/kfd_ioctl.h

index 2a4612d8437ae0c25f23ba3f72552d669cf02075..cc61ec2898802a5d15f26367c34ce16cdf3c009a 100644 (file)
@@ -432,6 +432,38 @@ out:
        return err;
 }
 
+static int kfd_ioctl_set_trap_handler(struct file *filep,
+                                       struct kfd_process *p, void *data)
+{
+       struct kfd_ioctl_set_trap_handler_args *args = data;
+       struct kfd_dev *dev;
+       int err = 0;
+       struct kfd_process_device *pdd;
+
+       dev = kfd_device_by_id(args->gpu_id);
+       if (dev == NULL)
+               return -EINVAL;
+
+       mutex_lock(&p->mutex);
+
+       pdd = kfd_bind_process_to_device(dev, p);
+       if (IS_ERR(pdd)) {
+               err = -ESRCH;
+               goto out;
+       }
+
+       if (dev->dqm->ops.set_trap_handler(dev->dqm,
+                                       &pdd->qpd,
+                                       args->tba_addr,
+                                       args->tma_addr))
+               err = -EINVAL;
+
+out:
+       mutex_unlock(&p->mutex);
+
+       return err;
+}
+
 static int kfd_ioctl_dbg_register(struct file *filep,
                                struct kfd_process *p, void *data)
 {
@@ -980,7 +1012,10 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = {
                        kfd_ioctl_set_scratch_backing_va, 0),
 
        AMDKFD_IOCTL_DEF(AMDKFD_IOC_GET_TILE_CONFIG,
-                       kfd_ioctl_get_tile_config, 0)
+                       kfd_ioctl_get_tile_config, 0),
+
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_SET_TRAP_HANDLER,
+                       kfd_ioctl_set_trap_handler, 0),
 };
 
 #define AMDKFD_CORE_IOCTL_COUNT        ARRAY_SIZE(amdkfd_ioctls)
index 5c065024e2855439ef5028f27dfd8a1eeb2926a9..8447810c9a1e8024131c6f38570e7a7d32987c60 100644 (file)
@@ -1116,6 +1116,26 @@ out:
        return retval;
 }
 
+static int set_trap_handler(struct device_queue_manager *dqm,
+                               struct qcm_process_device *qpd,
+                               uint64_t tba_addr,
+                               uint64_t tma_addr)
+{
+       uint64_t *tma;
+
+       if (dqm->dev->cwsr_enabled) {
+               /* Jump from CWSR trap handler to user trap */
+               tma = (uint64_t *)(qpd->cwsr_kaddr + KFD_CWSR_TMA_OFFSET);
+               tma[0] = tba_addr;
+               tma[1] = tma_addr;
+       } else {
+               qpd->tba_addr = tba_addr;
+               qpd->tma_addr = tma_addr;
+       }
+
+       return 0;
+}
+
 static int process_termination_nocpsch(struct device_queue_manager *dqm,
                struct qcm_process_device *qpd)
 {
@@ -1247,6 +1267,7 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev)
                dqm->ops.create_kernel_queue = create_kernel_queue_cpsch;
                dqm->ops.destroy_kernel_queue = destroy_kernel_queue_cpsch;
                dqm->ops.set_cache_memory_policy = set_cache_memory_policy;
+               dqm->ops.set_trap_handler = set_trap_handler;
                dqm->ops.process_termination = process_termination_cpsch;
                break;
        case KFD_SCHED_POLICY_NO_HWS:
@@ -1262,6 +1283,7 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev)
                dqm->ops.initialize = initialize_nocpsch;
                dqm->ops.uninitialize = uninitialize;
                dqm->ops.set_cache_memory_policy = set_cache_memory_policy;
+               dqm->ops.set_trap_handler = set_trap_handler;
                dqm->ops.process_termination = process_termination_nocpsch;
                break;
        default:
index 5b77cb69f732d3e3c4ac4a1761da12ecdf07a983..8752edf9cd9b3d11c48c4c9c05aadbb1fea43b93 100644 (file)
@@ -123,6 +123,11 @@ struct device_queue_manager_ops {
                                           void __user *alternate_aperture_base,
                                           uint64_t alternate_aperture_size);
 
+       int     (*set_trap_handler)(struct device_queue_manager *dqm,
+                                   struct qcm_process_device *qpd,
+                                   uint64_t tba_addr,
+                                   uint64_t tma_addr);
+
        int (*process_termination)(struct device_queue_manager *dqm,
                        struct qcm_process_device *qpd);
 };
index f7563ef2e883d1d81ca63de6ca6e95228a23c2ef..f4cab5b3ba9aaf3c78c7004665363aef89aa8d3b 100644 (file)
@@ -262,6 +262,13 @@ struct kfd_ioctl_get_tile_config_args {
         */
 };
 
+struct kfd_ioctl_set_trap_handler_args {
+       uint64_t tba_addr;              /* to KFD */
+       uint64_t tma_addr;              /* to KFD */
+       uint32_t gpu_id;                /* to KFD */
+       uint32_t pad;
+};
+
 #define AMDKFD_IOCTL_BASE 'K'
 #define AMDKFD_IO(nr)                  _IO(AMDKFD_IOCTL_BASE, nr)
 #define AMDKFD_IOR(nr, type)           _IOR(AMDKFD_IOCTL_BASE, nr, type)
@@ -322,7 +329,10 @@ struct kfd_ioctl_get_tile_config_args {
 #define AMDKFD_IOC_GET_TILE_CONFIG                                      \
                AMDKFD_IOWR(0x12, struct kfd_ioctl_get_tile_config_args)
 
+#define AMDKFD_IOC_SET_TRAP_HANDLER            \
+               AMDKFD_IOW(0x13, struct kfd_ioctl_set_trap_handler_args)
+
 #define AMDKFD_COMMAND_START           0x01
-#define AMDKFD_COMMAND_END             0x13
+#define AMDKFD_COMMAND_END             0x14
 
 #endif