Add H/W Debugger module support to amdkfd
Subsystems (3)
cover Add H/W Debugger module support to amdkfd
This patch-set adds the H/W debugger module support to amdkfd. The H/W debugger module support enables a userspace debugger, e.g gdb, to debug GPU kernels running in HSA mode.
The available operations in this patch-set are setting watchpoints in the GPU kernel and controlling wave-fronts.
It is important to mention that due to security reasons, the userspace process can only debug itself. This means that the process should contain an "agent" that could be connected to remotely by a debugger, which will provide the front-end to the user.
There is ongoing work inside AMD to provide such a tool via gdb extensions.
In addition, this patch-set enables amdkfd to "kill" all running waves, in case of an infinite GPU kernel (due to bug or malicious attack), by using the debugger infrastructure. This provides greater control to the kernel level, which is always a good thing, IMO.
More data is inside the individual commit messages.
Please review.
Thanks,
Oded
Alexey Skidanov (1):
drm/radeon: Add ATC VMID<-->PASID functions to kfd->kgd
Ben Goz (1):
drm/amdkfd: Enforce kill all waves on process termination
Yair Shachar (9):
drm/radeon: Add H/W debugger kfd->kgd functions drm/amdkfd: add H/W debugger IOCTL set definitions drm/amdkfd: Add static user-mode queues support drm/amdkfd: Add skeleton H/W debugger module support drm/amdkfd: Add wave control operation to debugger drm/amdkfd: Add address watch operation to debugger drm/amdkfd: Implement (un)register debugger IOCTLs drm/amdkfd: Implement wave control debugger IOCTL drm/amdkfd: Implement address watch debugger IOCTL
drivers/gpu/drm/amd/amdkfd/Makefile | 3 +- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 310 +++++++ drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c | 886 +++++++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.h | 193 +++++ drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c | 168 ++++ drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.h | 294 +++++++ drivers/gpu/drm/amd/amdkfd/kfd_device.c | 5 + .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 48 +- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | 6 + drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c | 46 +- drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers.h | 6 +- drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h | 290 +++++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 18 + drivers/gpu/drm/amd/amdkfd/kfd_process.c | 8 + .../gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 18 +- drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 21 + drivers/gpu/drm/radeon/cik_reg.h | 56 +- drivers/gpu/drm/radeon/cikd.h | 9 +- drivers/gpu/drm/radeon/radeon_kfd.c | 151 +++- include/uapi/linux/kfd_ioctl.h | 43 +- 20 files changed, 2548 insertions(+), 31 deletions(-) create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.h create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.h create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h
Signature · 6 lines
2.1.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 1/11 drm/radeon: Add H/W debugger kfd->kgd functions
From: Yair Shachar <[email protected]>
This patch adds new interface functions to the kfd2kgd interface file. The new functions allow to perform H/W debugger operations by writing to GPU registers.
--- drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 13 +++ drivers/gpu/drm/radeon/cik_reg.h | 56 +++++++++++- drivers/gpu/drm/radeon/radeon_kfd.c | 113 ++++++++++++++++++++++++ 3 files changed, 181 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/include/kgd_kfd_interface.h +13 -0
@@ -163,6 +163,19 @@ struct kfd2kgd_calls {int (*hqd_sdma_destroy)(struct kgd_dev *kgd,void *mqd,unsigned int timeout); +int (*address_watch_disable)(struct kgd_dev *kgd); +int (*address_watch_execute)(struct kgd_dev *kgd, +unsigned int watch_point_id, +uint32_t cntl_val, +uint32_t addr_hi, +uint32_t addr_lo); +int (*wave_control_execute)(struct kgd_dev *kgd, +uint32_t gfx_index_val, +uint32_t sq_cmd); +uint32_t (*address_watch_get_offset)(struct kgd_dev *kgd, +unsigned int watch_point_id, +unsigned int reg_offset); +uint16_t (*get_fw_version)(struct kgd_dev *kgd,enum kgd_engine_type type); };
drivers/gpu/drm/radeon/cik_reg.h +55 -1
69 lines not on this page · raw message
drivers/gpu/drm/radeon/radeon_kfd.c +113 -0
137 lines not on this page · raw message
Signature · 6 lines
2.1.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 2/11 drm/amdkfd: add H/W debugger IOCTL set definitions
In reply to Oded GabbayFrom: Yair Shachar <[email protected]>
This patch adds four new IOCTLs to amdkfd. These IOCTLs expose a H/W debugger functionality to the userspace.
The IOCTLs are:
- AMDKFD_IOC_DBG_REGISTER:
The purpose of this IOCTL is to notify amdkfd that a process wants to use GPU debugging facilities on itself only.
It is expected that this IOCTL would be called before any other H/W debugger requests are sent to amdkfd and for each GPU where the H/W debugging needs to be enabled. The use of this IOCTL ensures that only one instance of a debugger is active in the system.
- AMDKFD_IOC_DBG_UNREGISTER:
This IOCTL detaches the debugger/debugged process from the H/W Debug which was established by the AMDKFD_IOC_DBG_REGISTER IOCTL.
- AMDKFD_IOC_DBG_ADDRESS_WATCH:
This IOCTL allows to set different watchpoints with various conditions as indicated by the IOCTL's arguments. The available number of watchpoints is retrieved from topology. This operation is confined to the current debugged process, which was registered through AMDKFD_IOC_DBG_REGISTER.
- AMDKFD_IOC_DBG_WAVE_CONTROL:
This IOCTL allows to control a wavefront as indicated by the IOCTL's arguments. For example, you can halt/resume or kill either a single wavefront or a set of wavefronts. This operation is confined to the current debugged process, which was registered through AMDKFD_IOC_DBG_REGISTER.
Because the arguments for the address watch IOCTL and wave control IOCTL are dynamic, meaning that they could vary in size, the userspace passes a pointer to a structure (in userspace) that contains the value of the arguments. The kernel driver is responsible to parse this structure and validate its contents.
--- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 54 ++++++++++++++++++++++++++++++++ include/uapi/linux/kfd_ioctl.h | 43 +++++++++++++++++++++++-- 2 files changed, 95 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +54 -0
@@ -432,6 +432,48 @@ out:return err; } +static int kfd_ioctl_dbg_register (struct file *filep, +struct kfd_process *p,void *data) +{ +long status = -EFAULT ; + +return status; +} + +static int kfd_ioctl_dbg_unrgesiter (struct file *filep, +struct kfd_process *p,void *data) +{ +long status = -EFAULT ; + +return status; +} + +/* +* Parse and generate variable size data structure for address watch. +* Total size of the buffer and # watch points is limited in order +* to prevent kernel abuse. (no bearing to the much smaller HW limitation +* which is enforced by dbgdev module) +* please also note that the watch address itself are not "copied from user", +* since it be set into the HW in user mode values. +* +*/ +static int kfd_ioctl_dbg_address_watch (struct file *filep, +struct kfd_process *p,void *data) +{ +long status = -EFAULT ; + +return status; +} + +/* Parse and generate fixed size data structure for wave control */ +static int kfd_ioctl_dbg_wave_control (struct file *filep, +struct kfd_process *p,void *data) +{ +long status = -EFAULT ; + +return status; +} +static int kfd_ioctl_get_clock_counters (struct file *filep,struct kfd_process *p,void *data) {
@@ -612,6 +654,18 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = {AMDKFD_IOCTL_DEF (AMDKFD_IOC_WAIT_EVENTS , kfd_ioctl_wait_events,0 ), + +AMDKFD_IOCTL_DEF (AMDKFD_IOC_DBG_REGISTER , + kfd_ioctl_dbg_register,0 ), + +AMDKFD_IOCTL_DEF (AMDKFD_IOC_DBG_UNREGISTER , + kfd_ioctl_dbg_unrgesiter,0 ), + +AMDKFD_IOCTL_DEF (AMDKFD_IOC_DBG_ADDRESS_WATCH , + kfd_ioctl_dbg_address_watch,0 ), + +AMDKFD_IOCTL_DEF (AMDKFD_IOC_DBG_WAVE_CONTROL , + kfd_ioctl_dbg_wave_control, 0), };#define AMDKFD_CORE_IOCTL_COUNT ARRAY_SIZE(amdkfd_ioctls)
include/uapi/linux/kfd_ioctl.h +41 -2
61 lines not on this page · raw message
Signature · 6 lines
2.1.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 3/11 drm/amdkfd: Add static user-mode queues support
In reply to Oded GabbayFrom: Yair Shachar <[email protected]>
This patch adds support for static user-mode queues in QCM. Queues which are designated as static can NOT be preempted by the CP microcode when it is executing its scheduling algorithm.
This is needed for supporting the debugger feature, because we can't allow the CP to preempt queues which are currently being debugged.
The number of queues that can be designated as static is limited by the number of HQDs (Hardware Queue Descriptors).
--- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 2 + .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 38 ++++++++++++++---- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | 6 +++ drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c | 46 +++++++++++++++++----- drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers.h | 6 ++- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 2 + .../gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 16 ++++++++ 7 files changed, 97 insertions(+), 19 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_device.c +2 -0
@@ -33,6 +33,8 @@static const struct kfd_device_info kaveri_device_info = { .asic_family =CHIP_KAVERI , .max_pasid_bits =16 , +/* max num of queues for KV.TODO should be a dynamic value */ + .max_no_of_hqd =24 , .ih_ring_entry_size =4 *sizeof (uint32_t ), .event_interrupt_class = &event_interrupt_class_cik, .mqd_size_aligned =MQD_SIZE_ALIGNED
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +31 -7
@@ -45,7 +45,8 @@ static int create_compute_queue_nocpsch(struct device_queue_manager *dqm, struct qcm_process_device *qpd);static int execute_queues_cpsch (struct device_queue_manager *dqm,bool lock); -static int destroy_queues_cpsch (struct device_queue_manager *dqm,bool lock); +static int destroy_queues_cpsch (struct device_queue_manager *dqm, +bool preempt_static_queues,bool lock); static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm, struct queue *q,
@@ -775,7 +776,7 @@ static int stop_cpsch(struct device_queue_manager *dqm)BUG_ON (!dqm); -destroy_queues_cpsch (dqm, true); +destroy_queues_cpsch (dqm, true, true);list_for_each_entry (node, &dqm->queues, list) { pdd =qpd_to_pdd (node->qpd);
@@ -829,7 +830,8 @@ static void destroy_kernel_queue_cpsch(struct device_queue_manager *dqm,pr_debug ("kfd: In %s\n" , __func__);mutex_lock (&dqm->lock); -destroy_queues_cpsch (dqm, false); +/* here we actually preempt the DIQ */ +destroy_queues_cpsch (dqm, true, false);list_del (&kq->list); dqm->queue_count--; qpd->is_debug = false;
@@ -935,13 +937,15 @@ static int destroy_sdma_queues(struct device_queue_manager *dqm, unsigned int sdma_engine) {return pm_send_unmap_queue (&dqm->packets,KFD_QUEUE_TYPE_SDMA , -KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES ,0 , false, +KFD_PREEMPT_TYPE_FILTER_DYNAMIC_QUEUES ,0 , false, sdma_engine); } -static int destroy_queues_cpsch (struct device_queue_manager *dqm,bool lock) +static int destroy_queues_cpsch (struct device_queue_manager *dqm, +bool preempt_static_queues,bool lock) {int retval; +enum kfd_preempt_type_filter preempt_type;BUG_ON (!dqm);
@@ -960,8 +964,12 @@ static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock)destroy_sdma_queues (dqm,1 ); } + preempt_type = preempt_static_queues ? +KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES : +KFD_PREEMPT_TYPE_FILTER_DYNAMIC_QUEUES ; + retval =pm_send_unmap_queue (&dqm->packets,KFD_QUEUE_TYPE_COMPUTE , -KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES ,0 , false,0 ); + preempt_type,0 , false,0 );if (retval !=0 ) goto out;
@@ -989,7 +997,7 @@ static int execute_queues_cpsch(struct device_queue_manager *dqm, bool lock)if (lock)mutex_lock (&dqm->lock); - retval =destroy_queues_cpsch (dqm, false); + retval =destroy_queues_cpsch (dqm, false, false);if (retval !=0 ) {pr_err ("kfd: the cp might be in an unrecoverable state due to an unsuccessful queues preemption" ); goto out;
@@ -1024,13 +1032,27 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, {int retval;struct mqd_manager *mqd; +bool preempt_all_queues;BUG_ON (!dqm || !qpd || !q); + preempt_all_queues = false; + retval =0 ;/* remove queue from list to prevent rescheduling after preemption */ mutex_lock (&dqm->lock); + +if (qpd->is_debug) { +/* +* error, currently we do not allow to destroy a queue +* of a currently debugged process +*/ + retval = -EBUSY ; + goto failed_try_destroy_debugged_queue; + + } + mqd = dqm->ops.get_mqd_manager (dqm,get_mqd_type_from_queue_type (q->properties.type));if (!mqd) {
@@ -1062,6 +1084,8 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm,return 0 ; failed: +failed_try_destroy_debugged_queue: +mutex_unlock (&dqm->lock);return retval; }
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +6 -0
@@ -88,9 +88,11 @@ struct device_queue_manager_ops {struct queue *q, struct qcm_process_device *qpd, int *allocate_vmid); +int (*destroy_queue)(struct device_queue_manager *dqm,struct qcm_process_device *qpd,struct queue *q); +int (*update_queue)(struct device_queue_manager *dqm,struct queue *q);
@@ -100,8 +102,10 @@ struct device_queue_manager_ops {int (*register_process)(struct device_queue_manager *dqm,struct qcm_process_device *qpd); +int (*unregister_process)(struct device_queue_manager *dqm,struct qcm_process_device *qpd); +int (*initialize)(struct device_queue_manager *dqm);int (*start)(struct device_queue_manager *dqm);int (*stop)(struct device_queue_manager *dqm);
@@ -109,9 +113,11 @@ struct device_queue_manager_ops {int (*create_kernel_queue)(struct device_queue_manager *dqm,struct kernel_queue *kq,struct qcm_process_device *qpd); +void (*destroy_kernel_queue)(struct device_queue_manager *dqm,struct kernel_queue *kq,struct qcm_process_device *qpd); + bool (*set_cache_memory_policy)(struct device_queue_manager *dqm, struct qcm_process_device *qpd, enum cache_policy default_policy,
drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c +36 -10
109 lines not on this page · raw message
drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers.h +4 -2
@@ -237,7 +237,8 @@ struct pm4_map_queues { struct { union { struct { - uint32_t reserved5:2; + uint32_t is_static:1; + uint32_t reserved5:1; uint32_t doorbell_offset:21; uint32_t reserved6:3; uint32_t queue:6;
@@ -328,7 +329,8 @@ enum unmap_queues_action_enum {enum unmap_queues_queue_sel_enum { queue_sel__mes_unmap_queues__perform_request_on_specified_queues =0 , queue_sel__mes_unmap_queues__perform_request_on_pasid_queues =1 , - queue_sel__mes_unmap_queues__perform_request_on_all_active_queues =2 + queue_sel__mes_unmap_queues__perform_request_on_all_active_queues =2 , + queue_sel__mes_unmap_queues__perform_request_on_dynamic_queues_only =3 };enum unmap_queues_engine_sel_enum {
drivers/gpu/drm/amd/amdkfd/kfd_priv.h +2 -0
@@ -128,6 +128,7 @@ struct kfd_device_info {unsigned int asic_family;const struct kfd_event_interrupt_class *event_interrupt_class;unsigned int max_pasid_bits; +unsigned int max_no_of_hqd;size_t ih_ring_entry_size;uint8_t num_of_watch_points;uint16_t mqd_size_aligned;
@@ -230,6 +231,7 @@ struct device *kfd_chardev(void);enum kfd_preempt_type_filter {KFD_PREEMPT_TYPE_FILTER_SINGLE_QUEUE ,KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES , +KFD_PREEMPT_TYPE_FILTER_DYNAMIC_QUEUES ,KFD_PREEMPT_TYPE_FILTER_BY_PASID };
drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +16 -0
@@ -158,6 +158,8 @@ int pqm_create_queue(struct process_queue_manager *pqm,struct queue *q;struct process_queue_node *pqn;struct kernel_queue *kq; +int num_queues =0 ; +struct queue *cur;BUG_ON (!pqm || !dev || !properties || !qid);
@@ -172,6 +174,20 @@ int pqm_create_queue(struct process_queue_manager *pqm,return -1 ; } +/* +* for debug process, verify that it is within the static queues limit +* currently limit is set to half of the total avail HQD slots +* If we are just about to create DIQ, the is_debug flag is not set yet +* Hence we also check the type as well +*/ +if ((pdd->qpd.is_debug) || + (type ==KFD_QUEUE_TYPE_DIQ )) { +list_for_each_entry (cur, &pdd->qpd.queues_list, list) + num_queues++; +if (num_queues >= dev->device_info->max_no_of_hqd/2 ) +return (-ENOSPC ); + } + retval =find_available_queue_slot (pqm, qid);if (retval !=0 )return retval;
Signature · 6 lines
2.1.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 4/11 drm/amdkfd: Add skeleton H/W debugger module support
In reply to Oded GabbayFrom: Yair Shachar <[email protected]>
This patch adds the skeleton H/W debugger module support. This code enables registration and unregistration of a single HSA process at a time.
The module saves the process's pasid and use it to verify that only the registered process is allowed to execute debugger operations through the kernel driver.
--- drivers/gpu/drm/amd/amdkfd/Makefile | 3 +- drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c | 142 ++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.h | 193 ++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c | 135 ++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.h | 287 ++++++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_device.c | 3 + drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h | 290 +++++++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 5 + .../gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 2 +- 9 files changed, 1058 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.h create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.h create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h
drivers/gpu/drm/amd/amdkfd/Makefile +2 -1
@@ -12,6 +12,7 @@ amdkfd-y := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \ kfd_kernel_queue_vi.o kfd_packet_manager.o \ kfd_process_queue_manager.o kfd_device_queue_manager.o \ kfd_device_queue_manager_cik.o kfd_device_queue_manager_vi.o \ - kfd_interrupt.o kfd_events.o cik_event_interrupt.o + kfd_interrupt.o kfd_events.o cik_event_interrupt.o \ + kfd_dbgdev.o kfd_dbgmgr.o obj-$(CONFIG_HSA_AMD) += amdkfd.o
drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c new file +142 -0
142 lines not on this page · raw message
drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.h new file +193 -0
193 lines not on this page · raw message
drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c new file +135 -0
135 lines not on this page · raw message
drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.h new file +287 -0
287 lines not on this page · raw message
drivers/gpu/drm/amd/amdkfd/kfd_device.c +3 -0
@@ -37,6 +37,7 @@ static const struct kfd_device_info kaveri_device_info = { .max_no_of_hqd = 24, .ih_ring_entry_size = 4 * sizeof(uint32_t), .event_interrupt_class = &event_interrupt_class_cik, + .num_of_watch_points = 4, .mqd_size_aligned = MQD_SIZE_ALIGNED };
@@ -296,6 +297,8 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, goto dqm_start_error; } + kfd->dbgmgr =NULL ; + kfd->init_complete = true;dev_info (kfd_device,"added device (%x:%x)\n" , kfd->pdev->vendor, kfd->pdev->device);
drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h new file +290 -0
290 lines not on this page · raw message
drivers/gpu/drm/amd/amdkfd/kfd_priv.h +5 -0
@@ -195,6 +195,9 @@ struct kfd_dev {* from the HW ring into a SW ring. */ bool interrupts_active; + +/* Debug manager */ +struct kfd_dbgmgr *dbgmgr; };/* KGD2KFD callbacks */
@@ -649,6 +652,8 @@ int pqm_create_queue(struct process_queue_manager *pqm,int pqm_destroy_queue (struct process_queue_manager *pqm,unsigned int qid);int pqm_update_queue (struct process_queue_manager *pqm,unsigned int qid,struct queue_properties *p); +struct kernel_queue *pqm_get_kernel_queue (struct process_queue_manager *pqm, +unsigned int qid);/* Packet Manager */
drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +1 -1
@@ -357,7 +357,7 @@ int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid,return 0 ; } -static __attribute__((unused))struct kernel_queue *pqm_get_kernel_queue ( +struct kernel_queue *pqm_get_kernel_queue (struct process_queue_manager *pqm,unsigned int qid) {
Signature · 6 lines
2.1.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 5/11 drm/amdkfd: Add wave control operation to debugger
In reply to Oded GabbayFrom: Yair Shachar <[email protected]>
The wave control operation supports several command types executed upon existing wave fronts that belong to the currently debugged process.
The available commands are:
HALT - Freeze wave front(s) execution
RESUME - Resume freezed wave front(s) execution
KILL - Kill existing wave front(s)
--- drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c | 405 +++++++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c | 16 + drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.h | 5 +- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 4 + 5 files changed, 430 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c +405 -0
@@ -47,6 +47,125 @@ static void dbgdev_address_watch_disable_nodiq(struct kfd_dev *dev) dev->kfd2kgd->address_watch_disable (dev->kgd); } +static int dbgdev_diq_submit_ib (struct kfd_dbgdev *dbgdev, +unsigned int pasid,uint64_t vmid0_address, +uint32_t *packet_buff,size_t size_in_bytes) +{ +struct pm4__release_mem *rm_packet; +struct pm4__indirect_buffer_pasid *ib_packet; +struct kfd_mem_obj *mem_obj; +size_t pq_packets_size_in_bytes; +union ULARGE_INTEGER *largep; +union ULARGE_INTEGER addr; +struct kernel_queue *kq; +uint64_t *rm_state; +unsigned int *ib_packet_buff; +int status; + +BUG_ON (!dbgdev || !dbgdev->kq || !packet_buff || !size_in_bytes); + + kq = dbgdev->kq; + + pq_packets_size_in_bytes =sizeof (struct pm4__release_mem ) + +sizeof (struct pm4__indirect_buffer_pasid ); + +/* +* We acquire a buffer from DIQ +* The receive packet buff will be sitting on the Indirect Buffer +* and in the PQ we put the IB packet + sync packet(s). +*/ + status = kq->ops.acquire_packet_buffer (kq, + pq_packets_size_in_bytes /sizeof (uint32_t ), + &ib_packet_buff); +if (status !=0 ) { +pr_err ("amdkfd: acquire_packet_buffer failed\n" ); +return status; + } + +memset (ib_packet_buff,0 , pq_packets_size_in_bytes); + + ib_packet = (struct pm4__indirect_buffer_pasid *) (ib_packet_buff); + + ib_packet->header.count =3 ; + ib_packet->header.opcode =IT_INDIRECT_BUFFER_PASID ; + ib_packet->header.type =PM4_TYPE_3 ; + + largep = (union ULARGE_INTEGER *) &vmid0_address; + + ib_packet->bitfields2.ib_base_lo = largep->u.low_part >>2 ; + ib_packet->bitfields3.ib_base_hi = largep->u.high_part; + + ib_packet->control = (1 <<23 ) | (1 <<31 ) | + ((size_in_bytes /sizeof (uint32_t )) &0xfffff ); + + ib_packet->bitfields5.pasid = pasid; + +/* +* for now we use release mem for GPU-CPU synchronization +* Consider WaitRegMem + WriteData as a better alternative +* we get a GART allocations ( gpu/cpu mapping), +* for the sync variable, and wait until: +* (a) Sync with HW +* (b) Sync var is written by CP to mem. +*/ + rm_packet = (struct pm4__release_mem *) (ib_packet_buff + + (sizeof (struct pm4__indirect_buffer_pasid ) / +sizeof (unsigned int ))); + + status =kfd_gtt_sa_allocate (dbgdev->dev,sizeof (uint64_t ), + &mem_obj); + +if (status !=0 ) { +pr_err ("amdkfd: Failed to allocate GART memory\n" ); + kq->ops.rollback_packet (kq); +return status; + } + + rm_state = (uint64_t *) mem_obj->cpu_ptr; + + *rm_state =QUEUESTATE__ACTIVE_COMPLETION_PENDING ; + + rm_packet->header.opcode =IT_RELEASE_MEM ; + rm_packet->header.type =PM4_TYPE_3 ; + rm_packet->header.count =sizeof (struct pm4__release_mem ) / +sizeof (unsigned int ) -2 ; + + rm_packet->bitfields2.event_type =CACHE_FLUSH_AND_INV_TS_EVENT ; + rm_packet->bitfields2.event_index = + event_index___release_mem__end_of_pipe; + + rm_packet->bitfields2.cache_policy = cache_policy___release_mem__lru; + rm_packet->bitfields2.atc =0 ; + rm_packet->bitfields2.tc_wb_action_ena =1 ; + + addr.quad_part = mem_obj->gpu_addr; + + rm_packet->bitfields4.address_lo_32b = addr.u.low_part >>2 ; + rm_packet->address_hi = addr.u.high_part; + + rm_packet->bitfields3.data_sel = + data_sel___release_mem__send_64_bit_data; + + rm_packet->bitfields3.int_sel = + int_sel___release_mem__send_data_after_write_confirm; + + rm_packet->bitfields3.dst_sel = + dst_sel___release_mem__memory_controller; + + rm_packet->data_lo =QUEUESTATE__ACTIVE ; + + kq->ops.submit_packet (kq); + +/* Wait till CP writes sync code: */ + status =amdkfd_fence_wait_timeout ( + (unsigned int *) rm_state, +QUEUESTATE__ACTIVE ,1500 ); + +kfd_gtt_sa_free (dbgdev->dev, mem_obj); + +return status; +} +static int dbgdev_register_nodiq (struct kfd_dbgdev *dbgdev) {BUG_ON (!dbgdev);
@@ -117,6 +236,290 @@ static int dbgdev_unregister_diq(struct kfd_dbgdev *dbgdev)return status; } +static int dbgdev_wave_control_set_registers ( +struct dbg_wave_control_info *wac_info, +union SQ_CMD_BITS *in_reg_sq_cmd, +union GRBM_GFX_INDEX_BITS *in_reg_gfx_index) +{ +int status; +union SQ_CMD_BITS reg_sq_cmd; +union GRBM_GFX_INDEX_BITS reg_gfx_index; +struct HsaDbgWaveMsgAMDGen2 *pMsg; + +BUG_ON (!wac_info || !in_reg_sq_cmd || !in_reg_gfx_index); + + reg_sq_cmd.u32All =0 ; + reg_gfx_index.u32All =0 ; + pMsg = &wac_info->dbgWave_msg.DbgWaveMsg.WaveMsgInfoGen2; + +switch (wac_info->mode) { +/* Send command to single wave */ +case HSA_DBG_WAVEMODE_SINGLE : +/* +* Limit access to the process waves only, +* by setting vmid check +*/ + reg_sq_cmd.bits.check_vmid =1 ; + reg_sq_cmd.bits.simd_id = pMsg->ui32.SIMD; + reg_sq_cmd.bits.wave_id = pMsg->ui32.WaveId; + reg_sq_cmd.bits.mode =SQ_IND_CMD_MODE_SINGLE ; + + reg_gfx_index.bits.sh_index = pMsg->ui32.ShaderArray; + reg_gfx_index.bits.se_index = pMsg->ui32.ShaderEngine; + reg_gfx_index.bits.instance_index = pMsg->ui32.HSACU; + +break ; + +/* Send command to all waves with matching VMID */ +case HSA_DBG_WAVEMODE_BROADCAST_PROCESS : + + reg_gfx_index.bits.sh_broadcast_writes =1 ; + reg_gfx_index.bits.se_broadcast_writes =1 ; + reg_gfx_index.bits.instance_broadcast_writes =1 ; + + reg_sq_cmd.bits.mode =SQ_IND_CMD_MODE_BROADCAST ; + +break ; + +/* Send command to all CU waves with matching VMID */ +case HSA_DBG_WAVEMODE_BROADCAST_PROCESS_CU : + + reg_sq_cmd.bits.check_vmid =1 ; + reg_sq_cmd.bits.mode =SQ_IND_CMD_MODE_BROADCAST ; + + reg_gfx_index.bits.sh_index = pMsg->ui32.ShaderArray; + reg_gfx_index.bits.se_index = pMsg->ui32.ShaderEngine; + reg_gfx_index.bits.instance_index = pMsg->ui32.HSACU; + +break ; + +default : +return -EINVAL ; + } + +switch (wac_info->operand) { +case HSA_DBG_WAVEOP_HALT : + reg_sq_cmd.bits.cmd =SQ_IND_CMD_CMD_HALT ; +break ; + +case HSA_DBG_WAVEOP_RESUME : + reg_sq_cmd.bits.cmd =SQ_IND_CMD_CMD_RESUME ; +break ; + +case HSA_DBG_WAVEOP_KILL : + reg_sq_cmd.bits.cmd =SQ_IND_CMD_CMD_KILL ; +break ; + +case HSA_DBG_WAVEOP_DEBUG : + reg_sq_cmd.bits.cmd =SQ_IND_CMD_CMD_DEBUG ; +break ; + +case HSA_DBG_WAVEOP_TRAP : +if (wac_info->trapId <MAX_TRAPID ) { + reg_sq_cmd.bits.cmd =SQ_IND_CMD_CMD_TRAP ; + reg_sq_cmd.bits.trap_id = wac_info->trapId; + }else { + status = -EINVAL ; + } +break ; + +default : + status = -EINVAL ; +break ; + } + +if (status ==0 ) { + *in_reg_sq_cmd = reg_sq_cmd; + *in_reg_gfx_index = reg_gfx_index; + } + +return status; +} + +static int dbgdev_wave_control_diq (struct kfd_dbgdev *dbgdev, +struct dbg_wave_control_info *wac_info) +{ + +int status; +union SQ_CMD_BITS reg_sq_cmd; +union GRBM_GFX_INDEX_BITS reg_gfx_index; +struct kfd_mem_obj *mem_obj; +uint32_t *packet_buff_uint; +struct pm4__set_config_reg *packets_vec; +size_t ib_size =sizeof (struct pm4__set_config_reg ) *3 ; + +BUG_ON (!dbgdev || !wac_info); + + reg_sq_cmd.u32All =0 ; + + status =dbgdev_wave_control_set_registers (wac_info, ®_sq_cmd, + ®_gfx_index); +if (status) { +pr_err ("amdkfd: Failed to set wave control registers\n" ); +return status; + } + +/* we do not control the VMID in DIQ,so reset it to a known value */ + reg_sq_cmd.bits.vm_id =0 ; + +pr_debug ("\t\t %30s\n" ,"* * * * * * * * * * * * * * * * * *" ); + +pr_debug ("\t\t mode is: %u\n" , wac_info->mode); +pr_debug ("\t\t operand is: %u\n" , wac_info->operand); +pr_debug ("\t\t trap id is: %u\n" , wac_info->trapId); +pr_debug ("\t\t msg value is: %u\n" , + wac_info->dbgWave_msg.DbgWaveMsg.WaveMsgInfoGen2.Value); +pr_debug ("\t\t vmid is: N/A\n" ); + +pr_debug ("\t\t chk_vmid is : %u\n" , reg_sq_cmd.bitfields.check_vmid); +pr_debug ("\t\t command is : %u\n" , reg_sq_cmd.bitfields.cmd); +pr_debug ("\t\t queue id is : %u\n" , reg_sq_cmd.bitfields.queue_id); +pr_debug ("\t\t simd id is : %u\n" , reg_sq_cmd.bitfields.simd_id); +pr_debug ("\t\t mode is : %u\n" , reg_sq_cmd.bitfields.mode); +pr_debug ("\t\t vm_id is : %u\n" , reg_sq_cmd.bitfields.vm_id); +pr_debug ("\t\t wave_id is : %u\n" , reg_sq_cmd.bitfields.wave_id); + +pr_debug ("\t\t ibw is : %u\n" , + reg_gfx_index.bitfields.instance_broadcast_writes); +pr_debug ("\t\t ii is : %u\n" , + reg_gfx_index.bitfields.instance_index); +pr_debug ("\t\t sebw is : %u\n" , + reg_gfx_index.bitfields.se_broadcast_writes); +pr_debug ("\t\t se_ind is : %u\n" , reg_gfx_index.bitfields.se_index); +pr_debug ("\t\t sh_ind is : %u\n" , reg_gfx_index.bitfields.sh_index); +pr_debug ("\t\t sbw is : %u\n" , + reg_gfx_index.bitfields.sh_broadcast_writes); + +pr_debug ("\t\t %30s\n" ,"* * * * * * * * * * * * * * * * * *" ); + + status =kfd_gtt_sa_allocate (dbgdev->dev, ib_size, &mem_obj); + +if (status !=0 ) { +pr_err ("amdkfd: Failed to allocate GART memory\n" ); +return status; + } + + packet_buff_uint = mem_obj->cpu_ptr; + +memset (packet_buff_uint,0 , ib_size); + + packets_vec = (struct pm4__set_config_reg *) packet_buff_uint; + packets_vec[0 ].header.count =1 ; + packets_vec[0 ].header.opcode =IT_SET_UCONFIG_REG ; + packets_vec[0 ].header.type =PM4_TYPE_3 ; + packets_vec[0 ].bitfields2.reg_offset = +GRBM_GFX_INDEX / (sizeof (uint32_t )) - +USERCONFIG_REG_BASE ; + + packets_vec[0 ].bitfields2.insert_vmid =0 ; + packets_vec[0 ].reg_data[0 ] = reg_gfx_index.u32All; + + packets_vec[1 ].header.count =1 ; + packets_vec[1 ].header.opcode =IT_SET_CONFIG_REG ; + packets_vec[1 ].header.type =PM4_TYPE_3 ; + packets_vec[1 ].bitfields2.reg_offset =SQ_CMD / (sizeof (uint32_t )) - +CONFIG_REG_BASE ; + + packets_vec[1 ].bitfields2.vmid_shift =SQ_CMD_VMID_OFFSET ; + packets_vec[1 ].bitfields2.insert_vmid =1 ; + packets_vec[1 ].reg_data[0 ] = reg_sq_cmd.u32All; + +/* Restore the GRBM_GFX_INDEX register */ + + reg_gfx_index.u32All =0 ; + reg_gfx_index.bits.sh_broadcast_writes =1 ; + reg_gfx_index.bits.instance_broadcast_writes =1 ; + reg_gfx_index.bits.se_broadcast_writes =1 ; + + + packets_vec[2 ].ordinal1 = packets_vec[0 ].ordinal1; + packets_vec[2 ].bitfields2.reg_offset = +GRBM_GFX_INDEX / (sizeof (uint32_t )) - +USERCONFIG_REG_BASE ; + + packets_vec[2 ].bitfields2.insert_vmid =0 ; + packets_vec[2 ].reg_data[0 ] = reg_gfx_index.u32All; + + status =dbgdev_diq_submit_ib ( + dbgdev, + wac_info->process->pasid, + mem_obj->gpu_addr, + packet_buff_uint, + ib_size); + +if (status !=0 ) +pr_err ("amdkfd: Failed to submit IB to DIQ\n" ); + +kfd_gtt_sa_free (dbgdev->dev, mem_obj); + +return status; +} + +static int dbgdev_wave_control_nodiq (struct kfd_dbgdev *dbgdev, +struct dbg_wave_control_info *wac_info) +{ +int status; +union SQ_CMD_BITS reg_sq_cmd; +union GRBM_GFX_INDEX_BITS reg_gfx_index; +struct kfd_process_device *pdd; + +BUG_ON (!dbgdev || !dbgdev->dev || !wac_info); + + reg_sq_cmd.u32All =0 ; + +/* taking the VMID for that process on the safe way using PDD */ + pdd =kfd_get_process_device_data (dbgdev->dev, wac_info->process); + +if (!pdd) { +pr_err ("amdkfd: Failed to get pdd for wave control no DIQ\n" ); +return -EFAULT ; + } + status =dbgdev_wave_control_set_registers (wac_info, ®_sq_cmd, + ®_gfx_index); +if (status) { +pr_err ("amdkfd: Failed to set wave control registers\n" ); +return status; + } + +/* for non DIQ we need to patch the VMID: */ + + reg_sq_cmd.bits.vm_id = pdd->qpd.vmid; + +pr_debug ("\t\t %30s\n" ,"* * * * * * * * * * * * * * * * * *" ); + +pr_debug ("\t\t mode is: %u\n" , wac_info->mode); +pr_debug ("\t\t operand is: %u\n" , wac_info->operand); +pr_debug ("\t\t trap id is: %u\n" , wac_info->trapId); +pr_debug ("\t\t msg value is: %u\n" , + wac_info->dbgWave_msg.DbgWaveMsg.WaveMsgInfoGen2.Value); +pr_debug ("\t\t vmid is: %u\n" , pdd->qpd.vmid); + +pr_debug ("\t\t chk_vmid is : %u\n" , reg_sq_cmd.bitfields.check_vmid); +pr_debug ("\t\t command is : %u\n" , reg_sq_cmd.bitfields.cmd); +pr_debug ("\t\t queue id is : %u\n" , reg_sq_cmd.bitfields.queue_id); +pr_debug ("\t\t simd id is : %u\n" , reg_sq_cmd.bitfields.simd_id); +pr_debug ("\t\t mode is : %u\n" , reg_sq_cmd.bitfields.mode); +pr_debug ("\t\t vm_id is : %u\n" , reg_sq_cmd.bitfields.vm_id); +pr_debug ("\t\t wave_id is : %u\n" , reg_sq_cmd.bitfields.wave_id); + +pr_debug ("\t\t ibw is : %u\n" , + reg_gfx_index.bitfields.instance_broadcast_writes); +pr_debug ("\t\t ii is : %u\n" , + reg_gfx_index.bitfields.instance_index); +pr_debug ("\t\t sebw is : %u\n" , + reg_gfx_index.bitfields.se_broadcast_writes); +pr_debug ("\t\t se_ind is : %u\n" , reg_gfx_index.bitfields.se_index); +pr_debug ("\t\t sh_ind is : %u\n" , reg_gfx_index.bitfields.sh_index); +pr_debug ("\t\t sbw is : %u\n" , + reg_gfx_index.bitfields.sh_broadcast_writes); + +pr_debug ("\t\t %30s\n" ,"* * * * * * * * * * * * * * * * * *" ); + +return dbgdev->dev->kfd2kgd->wave_control_execute (dbgdev->dev->kgd, + reg_gfx_index.u32All, + reg_sq_cmd.u32All); +} +void kfd_dbgdev_init (struct kfd_dbgdev *pdbgdev,struct kfd_dev *pdev,enum DBGDEV_TYPE type) {
@@ -131,11 +534,13 @@ void kfd_dbgdev_init(struct kfd_dbgdev *pdbgdev, struct kfd_dev *pdev,case DBGDEV_TYPE_NODIQ : pdbgdev->dbgdev_register = dbgdev_register_nodiq; pdbgdev->dbgdev_unregister = dbgdev_unregister_nodiq; + pdbgdev->dbgdev_wave_control = dbgdev_wave_control_nodiq;break ;case DBGDEV_TYPE_DIQ :default : pdbgdev->dbgdev_register = dbgdev_register_diq; pdbgdev->dbgdev_unregister = dbgdev_unregister_diq; + pdbgdev->dbgdev_wave_control = dbgdev_wave_control_diq;break ; }
drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c +16 -0
@@ -133,3 +133,19 @@ long kfd_dbgmgr_unregister(struct kfd_dbgmgr *pmgr, struct kfd_process *p)return 0 ; } + +long kfd_dbgmgr_wave_control (struct kfd_dbgmgr *pmgr, +struct dbg_wave_control_info *wac_info) +{ +BUG_ON (!pmgr || !pmgr->dbgdev || !wac_info); + +/* Is the requests coming from the already registered process? */ +if (pmgr->pasid != wac_info->process->pasid) { +pr_debug ("H/W debugger support was not registered for requester pasid %d\n" , + wac_info->process->pasid); +return -EINVAL ; + } + +return (long ) pmgr->dbgdev->dbgdev_wave_control (pmgr->dbgdev, wac_info); +} +
drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.h +4 -1
@@ -268,6 +268,8 @@ struct kfd_dbgdev {/* virtualized function pointers to device dbg */ int (*dbgdev_register)(struct kfd_dbgdev *dbgdev);int (*dbgdev_unregister)(struct kfd_dbgdev *dbgdev); +int (*dbgdev_wave_control)(struct kfd_dbgdev *dbgdev, +struct dbg_wave_control_info *wac_info); };
@@ -283,5 +285,6 @@ void kfd_dbgmgr_destroy(struct kfd_dbgmgr *pmgr);bool kfd_dbgmgr_create (struct kfd_dbgmgr **ppmgr,struct kfd_dev *pdev);long kfd_dbgmgr_register (struct kfd_dbgmgr *pmgr,struct kfd_process *p);long kfd_dbgmgr_unregister (struct kfd_dbgmgr *pmgr,struct kfd_process *p); - +long kfd_dbgmgr_wave_control (struct kfd_dbgmgr *pmgr, +struct dbg_wave_control_info *wac_info);#endif /* KFD_DBGMGR_H_ */
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +1 -1
@@ -915,7 +915,7 @@ out:return retval; } -static int amdkfd_fence_wait_timeout (unsigned int *fence_addr, +int amdkfd_fence_wait_timeout (unsigned int *fence_addr,unsigned int fence_value,unsigned long timeout) {
drivers/gpu/drm/amd/amdkfd/kfd_priv.h +4 -0
@@ -655,6 +655,10 @@ int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid,struct kernel_queue *pqm_get_kernel_queue (struct process_queue_manager *pqm,unsigned int qid); +int amdkfd_fence_wait_timeout (unsigned int *fence_addr, +unsigned int fence_value, +unsigned long timeout); +/* Packet Manager */ #define KFD_HIQ_TIMEOUT (500)
Signature · 6 lines
2.1.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 6/11 drm/amdkfd: Add address watch operation to debugger
In reply to Oded GabbayFrom: Yair Shachar <[email protected]>
The address watch operation gives the ability to specify watch points which will generate a shader breakpoint, based on a specified single address or range of addresses.
There is support for read/write/any access modes.
--- drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c | 274 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c | 17 ++ drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.h | 4 + 3 files changed, 295 insertions(+)
drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c +274 -0
@@ -236,6 +236,278 @@ static int dbgdev_unregister_diq(struct kfd_dbgdev *dbgdev)return status; } +static void dbgdev_address_watch_set_registers ( +const struct dbg_address_watch_info *adw_info, +union TCP_WATCH_ADDR_H_BITS *addrHi, +union TCP_WATCH_ADDR_L_BITS *addrLo, +union TCP_WATCH_CNTL_BITS *cntl, +unsigned int index,unsigned int vmid) +{ +union ULARGE_INTEGER addr; + +BUG_ON (!adw_info || !addrHi || !addrLo || !cntl); + + addr.quad_part =0 ; + addrHi->u32All =0 ; + addrLo->u32All =0 ; + cntl->u32All =0 ; + +if (adw_info->watch_mask !=NULL ) + cntl->bitfields.mask = + (uint32_t ) (adw_info->watch_mask[index] & +ADDRESS_WATCH_REG_CNTL_DEFAULT_MASK ); +else + cntl->bitfields.mask =ADDRESS_WATCH_REG_CNTL_DEFAULT_MASK ; + + addr.quad_part = (unsigned long long ) adw_info->watch_address[index]; + + addrHi->bitfields.addr = addr.u.high_part & +ADDRESS_WATCH_REG_ADDHIGH_MASK ; + addrLo->bitfields.addr = + (addr.u.low_part >>ADDRESS_WATCH_REG_ADDLOW_SHIFT ); + + cntl->bitfields.mode = adw_info->watch_mode[index]; + cntl->bitfields.vmid = (uint32_t ) vmid; +/* for now assume it is an ATC address */ + cntl->u32All |=ADDRESS_WATCH_REG_CNTL_ATC_BIT ; + +pr_debug ("\t\t%20s %08x\n" ,"set reg mask :" , cntl->bitfields.mask); +pr_debug ("\t\t%20s %08x\n" ,"set reg add high :" , + addrHi->bitfields.addr); +pr_debug ("\t\t%20s %08x\n" ,"set reg add low :" , + addrLo->bitfields.addr); +} + +static int dbgdev_address_watch_nodiq (struct kfd_dbgdev *dbgdev, +struct dbg_address_watch_info *adw_info) +{ +union TCP_WATCH_ADDR_H_BITS addrHi; +union TCP_WATCH_ADDR_L_BITS addrLo; +union TCP_WATCH_CNTL_BITS cntl; +struct kfd_process_device *pdd; +unsigned int i; + +BUG_ON (!dbgdev || !dbgdev->dev || !adw_info); + +/* taking the vmid for that process on the safe way using pdd */ + pdd =kfd_get_process_device_data (dbgdev->dev, + adw_info->process); +if (!pdd) { +pr_err ("amdkfd: Failed to get pdd for wave control no DIQ\n" ); +return -EFAULT ; + } + + addrHi.u32All =0 ; + addrLo.u32All =0 ; + cntl.u32All =0 ; + +if ((adw_info->num_watch_points >MAX_WATCH_ADDRESSES ) || + (adw_info->num_watch_points ==0 )) { +pr_err ("amdkfd: num_watch_points is invalid\n" ); +return -EINVAL ; + } + +if ((adw_info->watch_mode ==NULL ) || + (adw_info->watch_address ==NULL )) { +pr_err ("amdkfd: adw_info fields are not valid\n" ); +return -EINVAL ; + } + +for (i =0 ; i < adw_info->num_watch_points ; i++) { +dbgdev_address_watch_set_registers (adw_info, &addrHi, &addrLo, + &cntl, i, pdd->qpd.vmid); + +pr_debug ("\t\t%30s\n" ,"* * * * * * * * * * * * * * * * * *" ); +pr_debug ("\t\t%20s %08x\n" ,"register index :" , i); +pr_debug ("\t\t%20s %08x\n" ,"vmid is :" , pdd->qpd.vmid); +pr_debug ("\t\t%20s %08x\n" ,"Address Low is :" , + addrLo.bitfields.addr); +pr_debug ("\t\t%20s %08x\n" ,"Address high is :" , + addrHi.bitfields.addr); +pr_debug ("\t\t%20s %08x\n" ,"Address high is :" , + addrHi.bitfields.addr); +pr_debug ("\t\t%20s %08x\n" ,"Control Mask is :" , + cntl.bitfields.mask); +pr_debug ("\t\t%20s %08x\n" ,"Control Mode is :" , + cntl.bitfields.mode); +pr_debug ("\t\t%20s %08x\n" ,"Control Vmid is :" , + cntl.bitfields.vmid); +pr_debug ("\t\t%20s %08x\n" ,"Control atc is :" , + cntl.bitfields.atc); +pr_debug ("\t\t%30s\n" ,"* * * * * * * * * * * * * * * * * *" ); + + pdd->dev->kfd2kgd->address_watch_execute ( + dbgdev->dev->kgd, + i, + cntl.u32All, + addrHi.u32All, + addrLo.u32All); + } + +return 0 ; +} + +static int dbgdev_address_watch_diq (struct kfd_dbgdev *dbgdev, +struct dbg_address_watch_info *adw_info) +{ +struct pm4__set_config_reg *packets_vec; +union TCP_WATCH_ADDR_H_BITS addrHi; +union TCP_WATCH_ADDR_L_BITS addrLo; +union TCP_WATCH_CNTL_BITS cntl; +struct kfd_mem_obj *mem_obj; +unsigned int aw_reg_add_dword; +uint32_t *packet_buff_uint; +unsigned int i; +int status; +size_t ib_size =sizeof (struct pm4__set_config_reg ) *4 ; +/* we do not control the vmid in DIQ mode, just a place holder */ +unsigned int vmid =0 ; + +BUG_ON (!dbgdev || !dbgdev->dev || !adw_info); + + addrHi.u32All =0 ; + addrLo.u32All =0 ; + cntl.u32All =0 ; + +if ((adw_info->num_watch_points >MAX_WATCH_ADDRESSES ) || + (adw_info->num_watch_points ==0 )) { +pr_err ("amdkfd: num_watch_points is invalid\n" ); +return -EINVAL ; + } + +if ((NULL == adw_info->watch_mode) || + (NULL == adw_info->watch_address)) { +pr_err ("amdkfd: adw_info fields are not valid\n" ); +return -EINVAL ; + } + + status =kfd_gtt_sa_allocate (dbgdev->dev, ib_size, &mem_obj); + +if (status !=0 ) { +pr_err ("amdkfd: Failed to allocate GART memory\n" ); +return status; + } + + packet_buff_uint = mem_obj->cpu_ptr; + +memset (packet_buff_uint,0 , ib_size); + + packets_vec = (struct pm4__set_config_reg *) (packet_buff_uint); + + packets_vec[0 ].header.count =1 ; + packets_vec[0 ].header.opcode =IT_SET_CONFIG_REG ; + packets_vec[0 ].header.type =PM4_TYPE_3 ; + packets_vec[0 ].bitfields2.vmid_shift =ADDRESS_WATCH_CNTL_OFFSET ; + packets_vec[0 ].bitfields2.insert_vmid =1 ; + packets_vec[1 ].ordinal1 = packets_vec[0 ].ordinal1; + packets_vec[1 ].bitfields2.insert_vmid =0 ; + packets_vec[2 ].ordinal1 = packets_vec[0 ].ordinal1; + packets_vec[2 ].bitfields2.insert_vmid =0 ; + packets_vec[3 ].ordinal1 = packets_vec[0 ].ordinal1; + packets_vec[3 ].bitfields2.vmid_shift =ADDRESS_WATCH_CNTL_OFFSET ; + packets_vec[3 ].bitfields2.insert_vmid =1 ; + +for (i =0 ; i < adw_info->num_watch_points; i++) { +dbgdev_address_watch_set_registers (adw_info, + &addrHi, + &addrLo, + &cntl, + i, + vmid); + +pr_debug ("\t\t%30s\n" ,"* * * * * * * * * * * * * * * * * *" ); +pr_debug ("\t\t%20s %08x\n" ,"register index :" , i); +pr_debug ("\t\t%20s %08x\n" ,"vmid is :" , vmid); +pr_debug ("\t\t%20s %p\n" ,"Add ptr is :" , + adw_info->watch_address); +pr_debug ("\t\t%20s %08llx\n" ,"Add is :" , + adw_info->watch_address[i]); +pr_debug ("\t\t%20s %08x\n" ,"Address Low is :" , + addrLo.bitfields.addr); +pr_debug ("\t\t%20s %08x\n" ,"Address high is :" , + addrHi.bitfields.addr); +pr_debug ("\t\t%20s %08x\n" ,"Control Mask is :" , + cntl.bitfields.mask); +pr_debug ("\t\t%20s %08x\n" ,"Control Mode is :" , + cntl.bitfields.mode); +pr_debug ("\t\t%20s %08x\n" ,"Control Vmid is :" , + cntl.bitfields.vmid); +pr_debug ("\t\t%20s %08x\n" ,"Control atc is :" , + cntl.bitfields.atc); +pr_debug ("\t\t%30s\n" ,"* * * * * * * * * * * * * * * * * *" ); + + aw_reg_add_dword = + dbgdev->dev->kfd2kgd->address_watch_get_offset ( + dbgdev->dev->kgd, + i, +ADDRESS_WATCH_REG_CNTL ); + + aw_reg_add_dword /=sizeof (uint32_t ); + + packets_vec[0 ].bitfields2.reg_offset = + aw_reg_add_dword -CONFIG_REG_BASE ; + + packets_vec[0 ].reg_data[0 ] = cntl.u32All; + + aw_reg_add_dword = + dbgdev->dev->kfd2kgd->address_watch_get_offset ( + dbgdev->dev->kgd, + i, +ADDRESS_WATCH_REG_ADDR_HI ); + + aw_reg_add_dword /=sizeof (uint32_t ); + + packets_vec[1 ].bitfields2.reg_offset = + aw_reg_add_dword -CONFIG_REG_BASE ; + packets_vec[1 ].reg_data[0 ] = addrHi.u32All; + + aw_reg_add_dword = + dbgdev->dev->kfd2kgd->address_watch_get_offset ( + dbgdev->dev->kgd, + i, +ADDRESS_WATCH_REG_ADDR_LO ); + + aw_reg_add_dword /=sizeof (uint32_t ); + + packets_vec[2 ].bitfields2.reg_offset = + aw_reg_add_dword -CONFIG_REG_BASE ; + packets_vec[2 ].reg_data[0 ] = addrLo.u32All; + +/* enable watch flag if address is not zero*/ +if (adw_info->watch_address[i] >0 ) + cntl.bitfields.valid =1 ; +else + cntl.bitfields.valid =0 ; + + aw_reg_add_dword = + dbgdev->dev->kfd2kgd->address_watch_get_offset ( + dbgdev->dev->kgd, + i, +ADDRESS_WATCH_REG_CNTL ); + + aw_reg_add_dword /=sizeof (uint32_t ); + + packets_vec[3 ].bitfields2.reg_offset = + aw_reg_add_dword -CONFIG_REG_BASE ; + packets_vec[3 ].reg_data[0 ] = cntl.u32All; + + status =dbgdev_diq_submit_ib ( + dbgdev, + adw_info->process->pasid, + mem_obj->gpu_addr, + packet_buff_uint, + ib_size); + +if (status !=0 ) { +pr_err ("amdkfd: Failed to submit IB to DIQ\n" ); +break ; + } + } + +kfd_gtt_sa_free (dbgdev->dev, mem_obj); +return status; +} + static int dbgdev_wave_control_set_registers( struct dbg_wave_control_info *wac_info, union SQ_CMD_BITS *in_reg_sq_cmd,
@@ -535,12 +807,14 @@ void kfd_dbgdev_init(struct kfd_dbgdev *pdbgdev, struct kfd_dev *pdev, pdbgdev->dbgdev_register = dbgdev_register_nodiq; pdbgdev->dbgdev_unregister = dbgdev_unregister_nodiq; pdbgdev->dbgdev_wave_control = dbgdev_wave_control_nodiq; + pdbgdev->dbgdev_address_watch = dbgdev_address_watch_nodiq;break ;case DBGDEV_TYPE_DIQ :default : pdbgdev->dbgdev_register = dbgdev_register_diq; pdbgdev->dbgdev_unregister = dbgdev_unregister_diq; pdbgdev->dbgdev_wave_control = dbgdev_wave_control_diq; + pdbgdev->dbgdev_address_watch = dbgdev_address_watch_diq;break ; }
drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c +17 -0
@@ -149,3 +149,20 @@ long kfd_dbgmgr_wave_control(struct kfd_dbgmgr *pmgr,return (long ) pmgr->dbgdev->dbgdev_wave_control (pmgr->dbgdev, wac_info); } +long kfd_dbgmgr_address_watch (struct kfd_dbgmgr *pmgr, +struct dbg_address_watch_info *adw_info) +{ +BUG_ON (!pmgr || !pmgr->dbgdev || !adw_info); + + +/* Is the requests coming from the already registered process? */ +if (pmgr->pasid != adw_info->process->pasid) { +pr_debug ("H/W debugger support was not registered for requester pasid %d\n" , + adw_info->process->pasid); +return -EINVAL ; + } + +return (long ) pmgr->dbgdev->dbgdev_address_watch (pmgr->dbgdev, + adw_info); +} +
drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.h +4 -0
@@ -268,6 +268,8 @@ struct kfd_dbgdev {/* virtualized function pointers to device dbg */ int (*dbgdev_register)(struct kfd_dbgdev *dbgdev);int (*dbgdev_unregister)(struct kfd_dbgdev *dbgdev); +int (*dbgdev_address_watch)(struct kfd_dbgdev *dbgdev, +struct dbg_address_watch_info *adw_info);int (*dbgdev_wave_control)(struct kfd_dbgdev *dbgdev,struct dbg_wave_control_info *wac_info);
@@ -287,4 +289,6 @@ long kfd_dbgmgr_register(struct kfd_dbgmgr *pmgr, struct kfd_process *p);long kfd_dbgmgr_unregister (struct kfd_dbgmgr *pmgr,struct kfd_process *p);long kfd_dbgmgr_wave_control (struct kfd_dbgmgr *pmgr,struct dbg_wave_control_info *wac_info); +long kfd_dbgmgr_address_watch (struct kfd_dbgmgr *pmgr, +struct dbg_address_watch_info *adw_info);#endif /* KFD_DBGMGR_H_ */
Signature · 6 lines
2.1.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 7/11 drm/amdkfd: Implement (un)register debugger IOCTLs
In reply to Oded GabbayFrom: Yair Shachar <[email protected]>
--- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 72 +++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +70 -2
@@ -35,6 +35,7 @@#include <asm/processor.h> #include "kfd_priv.h" #include "kfd_device_queue_manager.h" +#include "kfd_dbgmgr.h" static long kfd_ioctl (struct file *,unsigned int ,unsigned long );static int kfd_open (struct inode *,struct file *);
@@ -435,7 +436,53 @@ out:static int kfd_ioctl_dbg_register (struct file *filep,struct kfd_process *p,void *data) { -long status = -EFAULT ; +struct kfd_ioctl_dbg_register_args *args = data; +struct kfd_dev *dev; +struct kfd_dbgmgr *dbgmgr_ptr; +struct kfd_process_device *pdd; +bool create_ok; +long status =0 ; + + dev =kfd_device_by_id (args->gpu_id); +if (dev ==NULL ) +return -EINVAL ; + +if (dev->device_info->asic_family ==CHIP_CARRIZO ) { +pr_debug ("kfd_ioctl_dbg_register not supported on CZ\n" ); +return -EINVAL ; + } + +mutex_lock (get_dbgmgr_mutex ()); +mutex_lock (&p->mutex); + +/* +* make sure that we have pdd, if this the first queue created for +* this process +*/ + pdd =kfd_bind_process_to_device (dev, p); +if (IS_ERR (pdd) <0 ) { +mutex_unlock (&p->mutex); +mutex_unlock (get_dbgmgr_mutex ()); +return PTR_ERR (pdd); + } + +if (dev->dbgmgr ==NULL ) { +/* In case of a legal call, we have no dbgmgr yet */ + create_ok =kfd_dbgmgr_create (&dbgmgr_ptr, dev); +if (create_ok) { + status =kfd_dbgmgr_register (dbgmgr_ptr, p); +if (status !=0 ) +kfd_dbgmgr_destroy (dbgmgr_ptr); +else + dev->dbgmgr = dbgmgr_ptr; + } + }else { +pr_debug ("debugger already registered\n" ); + status = -EINVAL ; + } + +mutex_unlock (&p->mutex); +mutex_unlock (get_dbgmgr_mutex ());return status; }
@@ -443,7 +490,28 @@ static int kfd_ioctl_dbg_register(struct file *filep,static int kfd_ioctl_dbg_unrgesiter (struct file *filep,struct kfd_process *p,void *data) { -long status = -EFAULT ; +struct kfd_ioctl_dbg_unregister_args *args = data; +struct kfd_dev *dev; +long status; + + dev =kfd_device_by_id (args->gpu_id); +if (dev ==NULL ) +return -EINVAL ; + +if (dev->device_info->asic_family ==CHIP_CARRIZO ) { +pr_debug ("kfd_ioctl_dbg_unrgesiter not supported on CZ\n" ); +return -EINVAL ; + } + +mutex_lock (get_dbgmgr_mutex ()); + + status =kfd_dbgmgr_unregister (dev->dbgmgr, p); +if (status ==0 ) { +kfd_dbgmgr_destroy (dev->dbgmgr); + dev->dbgmgr =NULL ; + } + +mutex_unlock (get_dbgmgr_mutex ());return status; }
Signature · 6 lines
2.1.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 8/11 drm/amdkfd: Implement wave control debugger IOCTL
In reply to Oded GabbayFrom: Yair Shachar <[email protected]>
--- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 88 +++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +87 -1
@@ -537,7 +537,93 @@ static int kfd_ioctl_dbg_address_watch(struct file *filep,static int kfd_ioctl_dbg_wave_control (struct file *filep,struct kfd_process *p,void *data) { -long status = -EFAULT ; +struct kfd_ioctl_dbg_wave_control_args *args = data; +struct kfd_dev *dev; +struct dbg_wave_control_info wac_info; +unsigned char *args_buff; +uint32_t computed_buff_size; +long status; +unsigned int args_idx =0 ; + +memset ((void *) &wac_info,0 ,sizeof (struct dbg_wave_control_info )); + +/* we use compact form, independent of the packing attribute value */ + computed_buff_size =sizeof (*args) + +sizeof (wac_info.mode) + +sizeof (wac_info.operand) + +sizeof (wac_info.dbgWave_msg.DbgWaveMsg) + +sizeof (wac_info.dbgWave_msg.MemoryVA) + +sizeof (wac_info.trapId); + + dev =kfd_device_by_id (args->gpu_id); +if (dev ==NULL ) +return -EINVAL ; + +if (dev->device_info->asic_family ==CHIP_CARRIZO ) { +pr_debug ("kfd_ioctl_dbg_wave_control not supported on CZ\n" ); +return -EINVAL ; + } + +/* input size must match the computed "compact" size */ +if (args->buf_size_in_bytes != computed_buff_size) { +pr_debug ("size mismatch, computed : actual %u : %u\n" , + args->buf_size_in_bytes, computed_buff_size); +return -EINVAL ; + } + +/* this is the actual buffer to work with */ + + args_buff =kzalloc (args->buf_size_in_bytes -sizeof (*args), +GFP_KERNEL ); + +if (args_buff ==NULL ) +return -ENOMEM ; + +if (args->content_ptr ==NULL ) { +kfree (args_buff); +return -EINVAL ; + } + +/* Now copy the entire buffer from user */ + status =copy_from_user (args_buff, + (void __user *) args->content_ptr, + args->buf_size_in_bytes -sizeof (*args)); +if (status !=0 ) { +pr_debug ("Failed to copy wave control user data\n" ); +kfree (args_buff); +return -EINVAL ; + } + +/* move ptr to the start of the "pay-load" area */ + wac_info.process = p; + + wac_info.operand = *((enum HSA_DBG_WAVEOP *)(&args_buff[args_idx])); + args_idx +=sizeof (wac_info.operand); + + wac_info.mode = *((enum HSA_DBG_WAVEMODE *)(&args_buff[args_idx])); + args_idx +=sizeof (wac_info.mode); + + wac_info.trapId = *((uint32_t *)(&args_buff[args_idx])); + args_idx +=sizeof (wac_info.trapId); + + wac_info.dbgWave_msg.DbgWaveMsg.WaveMsgInfoGen2.Value = + *((uint32_t *)(&args_buff[args_idx])); + wac_info.dbgWave_msg.MemoryVA =NULL ; + +mutex_lock (get_dbgmgr_mutex ()); + +pr_debug ("Calling dbg manager process %p, operand %u, mode %u, trapId %u, message %u\n" , + wac_info.process, wac_info.operand, + wac_info.mode, wac_info.trapId, + wac_info.dbgWave_msg.DbgWaveMsg.WaveMsgInfoGen2.Value); + + status =kfd_dbgmgr_wave_control (dev->dbgmgr, &wac_info); + +pr_debug ("Returned status of dbg manager is %ld\n" , status); + +mutex_unlock (get_dbgmgr_mutex ()); + +kfree (args_buff);return status; }
Signature · 6 lines
2.1.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 9/11 drm/amdkfd: Implement address watch debugger IOCTL
In reply to Oded GabbayFrom: Yair Shachar <[email protected]>
--- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 104 ++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +103 -1
@@ -528,7 +528,109 @@ static int kfd_ioctl_dbg_unrgesiter(struct file *filep,static int kfd_ioctl_dbg_address_watch (struct file *filep,struct kfd_process *p,void *data) { -long status = -EFAULT ; +struct kfd_ioctl_dbg_address_watch_args *args = data; +struct kfd_dev *dev; +struct dbg_address_watch_info aw_info; +unsigned char *args_buff; +unsigned int args_idx =0 ; +uint64_t watch_mask_value =0 ; +long status; + +memset ((void *) &aw_info,0 ,sizeof (struct dbg_address_watch_info )); + + dev =kfd_device_by_id (args->gpu_id); +if (dev ==NULL ) +return -EINVAL ; + +if (dev->device_info->asic_family ==CHIP_CARRIZO ) { +pr_debug ("kfd_ioctl_dbg_wave_control not supported on CZ\n" ); +return -EINVAL ; + } + +if (args->buf_size_in_bytes >MAX_ALLOWED_AW_BUFF_SIZE ) +return -EINVAL ; + +if (args->buf_size_in_bytes <=sizeof (*args)) +return -EINVAL ; + +/* this is the actual buffer to work with */ + + args_buff =kzalloc (args->buf_size_in_bytes - +sizeof (*args),GFP_KERNEL ); +if (args_buff ==NULL ) +return -ENOMEM ; + +if (args->content_ptr ==NULL ) { +kfree (args_buff); +return -EINVAL ; + } + + status =copy_from_user (args_buff, + (void __user *) args->content_ptr, + args->buf_size_in_bytes -sizeof (*args)); + +if (status !=0 ) { +pr_debug ("Failed to copy address watch user data\n" ); +kfree (args_buff); +return -EINVAL ; + } + + aw_info.process = p; + + aw_info.num_watch_points = *((uint32_t *)(&args_buff[args_idx])); + args_idx +=sizeof (aw_info.num_watch_points); + + aw_info.watch_mode = (enum HSA_DBG_WATCH_MODE *) &args_buff[args_idx]; + args_idx +=sizeof (enum HSA_DBG_WATCH_MODE ) * aw_info.num_watch_points; + +/* +* set watch address base pointer to point on the array base +* within args_buff +*/ + aw_info.watch_address = (uint64_t *) &args_buff[args_idx]; + +/* skip over the addresses buffer */ + args_idx +=sizeof (aw_info.watch_address) * aw_info.num_watch_points; + +if (args_idx >= args->buf_size_in_bytes) { +kfree (args_buff); +return -EINVAL ; + } + + watch_mask_value = (uint64_t ) args_buff[args_idx]; + +if (watch_mask_value >0 ) { +/* +* There is an array of masks. +* set watch mask base pointer to point on the array base +* within args_buff +*/ + aw_info.watch_mask = (uint64_t *) &args_buff[args_idx]; + +/* skip over the masks buffer */ + args_idx +=sizeof (aw_info.watch_mask) * + aw_info.num_watch_points; + }else { +/* just the NULL mask, set to NULL and skip over it */ + aw_info.watch_mask =NULL ; + args_idx +=sizeof (aw_info.watch_mask); + } + +if (args_idx > args->buf_size_in_bytes) { +kfree (args_buff); +return -EINVAL ; + } + +/* Currently HSA Event is not supported for DBG */ + aw_info.watch_event =NULL ; + +mutex_lock (get_dbgmgr_mutex ()); + + status =kfd_dbgmgr_address_watch (dev->dbgmgr, &aw_info); + +mutex_unlock (get_dbgmgr_mutex ()); + +kfree (args_buff);return status; }
Signature · 6 lines
2.1.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 10/11 drm/radeon: Add ATC VMID<-->PASID functions to kfd->kgd
In reply to Oded GabbayFrom: Alexey Skidanov <[email protected]>
This patch adds three new interfaces to kfd2kgd interface file of radeon.
The interfaces are:
- Check if a specific VMID has a valid PASID mapping
- Retrieve the PASID which is mapped to a specific VMID
- Issue a VMID invalidation request to the ATC
--- drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 8 ++++++ drivers/gpu/drm/radeon/cikd.h | 9 ++++-- drivers/gpu/drm/radeon/radeon_kfd.c | 38 +++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/include/kgd_kfd_interface.h +8 -0
@@ -175,6 +175,14 @@ struct kfd2kgd_calls {uint32_t (*address_watch_get_offset)(struct kgd_dev *kgd,unsigned int watch_point_id,unsigned int reg_offset); +bool (*get_atc_vmid_pasid_mapping_valid)( +struct kgd_dev *kgd, +uint8_t vmid); +uint16_t (*get_atc_vmid_pasid_mapping_pasid)( +struct kgd_dev *kgd, +uint8_t vmid); +void (*write_vmid_invalidate_request)(struct kgd_dev *kgd, +uint8_t vmid);uint16_t (*get_fw_version)(struct kgd_dev *kgd,enum kgd_engine_type type);
drivers/gpu/drm/radeon/cikd.h +6 -3
@@ -2148,9 +2148,12 @@#define VCE_CMD_IB_AUTO 0x00000005#define VCE_CMD_SEMAPHORE 0x00000006 -#define ATC_VMID0_PASID_MAPPING 0x339Cu -#define ATC_VMID_PASID_MAPPING_UPDATE_STATUS 0x3398u -#define ATC_VMID_PASID_MAPPING_VALID (1U << 31) +#define ATC_VMID_PASID_MAPPING_UPDATE_STATUS 0x3398u +#define ATC_VMID0_PASID_MAPPING 0x339Cu +#define ATC_VMID_PASID_MAPPING_PASID_MASK (0xFFFF) +#define ATC_VMID_PASID_MAPPING_PASID_SHIFT 0 +#define ATC_VMID_PASID_MAPPING_VALID_MASK (0x1 << 31) +#define ATC_VMID_PASID_MAPPING_VALID_SHIFT 31#define ATC_VM_APERTURE0_CNTL 0x3310u#define ATS_ACCESS_MODE_NEVER 0
drivers/gpu/drm/radeon/radeon_kfd.c +36 -2
@@ -99,6 +99,11 @@ static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd,unsigned int watch_point_id, unsigned int reg_offset); +static bool get_atc_vmid_pasid_mapping_valid (struct kgd_dev *kgd,uint8_t vmid); +static uint16_t get_atc_vmid_pasid_mapping_pasid (struct kgd_dev *kgd, +uint8_t vmid); +static void write_vmid_invalidate_request (struct kgd_dev *kgd,uint8_t vmid); +static const struct kfd2kgd_calls kfd2kgd = { .init_gtt_mem_allocation = alloc_gtt_mem, .free_gtt_mem = free_gtt_mem,
@@ -119,6 +124,9 @@ static const struct kfd2kgd_calls kfd2kgd = { .address_watch_execute = kgd_address_watch_execute, .wave_control_execute = kgd_wave_control_execute, .address_watch_get_offset = kgd_address_watch_get_offset, + .get_atc_vmid_pasid_mapping_pasid = get_atc_vmid_pasid_mapping_pasid, + .get_atc_vmid_pasid_mapping_valid = get_atc_vmid_pasid_mapping_valid, + .write_vmid_invalidate_request = write_vmid_invalidate_request, .get_fw_version = get_fw_version };
@@ -395,8 +403,8 @@ static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,* the SW cleared it. * So the protocol is to always wait & clear. */ -uint32_t pasid_mapping = (pasid ==0 ) ?0 : - (uint32_t )pasid |ATC_VMID_PASID_MAPPING_VALID ; +uint32_t pasid_mapping = (pasid ==0 ) ?0 : (uint32_t )pasid | +ATC_VMID_PASID_MAPPING_VALID_MASK ;write_register (kgd,ATC_VMID0_PASID_MAPPING + vmid*sizeof (uint32_t ), pasid_mapping);
@@ -778,6 +786,32 @@ static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd,return watchRegs[watch_point_id *ADDRESS_WATCH_REG_MAX + reg_offset]; } +static bool get_atc_vmid_pasid_mapping_valid (struct kgd_dev *kgd,uint8_t vmid) +{ +uint32_t reg; +struct radeon_device *rdev = (struct radeon_device *) kgd; + + reg =RREG32 (ATC_VMID0_PASID_MAPPING + vmid*4 ); +return reg &ATC_VMID_PASID_MAPPING_VALID_MASK ; +} + +static uint16_t get_atc_vmid_pasid_mapping_pasid (struct kgd_dev *kgd, +uint8_t vmid) +{ +uint32_t reg; +struct radeon_device *rdev = (struct radeon_device *) kgd; + + reg =RREG32 (ATC_VMID0_PASID_MAPPING + vmid*4 ); +return reg &ATC_VMID_PASID_MAPPING_PASID_MASK ; +} + +static void write_vmid_invalidate_request (struct kgd_dev *kgd,uint8_t vmid) +{ +struct radeon_device *rdev = (struct radeon_device *) kgd; + +return WREG32 (VM_INVALIDATE_REQUEST ,1 << vmid); +} +static uint16_t get_fw_version (struct kgd_dev *kgd,enum kgd_engine_type type) {struct radeon_device *rdev = (struct radeon_device *) kgd;
Signature · 6 lines
2.1.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 11/11 drm/amdkfd: Enforce kill all waves on process termination
In reply to Oded GabbayFrom: Ben Goz <[email protected]>
This commit makes sure that on process termination, after we're destroying all the active queues, we're killing all the existing wave front of the current process.
By doing this we're making sure that if any of the CUs were blocked by infinite loop we're enforcing it to end the shader explicitly.
--- drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c | 65 ++++++++++++++++++++++ .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 8 ++- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 7 +++ drivers/gpu/drm/amd/amdkfd/kfd_process.c | 8 +++ 4 files changed, 87 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c +65 -0
@@ -792,6 +792,71 @@ static int dbgdev_wave_control_nodiq(struct kfd_dbgdev *dbgdev, reg_sq_cmd.u32All); } +int dbgdev_wave_reset_wavefronts (struct kfd_dev *dev,struct kfd_process *p) +{ +int status =0 ; +unsigned int vmid; +union SQ_CMD_BITS reg_sq_cmd; +union GRBM_GFX_INDEX_BITS reg_gfx_index; +struct kfd_process_device *pdd; +struct dbg_wave_control_info wac_info; +int temp; +int first_vmid_to_scan =8 ; +int last_vmid_to_scan =15 ; + + first_vmid_to_scan =ffs (dev->shared_resources.compute_vmid_bitmap) -1 ; + temp = dev->shared_resources.compute_vmid_bitmap >> first_vmid_to_scan; + last_vmid_to_scan = first_vmid_to_scan +ffz (temp); + + reg_sq_cmd.u32All =0 ; + status =0 ; + + wac_info.mode =HSA_DBG_WAVEMODE_BROADCAST_PROCESS ; + wac_info.operand =HSA_DBG_WAVEOP_KILL ; + +pr_debug ("Killing all process wavefronts\n" ); + +/* Scan all registers in the range ATC_VMID8_PASID_MAPPING .. +* ATC_VMID15_PASID_MAPPING +* to check which VMID the current process is mapped to. */ + +for (vmid = first_vmid_to_scan; vmid <= last_vmid_to_scan; vmid++) { +if (dev->kfd2kgd->get_atc_vmid_pasid_mapping_valid + (dev->kgd, vmid)) { +if (dev->kfd2kgd->get_atc_vmid_pasid_mapping_valid + (dev->kgd, vmid) == p->pasid) { +pr_debug ("Killing wave fronts of vmid %d and pasid %d\n" , + vmid, p->pasid); +break ; + } + } + } + +if (vmid > last_vmid_to_scan) { +pr_err ("amdkfd: didn't found vmid for pasid (%d)\n" , p->pasid); +return -EFAULT ; + } + +/* taking the VMID for that process on the safe way using PDD */ + pdd =kfd_get_process_device_data (dev, p); +if (!pdd) +return -EFAULT ; + + status =dbgdev_wave_control_set_registers (&wac_info, ®_sq_cmd, + ®_gfx_index); +if (status !=0 ) +return -EINVAL ; + +/* for non DIQ we need to patch the VMID: */ + reg_sq_cmd.bits.vm_id = vmid; + + dev->kfd2kgd->wave_control_execute (dev->kgd, + reg_gfx_index.u32All, + reg_sq_cmd.u32All); + +return 0 ; +} +void kfd_dbgdev_init (struct kfd_dbgdev *pdbgdev,struct kfd_dev *pdev,enum DBGDEV_TYPE type) {
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +7 -1
@@ -946,6 +946,7 @@ static int destroy_queues_cpsch(struct device_queue_manager *dqm, {int retval;enum kfd_preempt_type_filter preempt_type; +struct kfd_process *p;BUG_ON (!dqm);
@@ -977,8 +978,13 @@ static int destroy_queues_cpsch(struct device_queue_manager *dqm,pm_send_query_status (&dqm->packets, dqm->fence_gpu_addr,KFD_FENCE_COMPLETED );/* should be timed out */ -amdkfd_fence_wait_timeout (dqm->fence_addr,KFD_FENCE_COMPLETED , + retval =amdkfd_fence_wait_timeout (dqm->fence_addr,KFD_FENCE_COMPLETED ,QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS ); +if (retval !=0 ) { + p =kfd_get_process (current); + p->reset_wavefronts = true; + goto out; + }pm_release_ib (&dqm->packets); dqm->active_runlist = false;
drivers/gpu/drm/amd/amdkfd/kfd_priv.h +7 -0
@@ -518,6 +518,11 @@ struct kfd_process {event_pages */ u32 next_nonsignal_event_id;size_t signal_event_count; +/* +* This flag tells if we should reset all wavefronts on +* process termination +*/ +bool reset_wavefronts; };/**
@@ -725,4 +730,6 @@ int kfd_event_create(struct file *devkfd, struct kfd_process *p, uint64_t *event_page_offset, uint32_t *event_slot_index);int kfd_event_destroy (struct kfd_process *p,uint32_t event_id); +int dbgdev_wave_reset_wavefronts (struct kfd_dev *dev,struct kfd_process *p); +#endif
drivers/gpu/drm/amd/amdkfd/kfd_process.c +8 -0
@@ -31,6 +31,7 @@struct mm_struct ;#include "kfd_priv.h" +#include "kfd_dbgmgr.h" /* * Initial size for the array of queues.
@@ -301,6 +302,8 @@ static struct kfd_process *create_process(const struct task_struct *thread)if (kfd_init_apertures (process) !=0 ) goto err_init_apretures; + process->reset_wavefronts = false; +return process; err_init_apretures:
@@ -399,7 +402,12 @@ void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid)mutex_lock (&p->mutex); +if ((dev->dbgmgr) && (dev->dbgmgr->pasid == p->pasid)) +kfd_dbgmgr_destroy (dev->dbgmgr); +pqm_uninit (&p->pqm); +if (p->reset_wavefronts) +dbgdev_wave_reset_wavefronts (dev, p); pdd =kfd_get_process_device_data (dev, p);
Signature · 6 lines
2.1.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel